diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/Android.mk | 64 | ||||
-rw-r--r-- | services/accessibility/Android.mk | 10 | ||||
-rw-r--r-- | services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java (renamed from services/java/com/android/server/accessibility/AccessibilityInputFilter.java) | 0 | ||||
-rw-r--r-- | services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java (renamed from services/java/com/android/server/accessibility/AccessibilityManagerService.java) | 0 | ||||
-rw-r--r-- | services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java (renamed from services/java/com/android/server/accessibility/EventStreamTransformation.java) | 0 | ||||
-rw-r--r-- | services/accessibility/java/com/android/server/accessibility/GestureUtils.java (renamed from services/java/com/android/server/accessibility/GestureUtils.java) | 0 | ||||
-rw-r--r-- | services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java (renamed from services/java/com/android/server/accessibility/ScreenMagnifier.java) | 0 | ||||
-rw-r--r-- | services/accessibility/java/com/android/server/accessibility/TouchExplorer.java (renamed from services/java/com/android/server/accessibility/TouchExplorer.java) | 0 | ||||
-rw-r--r-- | services/appwidget/Android.mk | 10 | ||||
-rw-r--r-- | services/appwidget/java/com/android/server/appwidget/AppWidgetService.java | 384 | ||||
-rw-r--r-- | services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java (renamed from services/java/com/android/server/AppWidgetServiceImpl.java) | 2 | ||||
-rw-r--r-- | services/backup/Android.mk | 12 | ||||
-rw-r--r-- | services/backup/java/com/android/server/backup/BackupManagerService.java (renamed from services/java/com/android/server/BackupManagerService.java) | 30 | ||||
-rw-r--r-- | services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java (renamed from services/java/com/android/server/PackageManagerBackupAgent.java) | 2 | ||||
-rw-r--r-- | services/backup/java/com/android/server/backup/SystemBackupAgent.java (renamed from services/java/com/android/server/SystemBackupAgent.java) | 48 | ||||
-rw-r--r-- | services/common_time/Android.mk | 36 | ||||
-rw-r--r-- | services/common_time/clock_recovery.cpp | 423 | ||||
-rw-r--r-- | services/common_time/clock_recovery.h | 159 | ||||
-rw-r--r-- | services/common_time/common_clock.cpp | 150 | ||||
-rw-r--r-- | services/common_time/common_clock.h | 57 | ||||
-rw-r--r-- | services/common_time/common_clock_service.cpp | 157 | ||||
-rw-r--r-- | services/common_time/common_clock_service.h | 91 | ||||
-rw-r--r-- | services/common_time/common_time_config_service.cpp | 112 | ||||
-rw-r--r-- | services/common_time/common_time_config_service.h | 60 | ||||
-rw-r--r-- | services/common_time/common_time_server.cpp | 1506 | ||||
-rw-r--r-- | services/common_time/common_time_server.h | 324 | ||||
-rw-r--r-- | services/common_time/common_time_server_api.cpp | 438 | ||||
-rw-r--r-- | services/common_time/common_time_server_packets.cpp | 293 | ||||
-rw-r--r-- | services/common_time/common_time_server_packets.h | 189 | ||||
-rw-r--r-- | services/common_time/diag_thread.cpp | 323 | ||||
-rw-r--r-- | services/common_time/diag_thread.h | 76 | ||||
-rw-r--r-- | services/common_time/main.cpp | 43 | ||||
-rw-r--r-- | services/common_time/utils.cpp | 164 | ||||
-rw-r--r-- | services/common_time/utils.h | 83 | ||||
-rw-r--r-- | services/core/Android.mk | 14 | ||||
-rw-r--r-- | services/core/java/com/android/server/AlarmManagerService.java (renamed from services/java/com/android/server/AlarmManagerService.java) | 599 | ||||
-rw-r--r-- | services/core/java/com/android/server/AppOpsService.java (renamed from services/java/com/android/server/AppOpsService.java) | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/AssetAtlasService.java (renamed from services/java/com/android/server/AssetAtlasService.java) | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/AttributeCache.java (renamed from services/java/com/android/server/AttributeCache.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/BatteryService.java (renamed from services/java/com/android/server/BatteryService.java) | 33 | ||||
-rw-r--r-- | services/core/java/com/android/server/BluetoothManagerService.java (renamed from services/java/com/android/server/BluetoothManagerService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/BootReceiver.java (renamed from services/java/com/android/server/BootReceiver.java) | 32 | ||||
-rw-r--r-- | services/core/java/com/android/server/BrickReceiver.java (renamed from services/java/com/android/server/BrickReceiver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/CertBlacklister.java (renamed from services/java/com/android/server/CertBlacklister.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/CommonTimeManagementService.java (renamed from services/java/com/android/server/CommonTimeManagementService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/ConnectivityService.java (renamed from services/java/com/android/server/ConnectivityService.java) | 11 | ||||
-rw-r--r-- | services/core/java/com/android/server/ConsumerIrService.java (renamed from services/java/com/android/server/ConsumerIrService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/CountryDetectorService.java (renamed from services/java/com/android/server/CountryDetectorService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/DiskStatsService.java (renamed from services/java/com/android/server/DiskStatsService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/DisplayThread.java | 56 | ||||
-rw-r--r-- | services/core/java/com/android/server/DockObserver.java (renamed from services/java/com/android/server/DockObserver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/DropBoxManagerService.java (renamed from services/java/com/android/server/DropBoxManagerService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/EntropyMixer.java (renamed from services/java/com/android/server/EntropyMixer.java) | 37 | ||||
-rw-r--r-- | services/core/java/com/android/server/EventLogTags.logtags (renamed from services/java/com/android/server/EventLogTags.logtags) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/FgThread.java (renamed from services/java/com/android/server/FgThread.java) | 11 | ||||
-rw-r--r-- | services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java (renamed from services/java/com/android/server/INativeDaemonConnectorCallbacks.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/IdleMaintenanceService.java (renamed from services/java/com/android/server/IdleMaintenanceService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/InputMethodManagerService.java (renamed from services/java/com/android/server/InputMethodManagerService.java) | 5 | ||||
-rw-r--r-- | services/core/java/com/android/server/IntentResolver.java (renamed from services/java/com/android/server/IntentResolver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/IoThread.java (renamed from services/java/com/android/server/IoThread.java) | 11 | ||||
-rw-r--r-- | services/core/java/com/android/server/LocationManagerService.java (renamed from services/java/com/android/server/LocationManagerService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/LockSettingsService.java (renamed from services/java/com/android/server/LockSettingsService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/MasterClearReceiver.java (renamed from services/java/com/android/server/MasterClearReceiver.java) | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/MountService.java (renamed from services/java/com/android/server/MountService.java) | 5 | ||||
-rw-r--r-- | services/core/java/com/android/server/NativeDaemonConnector.java (renamed from services/java/com/android/server/NativeDaemonConnector.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/NativeDaemonConnectorException.java (renamed from services/java/com/android/server/NativeDaemonConnectorException.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/NativeDaemonEvent.java (renamed from services/java/com/android/server/NativeDaemonEvent.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/NetworkManagementService.java (renamed from services/java/com/android/server/NetworkManagementService.java) | 84 | ||||
-rw-r--r-- | services/core/java/com/android/server/NetworkTimeUpdateService.java (renamed from services/java/com/android/server/NetworkTimeUpdateService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/NsdService.java (renamed from services/java/com/android/server/NsdService.java) | 107 | ||||
-rw-r--r-- | services/core/java/com/android/server/RandomBlock.java (renamed from services/java/com/android/server/RandomBlock.java) | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/RecognitionManagerService.java (renamed from services/java/com/android/server/RecognitionManagerService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/SamplingProfilerService.java (renamed from services/java/com/android/server/SamplingProfilerService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/SerialService.java (renamed from services/java/com/android/server/SerialService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/ServiceThread.java | 48 | ||||
-rw-r--r-- | services/core/java/com/android/server/ServiceWatcher.java (renamed from services/java/com/android/server/ServiceWatcher.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/ShutdownActivity.java (renamed from services/java/com/android/server/ShutdownActivity.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/TelephonyRegistry.java (renamed from services/java/com/android/server/TelephonyRegistry.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/TextServicesManagerService.java (renamed from services/java/com/android/server/TextServicesManagerService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/TwilightCalculator.java (renamed from services/java/com/android/server/TwilightCalculator.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/UiModeManagerService.java (renamed from services/java/com/android/server/UiModeManagerService.java) | 304 | ||||
-rw-r--r-- | services/core/java/com/android/server/UiThread.java (renamed from services/java/com/android/server/UiThread.java) | 20 | ||||
-rw-r--r-- | services/core/java/com/android/server/UpdateLockService.java (renamed from services/java/com/android/server/UpdateLockService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/VibratorService.java (renamed from services/java/com/android/server/VibratorService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/Watchdog.java (renamed from services/java/com/android/server/Watchdog.java) | 33 | ||||
-rw-r--r-- | services/core/java/com/android/server/WiredAccessoryManager.java (renamed from services/java/com/android/server/WiredAccessoryManager.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java (renamed from services/java/com/android/server/accounts/AccountAuthenticatorCache.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/accounts/AccountManagerService.java (renamed from services/java/com/android/server/accounts/AccountManagerService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java (renamed from services/java/com/android/server/accounts/IAccountAuthenticatorCache.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActiveServices.java (renamed from services/java/com/android/server/am/ActiveServices.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java (renamed from services/java/com/android/server/am/ActivityManagerService.java) | 556 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityRecord.java (renamed from services/java/com/android/server/am/ActivityRecord.java) | 9 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityResult.java (renamed from services/java/com/android/server/am/ActivityResult.java) | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | services/core/java/com/android/server/am/ActivityStack.java (renamed from services/java/com/android/server/am/ActivityStack.java) | 220 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityStackSupervisor.java (renamed from services/java/com/android/server/am/ActivityStackSupervisor.java) | 1390 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/AppBindRecord.java (renamed from services/java/com/android/server/am/AppBindRecord.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/AppErrorDialog.java (renamed from services/java/com/android/server/am/AppErrorDialog.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/AppErrorResult.java (renamed from services/java/com/android/server/am/AppErrorResult.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/AppNotRespondingDialog.java (renamed from services/java/com/android/server/am/AppNotRespondingDialog.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java (renamed from services/java/com/android/server/am/AppWaitingForDebuggerDialog.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/BackupRecord.java (renamed from services/java/com/android/server/am/BackupRecord.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/BaseErrorDialog.java (renamed from services/java/com/android/server/am/BaseErrorDialog.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/BatteryStatsService.java (renamed from services/java/com/android/server/am/BatteryStatsService.java) | 22 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/BroadcastFilter.java (renamed from services/java/com/android/server/am/BroadcastFilter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/BroadcastQueue.java (renamed from services/java/com/android/server/am/BroadcastQueue.java) | 15 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/BroadcastRecord.java (renamed from services/java/com/android/server/am/BroadcastRecord.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/CompatModeDialog.java (renamed from services/java/com/android/server/am/CompatModeDialog.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/CompatModePackages.java (renamed from services/java/com/android/server/am/CompatModePackages.java) | 41 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ConnectionRecord.java (renamed from services/java/com/android/server/am/ConnectionRecord.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ContentProviderConnection.java (renamed from services/java/com/android/server/am/ContentProviderConnection.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ContentProviderRecord.java (renamed from services/java/com/android/server/am/ContentProviderRecord.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/CoreSettingsObserver.java (renamed from services/java/com/android/server/am/CoreSettingsObserver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/EventLogTags.logtags (renamed from services/java/com/android/server/am/EventLogTags.logtags) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/FactoryErrorDialog.java (renamed from services/java/com/android/server/am/FactoryErrorDialog.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/IntentBindRecord.java (renamed from services/java/com/android/server/am/IntentBindRecord.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/LaunchWarningWindow.java (renamed from services/java/com/android/server/am/LaunchWarningWindow.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/NativeCrashListener.java (renamed from services/java/com/android/server/am/NativeCrashListener.java) | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/PendingIntentRecord.java (renamed from services/java/com/android/server/am/PendingIntentRecord.java) | 10 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/PendingThumbnailsRecord.java (renamed from services/java/com/android/server/am/PendingThumbnailsRecord.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ProcessList.java (renamed from services/java/com/android/server/am/ProcessList.java) | 135 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ProcessMemInfo.java (renamed from services/java/com/android/server/am/ProcessMemInfo.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ProcessRecord.java (renamed from services/java/com/android/server/am/ProcessRecord.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ProcessStatsService.java (renamed from services/java/com/android/server/am/ProcessStatsService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ProviderMap.java (renamed from services/java/com/android/server/am/ProviderMap.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ReceiverList.java (renamed from services/java/com/android/server/am/ReceiverList.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ServiceRecord.java (renamed from services/java/com/android/server/am/ServiceRecord.java) | 9 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/StrictModeViolationDialog.java (renamed from services/java/com/android/server/am/StrictModeViolationDialog.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/TaskAccessInfo.java (renamed from services/java/com/android/server/am/TaskAccessInfo.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/TaskRecord.java (renamed from services/java/com/android/server/am/TaskRecord.java) | 3 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ThumbnailHolder.java (renamed from services/java/com/android/server/am/ThumbnailHolder.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/UriPermission.java (renamed from services/java/com/android/server/am/UriPermission.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/UriPermissionOwner.java (renamed from services/java/com/android/server/am/UriPermissionOwner.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/UsageStatsService.java (renamed from services/java/com/android/server/am/UsageStatsService.java) | 7 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/UserStartedState.java (renamed from services/java/com/android/server/am/UserStartedState.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/package.html (renamed from services/java/com/android/server/am/package.html) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/clipboard/ClipboardService.java (renamed from services/java/com/android/server/ClipboardService.java) | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/connectivity/DataConnectionStats.java (renamed from services/java/com/android/server/connectivity/DataConnectionStats.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/connectivity/Nat464Xlat.java (renamed from services/java/com/android/server/connectivity/Nat464Xlat.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/connectivity/PacManager.java (renamed from services/java/com/android/server/connectivity/PacManager.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/connectivity/Tethering.java (renamed from services/java/com/android/server/connectivity/Tethering.java) | 11 | ||||
-rw-r--r-- | services/core/java/com/android/server/connectivity/Vpn.java (renamed from services/java/com/android/server/connectivity/Vpn.java) | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/content/ContentService.java (renamed from services/java/com/android/server/content/ContentService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/content/SyncManager.java (renamed from services/java/com/android/server/content/SyncManager.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/content/SyncOperation.java (renamed from services/java/com/android/server/content/SyncOperation.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/content/SyncQueue.java (renamed from services/java/com/android/server/content/SyncQueue.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/content/SyncStorageEngine.java (renamed from services/java/com/android/server/content/SyncStorageEngine.java) | 8 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/DisplayAdapter.java (renamed from services/java/com/android/server/display/DisplayAdapter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/DisplayBlanker.java (renamed from services/java/com/android/server/power/DisplayBlanker.java) | 9 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/DisplayDevice.java (renamed from services/java/com/android/server/display/DisplayDevice.java) | 11 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/DisplayDeviceInfo.java (renamed from services/java/com/android/server/display/DisplayDeviceInfo.java) | 19 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/DisplayManagerService.java (renamed from services/java/com/android/server/display/DisplayManagerService.java) | 1027 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/DisplayPowerController.java (renamed from services/java/com/android/server/power/DisplayPowerController.java) | 188 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/DisplayPowerState.java (renamed from services/java/com/android/server/power/DisplayPowerState.java) | 98 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/ElectronBeam.java (renamed from services/java/com/android/server/power/ElectronBeam.java) | 38 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/LocalDisplayAdapter.java (renamed from services/java/com/android/server/display/LocalDisplayAdapter.java) | 37 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/LogicalDisplay.java (renamed from services/java/com/android/server/display/LogicalDisplay.java) | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/OverlayDisplayAdapter.java (renamed from services/java/com/android/server/display/OverlayDisplayAdapter.java) | 29 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/OverlayDisplayWindow.java (renamed from services/java/com/android/server/display/OverlayDisplayWindow.java) | 8 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/PersistentDataStore.java (renamed from services/java/com/android/server/display/PersistentDataStore.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/RampAnimator.java (renamed from services/java/com/android/server/power/RampAnimator.java) | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/VirtualDisplayAdapter.java (renamed from services/java/com/android/server/display/VirtualDisplayAdapter.java) | 26 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/WifiDisplayAdapter.java (renamed from services/java/com/android/server/display/WifiDisplayAdapter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/display/WifiDisplayController.java (renamed from services/java/com/android/server/display/WifiDisplayController.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/dreams/DreamController.java (renamed from services/java/com/android/server/dreams/DreamController.java) | 19 | ||||
-rw-r--r-- | services/core/java/com/android/server/dreams/DreamManagerService.java | 656 | ||||
-rw-r--r-- | services/core/java/com/android/server/dreams/McuHal.java | 46 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/AndFilter.java (renamed from services/java/com/android/server/firewall/AndFilter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/CategoryFilter.java (renamed from services/java/com/android/server/firewall/CategoryFilter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/Filter.java (renamed from services/java/com/android/server/firewall/Filter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/FilterFactory.java (renamed from services/java/com/android/server/firewall/FilterFactory.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/FilterList.java (renamed from services/java/com/android/server/firewall/FilterList.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/IntentFirewall.java (renamed from services/java/com/android/server/firewall/IntentFirewall.java) | 12 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/NotFilter.java (renamed from services/java/com/android/server/firewall/NotFilter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/OrFilter.java (renamed from services/java/com/android/server/firewall/OrFilter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/PortFilter.java (renamed from services/java/com/android/server/firewall/PortFilter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/SenderFilter.java (renamed from services/java/com/android/server/firewall/SenderFilter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/SenderPermissionFilter.java (renamed from services/java/com/android/server/firewall/SenderPermissionFilter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/firewall/StringFilter.java (renamed from services/java/com/android/server/firewall/StringFilter.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/hdmi/HdmiCecDevice.java | 230 | ||||
-rw-r--r-- | services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java | 129 | ||||
-rw-r--r-- | services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java (renamed from services/java/com/android/server/display/DisplayTransactionListener.java) | 23 | ||||
-rw-r--r-- | services/core/java/com/android/server/hdmi/HdmiCecService.java | 388 | ||||
-rw-r--r-- | services/core/java/com/android/server/input/InputApplicationHandle.java (renamed from services/java/com/android/server/input/InputApplicationHandle.java) | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/input/InputManagerService.java (renamed from services/java/com/android/server/input/InputManagerService.java) | 241 | ||||
-rw-r--r-- | services/core/java/com/android/server/input/InputWindowHandle.java (renamed from services/java/com/android/server/input/InputWindowHandle.java) | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/input/PersistentDataStore.java (renamed from services/java/com/android/server/input/PersistentDataStore.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/lights/Light.java | 41 | ||||
-rw-r--r-- | services/core/java/com/android/server/lights/LightsManager.java | 31 | ||||
-rw-r--r-- | services/core/java/com/android/server/lights/LightsService.java (renamed from services/java/com/android/server/LightsService.java) | 98 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/ComprehensiveCountryDetector.java (renamed from services/java/com/android/server/location/ComprehensiveCountryDetector.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/CountryDetectorBase.java (renamed from services/java/com/android/server/location/CountryDetectorBase.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/FlpHardwareProvider.java (renamed from services/java/com/android/server/location/FlpHardwareProvider.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/FusedLocationHardwareSecure.java (renamed from services/java/com/android/server/location/FusedLocationHardwareSecure.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/FusedProxy.java (renamed from services/java/com/android/server/location/FusedProxy.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/GeocoderProxy.java (renamed from services/java/com/android/server/location/GeocoderProxy.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/GeofenceManager.java (renamed from services/java/com/android/server/location/GeofenceManager.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/GeofenceProxy.java (renamed from services/java/com/android/server/location/GeofenceProxy.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/GeofenceState.java (renamed from services/java/com/android/server/location/GeofenceState.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/GpsLocationProvider.java (renamed from services/java/com/android/server/location/GpsLocationProvider.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/GpsXtraDownloader.java (renamed from services/java/com/android/server/location/GpsXtraDownloader.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/LocationBasedCountryDetector.java (renamed from services/java/com/android/server/location/LocationBasedCountryDetector.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/LocationBlacklist.java (renamed from services/java/com/android/server/location/LocationBlacklist.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/LocationFudger.java (renamed from services/java/com/android/server/location/LocationFudger.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/LocationProviderInterface.java (renamed from services/java/com/android/server/location/LocationProviderInterface.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/LocationProviderProxy.java (renamed from services/java/com/android/server/location/LocationProviderProxy.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/MockProvider.java (renamed from services/java/com/android/server/location/MockProvider.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/location/PassiveProvider.java (renamed from services/java/com/android/server/location/PassiveProvider.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/media/MediaRouterService.java (renamed from services/java/com/android/server/media/MediaRouterService.java) | 8 | ||||
-rw-r--r-- | services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java (renamed from services/java/com/android/server/media/RemoteDisplayProviderProxy.java) | 7 | ||||
-rw-r--r-- | services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java (renamed from services/java/com/android/server/media/RemoteDisplayProviderWatcher.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/net/LockdownVpnTracker.java (renamed from services/java/com/android/server/net/LockdownVpnTracker.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/net/NetworkIdentitySet.java (renamed from services/java/com/android/server/net/NetworkIdentitySet.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/net/NetworkPolicyManagerService.java (renamed from services/java/com/android/server/net/NetworkPolicyManagerService.java) | 8 | ||||
-rw-r--r-- | services/core/java/com/android/server/net/NetworkStatsCollection.java (renamed from services/java/com/android/server/net/NetworkStatsCollection.java) | 6 | ||||
-rw-r--r-- | services/core/java/com/android/server/net/NetworkStatsRecorder.java (renamed from services/java/com/android/server/net/NetworkStatsRecorder.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/net/NetworkStatsService.java (renamed from services/java/com/android/server/net/NetworkStatsService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/notification/NotificationDelegate.java | 27 | ||||
-rw-r--r-- | services/core/java/com/android/server/notification/NotificationManagerInternal.java | 24 | ||||
-rw-r--r-- | services/core/java/com/android/server/notification/NotificationManagerService.java (renamed from services/java/com/android/server/NotificationManagerService.java) | 1373 | ||||
-rw-r--r-- | services/core/java/com/android/server/os/SchedulingPolicyService.java (renamed from services/java/com/android/server/os/SchedulingPolicyService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/BasePermission.java (renamed from services/java/com/android/server/pm/BasePermission.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/GrantedPermissions.java (renamed from services/java/com/android/server/pm/GrantedPermissions.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/Installer.java (renamed from services/java/com/android/server/pm/Installer.java) | 22 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/KeySetManager.java (renamed from services/java/com/android/server/pm/KeySetManager.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageKeySetData.java (renamed from services/java/com/android/server/pm/PackageKeySetData.java) | 0 | ||||
-rwxr-xr-x | services/core/java/com/android/server/pm/PackageManagerService.java (renamed from services/java/com/android/server/pm/PackageManagerService.java) | 92 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageSetting.java (renamed from services/java/com/android/server/pm/PackageSetting.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageSettingBase.java (renamed from services/java/com/android/server/pm/PackageSettingBase.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageSignatures.java (renamed from services/java/com/android/server/pm/PackageSignatures.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageVerificationResponse.java (renamed from services/java/com/android/server/pm/PackageVerificationResponse.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageVerificationState.java (renamed from services/java/com/android/server/pm/PackageVerificationState.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PendingPackage.java (renamed from services/java/com/android/server/pm/PendingPackage.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PreferredActivity.java (renamed from services/java/com/android/server/pm/PreferredActivity.java) | 1 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PreferredComponent.java (renamed from services/java/com/android/server/PreferredComponent.java) | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PreferredIntentResolver.java (renamed from services/java/com/android/server/pm/PreferredIntentResolver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/SELinuxMMAC.java (renamed from services/java/com/android/server/pm/SELinuxMMAC.java) | 248 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/Settings.java (renamed from services/java/com/android/server/pm/Settings.java) | 3 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/SharedUserSetting.java (renamed from services/java/com/android/server/pm/SharedUserSetting.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/UserManagerService.java (renamed from services/java/com/android/server/pm/UserManagerService.java) | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/power/Notifier.java (renamed from services/java/com/android/server/power/Notifier.java) | 167 | ||||
-rw-r--r-- | services/core/java/com/android/server/power/PowerManagerService.java (renamed from services/java/com/android/server/power/PowerManagerService.java) | 1504 | ||||
-rw-r--r-- | services/core/java/com/android/server/power/ScreenOnBlocker.java (renamed from services/java/com/android/server/power/ScreenOnBlocker.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/power/ShutdownThread.java (renamed from services/java/com/android/server/power/ShutdownThread.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/power/SuspendBlocker.java (renamed from services/java/com/android/server/power/SuspendBlocker.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/power/WirelessChargerDetector.java (renamed from services/java/com/android/server/power/WirelessChargerDetector.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/search/SearchManagerService.java (renamed from services/java/com/android/server/search/SearchManagerService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/search/Searchables.java (renamed from services/java/com/android/server/search/Searchables.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java | 29 | ||||
-rw-r--r-- | services/core/java/com/android/server/statusbar/StatusBarManagerService.java (renamed from services/java/com/android/server/StatusBarManagerService.java) | 236 | ||||
-rw-r--r-- | services/core/java/com/android/server/storage/DeviceStorageMonitorInternal.java | 24 | ||||
-rw-r--r-- | services/core/java/com/android/server/storage/DeviceStorageMonitorService.java (renamed from services/java/com/android/server/DeviceStorageMonitorService.java) | 250 | ||||
-rw-r--r-- | services/core/java/com/android/server/twilight/TwilightListener.java | 21 | ||||
-rw-r--r-- | services/core/java/com/android/server/twilight/TwilightManager.java | 24 | ||||
-rw-r--r-- | services/core/java/com/android/server/twilight/TwilightService.java (renamed from services/java/com/android/server/TwilightService.java) | 251 | ||||
-rw-r--r-- | services/core/java/com/android/server/twilight/TwilightState.java | 112 | ||||
-rw-r--r-- | services/core/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java (renamed from services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/updates/CertPinInstallReceiver.java (renamed from services/java/com/android/server/updates/CertPinInstallReceiver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java (renamed from services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/updates/IntentFirewallInstallReceiver.java (renamed from services/java/com/android/server/updates/IntentFirewallInstallReceiver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java (renamed from services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java) | 14 | ||||
-rw-r--r-- | services/core/java/com/android/server/updates/SmsShortCodesInstallReceiver.java (renamed from services/java/com/android/server/updates/SmsShortCodesInstallReceiver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/updates/TZInfoInstallReceiver.java (renamed from services/java/com/android/server/updates/TZInfoInstallReceiver.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wallpaper/WallpaperManagerService.java (renamed from services/java/com/android/server/WallpaperManagerService.java) | 20 | ||||
-rw-r--r-- | services/core/java/com/android/server/wifi/README.txt (renamed from services/java/com/android/server/wifi/README.txt) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wifi/WifiController.java (renamed from services/java/com/android/server/wifi/WifiController.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wifi/WifiNotificationController.java (renamed from services/java/com/android/server/wifi/WifiNotificationController.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wifi/WifiService.java (renamed from services/java/com/android/server/wifi/WifiService.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wifi/WifiSettingsStore.java (renamed from services/java/com/android/server/wifi/WifiSettingsStore.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wifi/WifiTrafficPoller.java (renamed from services/java/com/android/server/wifi/WifiTrafficPoller.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/AppTransition.java (renamed from services/java/com/android/server/wm/AppTransition.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/AppWindowAnimator.java (renamed from services/java/com/android/server/wm/AppWindowAnimator.java) | 16 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/AppWindowToken.java (renamed from services/java/com/android/server/wm/AppWindowToken.java) | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/BlackFrame.java (renamed from services/java/com/android/server/wm/BlackFrame.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/CircularDisplayMask.java | 130 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/DimLayer.java (renamed from services/java/com/android/server/wm/DimLayer.java) | 95 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/DisplayContent.java | 415 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/DisplayMagnifier.java (renamed from services/java/com/android/server/wm/DisplayMagnifier.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/DisplaySettings.java (renamed from services/java/com/android/server/wm/DisplaySettings.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/DragState.java (renamed from services/java/com/android/server/wm/DragState.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/FakeWindowImpl.java (renamed from services/java/com/android/server/wm/FakeWindowImpl.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/FocusedStackFrame.java (renamed from services/java/com/android/server/wm/FocusedStackFrame.java) | 8 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/InputMonitor.java (renamed from services/java/com/android/server/wm/InputMonitor.java) | 14 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/KeyguardDisableHandler.java (renamed from services/java/com/android/server/wm/KeyguardDisableHandler.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/PointerEventDispatcher.java (renamed from services/java/com/android/server/wm/PointerEventDispatcher.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/ScreenRotationAnimation.java (renamed from services/java/com/android/server/wm/ScreenRotationAnimation.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/Session.java (renamed from services/java/com/android/server/wm/Session.java) | 6 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/StackTapPointerEventListener.java (renamed from services/java/com/android/server/wm/StackTapPointerEventListener.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/StartingData.java (renamed from services/java/com/android/server/wm/StartingData.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/StrictModeFlash.java (renamed from services/java/com/android/server/wm/StrictModeFlash.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/Task.java (renamed from services/java/com/android/server/wm/Task.java) | 20 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/TaskGroup.java (renamed from services/java/com/android/server/wm/TaskGroup.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/TaskStack.java (renamed from services/java/com/android/server/wm/TaskStack.java) | 190 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/ViewServer.java (renamed from services/java/com/android/server/wm/ViewServer.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/Watermark.java (renamed from services/java/com/android/server/wm/Watermark.java) | 0 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/WindowAnimator.java (renamed from services/java/com/android/server/wm/WindowAnimator.java) | 98 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/WindowManagerService.java (renamed from services/java/com/android/server/wm/WindowManagerService.java) | 833 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/WindowState.java (renamed from services/java/com/android/server/wm/WindowState.java) | 125 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/WindowStateAnimator.java (renamed from services/java/com/android/server/wm/WindowStateAnimator.java) | 106 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/WindowToken.java (renamed from services/java/com/android/server/wm/WindowToken.java) | 0 | ||||
-rw-r--r-- | services/core/jni/Android.mk | 60 | ||||
-rw-r--r-- | services/core/jni/com_android_server_AlarmManagerService.cpp | 321 | ||||
-rw-r--r-- | services/core/jni/com_android_server_AssetAtlasService.cpp (renamed from services/jni/com_android_server_AssetAtlasService.cpp) | 18 | ||||
-rw-r--r-- | services/core/jni/com_android_server_ConsumerIrService.cpp (renamed from services/jni/com_android_server_ConsumerIrService.cpp) | 0 | ||||
-rw-r--r-- | services/core/jni/com_android_server_SerialService.cpp (renamed from services/jni/com_android_server_SerialService.cpp) | 0 | ||||
-rw-r--r-- | services/core/jni/com_android_server_SystemServer.cpp (renamed from services/jni/com_android_server_SystemServer.cpp) | 0 | ||||
-rw-r--r-- | services/core/jni/com_android_server_UsbDeviceManager.cpp (renamed from services/jni/com_android_server_UsbDeviceManager.cpp) | 0 | ||||
-rw-r--r-- | services/core/jni/com_android_server_UsbHostManager.cpp (renamed from services/jni/com_android_server_UsbHostManager.cpp) | 14 | ||||
-rw-r--r-- | services/core/jni/com_android_server_VibratorService.cpp (renamed from services/jni/com_android_server_VibratorService.cpp) | 0 | ||||
-rw-r--r-- | services/core/jni/com_android_server_connectivity_Vpn.cpp (renamed from services/jni/com_android_server_connectivity_Vpn.cpp) | 0 | ||||
-rw-r--r-- | services/core/jni/com_android_server_dreams_McuHal.cpp | 100 | ||||
-rw-r--r-- | services/core/jni/com_android_server_hdmi_HdmiCecService.cpp | 756 | ||||
-rw-r--r-- | services/core/jni/com_android_server_input_InputApplicationHandle.cpp (renamed from services/jni/com_android_server_input_InputApplicationHandle.cpp) | 12 | ||||
-rw-r--r-- | services/core/jni/com_android_server_input_InputApplicationHandle.h (renamed from services/jni/com_android_server_input_InputApplicationHandle.h) | 0 | ||||
-rw-r--r-- | services/core/jni/com_android_server_input_InputManagerService.cpp (renamed from services/jni/com_android_server_input_InputManagerService.cpp) | 252 | ||||
-rw-r--r-- | services/core/jni/com_android_server_input_InputWindowHandle.cpp (renamed from services/jni/com_android_server_input_InputWindowHandle.cpp) | 12 | ||||
-rw-r--r-- | services/core/jni/com_android_server_input_InputWindowHandle.h (renamed from services/jni/com_android_server_input_InputWindowHandle.h) | 0 | ||||
-rw-r--r-- | services/core/jni/com_android_server_lights_LightsService.cpp (renamed from services/jni/com_android_server_LightsService.cpp) | 18 | ||||
-rw-r--r-- | services/core/jni/com_android_server_location_FlpHardwareProvider.cpp (renamed from services/jni/com_android_server_location_FlpHardwareProvider.cpp) | 0 | ||||
-rw-r--r-- | services/core/jni/com_android_server_location_GpsLocationProvider.cpp (renamed from services/jni/com_android_server_location_GpsLocationProvider.cpp) | 57 | ||||
-rw-r--r-- | services/core/jni/com_android_server_power_PowerManagerService.cpp (renamed from services/jni/com_android_server_power_PowerManagerService.cpp) | 55 | ||||
-rw-r--r-- | services/core/jni/com_android_server_power_PowerManagerService.h (renamed from services/jni/com_android_server_power_PowerManagerService.h) | 4 | ||||
-rw-r--r-- | services/core/jni/onload.cpp (renamed from services/jni/onload.cpp) | 9 | ||||
-rw-r--r-- | services/devicepolicy/Android.mk | 12 | ||||
-rw-r--r-- | services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java (renamed from services/java/com/android/server/DevicePolicyManagerService.java) | 352 | ||||
-rw-r--r-- | services/input/Android.mk | 59 | ||||
-rw-r--r-- | services/input/EventHub.cpp | 1583 | ||||
-rw-r--r-- | services/input/EventHub.h | 447 | ||||
-rw-r--r-- | services/input/InputApplication.cpp | 42 | ||||
-rw-r--r-- | services/input/InputApplication.h | 83 | ||||
-rw-r--r-- | services/input/InputDispatcher.cpp | 4470 | ||||
-rw-r--r-- | services/input/InputDispatcher.h | 1123 | ||||
-rw-r--r-- | services/input/InputListener.cpp | 182 | ||||
-rw-r--r-- | services/input/InputListener.h | 196 | ||||
-rw-r--r-- | services/input/InputManager.cpp | 93 | ||||
-rw-r--r-- | services/input/InputManager.h | 109 | ||||
-rw-r--r-- | services/input/InputReader.cpp | 6530 | ||||
-rw-r--r-- | services/input/InputReader.h | 1816 | ||||
-rw-r--r-- | services/input/InputWindow.cpp | 64 | ||||
-rw-r--r-- | services/input/InputWindow.h | 206 | ||||
-rw-r--r-- | services/input/PointerController.cpp | 604 | ||||
-rw-r--r-- | services/input/PointerController.h | 266 | ||||
-rw-r--r-- | services/input/SpriteController.cpp | 482 | ||||
-rw-r--r-- | services/input/SpriteController.h | 293 | ||||
-rw-r--r-- | services/input/tests/Android.mk | 48 | ||||
-rw-r--r-- | services/input/tests/InputDispatcher_test.cpp | 247 | ||||
-rw-r--r-- | services/input/tests/InputReader_test.cpp | 5099 | ||||
-rw-r--r-- | services/java/Android.mk | 18 | ||||
-rw-r--r-- | services/java/com/android/server/AppWidgetService.java | 363 | ||||
-rw-r--r-- | services/java/com/android/server/SystemServer.java | 619 | ||||
-rw-r--r-- | services/java/com/android/server/display/DisplayViewport.java | 75 | ||||
-rw-r--r-- | services/java/com/android/server/display/HeadlessDisplayAdapter.java | 73 | ||||
-rw-r--r-- | services/java/com/android/server/dreams/DreamManagerService.java | 425 | ||||
-rw-r--r-- | services/java/com/android/server/power/DisplayPowerRequest.java | 117 | ||||
-rw-r--r-- | services/java/com/android/server/print/PrintManagerService.java | 656 | ||||
-rw-r--r-- | services/java/com/android/server/wm/DisplayContent.java | 523 | ||||
-rw-r--r-- | services/java/com/android/server/wm/StackBox.java | 414 | ||||
-rw-r--r-- | services/jni/Android.mk | 63 | ||||
-rw-r--r-- | services/jni/com_android_server_AlarmManagerService.cpp | 114 | ||||
-rw-r--r-- | services/print/Android.mk | 10 | ||||
-rw-r--r-- | services/print/java/com/android/server/print/PrintManagerService.java | 689 | ||||
-rw-r--r-- | services/print/java/com/android/server/print/RemotePrintService.java (renamed from services/java/com/android/server/print/RemotePrintService.java) | 0 | ||||
-rw-r--r-- | services/print/java/com/android/server/print/RemotePrintSpooler.java (renamed from services/java/com/android/server/print/RemotePrintSpooler.java) | 0 | ||||
-rw-r--r-- | services/print/java/com/android/server/print/UserState.java (renamed from services/java/com/android/server/print/UserState.java) | 0 | ||||
-rw-r--r-- | services/tests/Android.mk | 3 | ||||
-rw-r--r-- | services/tests/servicestests/src/com/android/server/EntropyMixerTest.java | 2 | ||||
-rw-r--r-- | services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java | 54 | ||||
-rw-r--r-- | services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java | 6 | ||||
-rw-r--r-- | services/usb/Android.mk | 12 | ||||
-rw-r--r-- | services/usb/java/com/android/server/usb/UsbDebuggingManager.java (renamed from services/java/com/android/server/usb/UsbDebuggingManager.java) | 67 | ||||
-rw-r--r-- | services/usb/java/com/android/server/usb/UsbDeviceManager.java (renamed from services/java/com/android/server/usb/UsbDeviceManager.java) | 2 | ||||
-rw-r--r-- | services/usb/java/com/android/server/usb/UsbHostManager.java (renamed from services/java/com/android/server/usb/UsbHostManager.java) | 4 | ||||
-rw-r--r-- | services/usb/java/com/android/server/usb/UsbService.java (renamed from services/java/com/android/server/usb/UsbService.java) | 23 | ||||
-rw-r--r-- | services/usb/java/com/android/server/usb/UsbSettingsManager.java (renamed from services/java/com/android/server/usb/UsbSettingsManager.java) | 169 |
373 files changed, 12564 insertions, 37096 deletions
diff --git a/services/Android.mk b/services/Android.mk new file mode 100644 index 0000000..5260540 --- /dev/null +++ b/services/Android.mk @@ -0,0 +1,64 @@ +LOCAL_PATH:= $(call my-dir) + +# merge all required services into one jar +# ============================================================ +include $(CLEAR_VARS) + +LOCAL_MODULE := services + +LOCAL_SRC_FILES := $(call all-java-files-under,java) + +# Uncomment to enable output of certain warnings (deprecated, unchecked) +# LOCAL_JAVACFLAGS := -Xlint + +# Services that will be built as part of services.jar +# These should map to directory names relative to this +# Android.mk. +services := \ + core \ + accessibility \ + appwidget \ + backup \ + devicepolicy \ + print \ + usb + +# The convention is to name each service module 'services.$(module_name)' +LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services)) + +include $(BUILD_JAVA_LIBRARY) + +# native library +# ============================================================= + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := +LOCAL_SHARED_LIBRARIES := + +# include all the jni subdirs to collect their sources +include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk) + +LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES + +ifeq ($(WITH_MALLOC_LEAK_CHECK),true) + LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK +endif + +LOCAL_MODULE:= libandroid_servers + +include $(BUILD_SHARED_LIBRARY) + +# ============================================================= + +ifeq (,$(ONE_SHOT_MAKEFILE)) +# A full make is happening, so make everything. +include $(call all-makefiles-under,$(LOCAL_PATH)) +else +# If we ran an mm[m] command, we still want to build the individual +# services that we depend on. This differs from the above condition +# by only including service makefiles and not any tests or other +# modules. +include $(patsubst %,$(LOCAL_PATH)/%/Android.mk,$(services)) +endif + diff --git a/services/accessibility/Android.mk b/services/accessibility/Android.mk new file mode 100644 index 0000000..d98fc28 --- /dev/null +++ b/services/accessibility/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.accessibility + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 9e893da..9e893da 100644 --- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index ccac0d3..ccac0d3 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java diff --git a/services/java/com/android/server/accessibility/EventStreamTransformation.java b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java index 8c93e7b..8c93e7b 100644 --- a/services/java/com/android/server/accessibility/EventStreamTransformation.java +++ b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java diff --git a/services/java/com/android/server/accessibility/GestureUtils.java b/services/accessibility/java/com/android/server/accessibility/GestureUtils.java index b68b09f..b68b09f 100644 --- a/services/java/com/android/server/accessibility/GestureUtils.java +++ b/services/accessibility/java/com/android/server/accessibility/GestureUtils.java diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java index 5f12cf4..5f12cf4 100644 --- a/services/java/com/android/server/accessibility/ScreenMagnifier.java +++ b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java index 43f12eb..43f12eb 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java diff --git a/services/appwidget/Android.mk b/services/appwidget/Android.mk new file mode 100644 index 0000000..ca38f2f --- /dev/null +++ b/services/appwidget/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.appwidget + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java new file mode 100644 index 0000000..e208677 --- /dev/null +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2007 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.appwidget; + +import android.app.ActivityManager; +import android.appwidget.AppWidgetProviderInfo; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Slog; +import android.util.SparseArray; +import android.widget.RemoteViews; + +import com.android.internal.appwidget.IAppWidgetHost; +import com.android.internal.appwidget.IAppWidgetService; +import com.android.internal.os.BackgroundThread; +import com.android.internal.util.IndentingPrintWriter; +import com.android.server.SystemService; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.List; +import java.util.Locale; + + +/** + * SystemService that publishes an IAppWidgetService. + */ +public class AppWidgetService extends SystemService { + + static final String TAG = "AppWidgetService"; + + final Context mContext; + final Handler mSaveStateHandler; + + final SparseArray<AppWidgetServiceImpl> mAppWidgetServices; + + public AppWidgetService(Context context) { + super(context); + mContext = context; + + mSaveStateHandler = BackgroundThread.getHandler(); + + mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5); + AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler); + mAppWidgetServices.append(0, primary); + } + + @Override + public void onStart() { + publishBinderService(Context.APPWIDGET_SERVICE, mServiceImpl); + } + + @Override + public void onBootPhase(int phase) { + if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + mServiceImpl.systemRunning(isSafeMode()); + } + } + + private final AppWidgetServiceStub mServiceImpl = new AppWidgetServiceStub(); + + private class AppWidgetServiceStub extends IAppWidgetService.Stub { + + private boolean mSafeMode; + private Locale mLocale; + private PackageManager mPackageManager; + + public void systemRunning(boolean safeMode) { + mSafeMode = safeMode; + + mAppWidgetServices.get(0).systemReady(safeMode); + + // Register for the boot completed broadcast, so we can send the + // ENABLE broacasts. If we try to send them now, they time out, + // because the system isn't ready to handle them yet. + mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, + new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); + + // Register for configuration changes so we can update the names + // of the widgets when the locale changes. + mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, + new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null); + + // Register for broadcasts about package install, etc., so we can + // update the provider list. + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addDataScheme("package"); + mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, + filter, null, null); + // Register for events related to sdcard installation. + IntentFilter sdFilter = new IntentFilter(); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); + mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, + sdFilter, null, null); + + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + userFilter.addAction(Intent.ACTION_USER_STOPPING); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { + onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, + UserHandle.USER_NULL)); + } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) { + onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, + UserHandle.USER_NULL)); + } + } + }, userFilter); + } + + @Override + public int allocateAppWidgetId(String packageName, int hostId, int userId) + throws RemoteException { + return getImplForUser(userId).allocateAppWidgetId(packageName, hostId); + } + + @Override + public int[] getAppWidgetIdsForHost(int hostId, int userId) throws RemoteException { + return getImplForUser(userId).getAppWidgetIdsForHost(hostId); + } + + @Override + public void deleteAppWidgetId(int appWidgetId, int userId) throws RemoteException { + getImplForUser(userId).deleteAppWidgetId(appWidgetId); + } + + @Override + public void deleteHost(int hostId, int userId) throws RemoteException { + getImplForUser(userId).deleteHost(hostId); + } + + @Override + public void deleteAllHosts(int userId) throws RemoteException { + getImplForUser(userId).deleteAllHosts(); + } + + @Override + public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options, + int userId) throws RemoteException { + getImplForUser(userId).bindAppWidgetId(appWidgetId, provider, options); + } + + @Override + public boolean bindAppWidgetIdIfAllowed( + String packageName, int appWidgetId, ComponentName provider, Bundle options, + int userId) throws RemoteException { + return getImplForUser(userId).bindAppWidgetIdIfAllowed( + packageName, appWidgetId, provider, options); + } + + @Override + public boolean hasBindAppWidgetPermission(String packageName, int userId) + throws RemoteException { + return getImplForUser(userId).hasBindAppWidgetPermission(packageName); + } + + @Override + public void setBindAppWidgetPermission(String packageName, boolean permission, int userId) + throws RemoteException { + getImplForUser(userId).setBindAppWidgetPermission(packageName, permission); + } + + @Override + public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection, + int userId) throws RemoteException { + getImplForUser(userId).bindRemoteViewsService(appWidgetId, intent, connection); + } + + @Override + public int[] startListening(IAppWidgetHost host, String packageName, int hostId, + List<RemoteViews> updatedViews, int userId) throws RemoteException { + return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews); + } + + public void onUserRemoved(int userId) { + if (userId < 1) return; + synchronized (mAppWidgetServices) { + AppWidgetServiceImpl impl = mAppWidgetServices.get(userId); + mAppWidgetServices.remove(userId); + + if (impl == null) { + AppWidgetServiceImpl.getSettingsFile(userId).delete(); + } else { + impl.onUserRemoved(); + } + } + } + + public void onUserStopping(int userId) { + if (userId < 1) return; + synchronized (mAppWidgetServices) { + AppWidgetServiceImpl impl = mAppWidgetServices.get(userId); + if (impl != null) { + mAppWidgetServices.remove(userId); + impl.onUserStopping(); + } + } + } + + private void checkPermission(int userId) { + int realUserId = ActivityManager.handleIncomingUser( + Binder.getCallingPid(), + Binder.getCallingUid(), + userId, + false, /* allowAll */ + true, /* requireFull */ + this.getClass().getSimpleName(), + this.getClass().getPackage().getName()); + } + + private AppWidgetServiceImpl getImplForUser(int userId) { + checkPermission(userId); + boolean sendInitial = false; + AppWidgetServiceImpl service; + synchronized (mAppWidgetServices) { + service = mAppWidgetServices.get(userId); + if (service == null) { + Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + + ", adding"); + // TODO: Verify that it's a valid user + service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler); + service.systemReady(mSafeMode); + // Assume that BOOT_COMPLETED was received, as this is a non-primary user. + mAppWidgetServices.append(userId, service); + sendInitial = true; + } + } + if (sendInitial) { + service.sendInitialBroadcasts(); + } + return service; + } + + @Override + public int[] getAppWidgetIds(ComponentName provider, int userId) throws RemoteException { + return getImplForUser(userId).getAppWidgetIds(provider); + } + + @Override + public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId) + throws RemoteException { + return getImplForUser(userId).getAppWidgetInfo(appWidgetId); + } + + @Override + public RemoteViews getAppWidgetViews(int appWidgetId, int userId) throws RemoteException { + return getImplForUser(userId).getAppWidgetViews(appWidgetId); + } + + @Override + public void updateAppWidgetOptions(int appWidgetId, Bundle options, int userId) { + getImplForUser(userId).updateAppWidgetOptions(appWidgetId, options); + } + + @Override + public Bundle getAppWidgetOptions(int appWidgetId, int userId) { + return getImplForUser(userId).getAppWidgetOptions(appWidgetId); + } + + @Override + public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId) + throws RemoteException { + return getImplForUser(userId).getInstalledProviders(categoryFilter); + } + + @Override + public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId, int userId) + throws RemoteException { + getImplForUser(userId).notifyAppWidgetViewDataChanged( + appWidgetIds, viewId); + } + + @Override + public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId) + throws RemoteException { + getImplForUser(userId).partiallyUpdateAppWidgetIds( + appWidgetIds, views); + } + + @Override + public void stopListening(int hostId, int userId) throws RemoteException { + getImplForUser(userId).stopListening(hostId); + } + + @Override + public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId) + throws RemoteException { + getImplForUser(userId).unbindRemoteViewsService( + appWidgetId, intent); + } + + @Override + public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId) + throws RemoteException { + getImplForUser(userId).updateAppWidgetIds(appWidgetIds, views); + } + + @Override + public void updateAppWidgetProvider(ComponentName provider, RemoteViews views, int userId) + throws RemoteException { + getImplForUser(userId).updateAppWidgetProvider(provider, views); + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); + + // Dump the state of all the app widget providers + synchronized (mAppWidgetServices) { + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + for (int i = 0; i < mAppWidgetServices.size(); i++) { + pw.println("User: " + mAppWidgetServices.keyAt(i)); + ipw.increaseIndent(); + AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); + service.dump(fd, ipw, args); + ipw.decreaseIndent(); + } + } + } + + BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + // Slog.d(TAG, "received " + action); + if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); + if (userId >= 0) { + getImplForUser(userId).sendInitialBroadcasts(); + } else { + Slog.w(TAG, "Incorrect user handle supplied in " + intent); + } + } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { + for (int i = 0; i < mAppWidgetServices.size(); i++) { + AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); + service.onConfigurationChanged(); + } + } else { + int sendingUser = getSendingUserId(); + if (sendingUser == UserHandle.USER_ALL) { + for (int i = 0; i < mAppWidgetServices.size(); i++) { + AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); + service.onBroadcastReceived(intent); + } + } else { + AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser); + if (service != null) { + service.onBroadcastReceived(intent); + } + } + } + } + }; + } +} diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 69ae846..98dead3 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.appwidget; import android.app.AlarmManager; import android.app.AppGlobals; diff --git a/services/backup/Android.mk b/services/backup/Android.mk new file mode 100644 index 0000000..3e686d1 --- /dev/null +++ b/services/backup/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.backup + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) + +LOCAL_JAVA_LIBRARIES := services.core + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/java/com/android/server/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 6d65a70..b3571d7 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.backup; import android.app.ActivityManagerNative; import android.app.AlarmManager; @@ -83,7 +83,8 @@ import com.android.internal.backup.BackupConstants; import com.android.internal.backup.IBackupTransport; import com.android.internal.backup.IObbBackupService; import com.android.server.EventLogTags; -import com.android.server.PackageManagerBackupAgent.Metadata; +import com.android.server.SystemService; +import com.android.server.backup.PackageManagerBackupAgent.Metadata; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -135,7 +136,8 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; -class BackupManagerService extends IBackupManager.Stub { +public class BackupManagerService extends IBackupManager.Stub { + private static final String TAG = "BackupManagerService"; private static final boolean DEBUG = true; private static final boolean MORE_DEBUG = false; @@ -276,6 +278,20 @@ class BackupManagerService extends IBackupManager.Stub { // Watch the device provisioning operation during setup ContentObserver mProvisionedObserver; + public static final class Lifecycle extends SystemService { + private final BackupManagerService mService; + + public Lifecycle(Context context) { + super(context); + mService = new BackupManagerService(context); + } + + @Override + public void onStart() { + publishBinderService(Context.BACKUP_SERVICE, mService); + } + } + class ProvisionedObserver extends ContentObserver { public ProvisionedObserver(Handler handler) { super(handler); @@ -1206,7 +1222,8 @@ class BackupManagerService extends IBackupManager.Stub { // First, on an encrypted device we require matching the device pw final boolean isEncrypted; try { - isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE); + isEncrypted = (mMountService.getEncryptionState() != + IMountService.ENCRYPTION_STATE_NONE); if (isEncrypted) { if (DEBUG) { Slog.i(TAG, "Device encrypted; verifying against device data pw"); @@ -5523,7 +5540,8 @@ class BackupManagerService extends IBackupManager.Stub { boolean isEncrypted; try { - isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE); + isEncrypted = (mMountService.getEncryptionState() != + IMountService.ENCRYPTION_STATE_NONE); if (isEncrypted) Slog.w(TAG, "Device is encrypted; forcing enc password"); } catch (RemoteException e) { // couldn't contact the mount service; fail "safe" and assume encryption @@ -6181,7 +6199,7 @@ class BackupManagerService extends IBackupManager.Stub { } } - // clean up the BackupManagerService side of the bookkeeping + // clean up the BackupManagerImpl side of the bookkeeping // and cancel any pending timeout message mBackupManager.clearRestoreSession(mSession); } diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java index 77bddb0..495da88 100644 --- a/services/java/com/android/server/PackageManagerBackupAgent.java +++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.backup; import android.app.backup.BackupAgent; import android.app.backup.BackupDataInput; diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/backup/java/com/android/server/backup/SystemBackupAgent.java index 8cf273d..26e2e2a 100644 --- a/services/java/com/android/server/SystemBackupAgent.java +++ b/services/backup/java/com/android/server/backup/SystemBackupAgent.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.backup; +import android.app.IWallpaperManager; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupAgentHelper; @@ -26,11 +27,11 @@ import android.app.backup.WallpaperBackupHelper; import android.content.Context; import android.os.Environment; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.util.Slog; - import java.io.File; import java.io.IOException; @@ -63,16 +64,23 @@ public class SystemBackupAgent extends BackupAgentHelper { public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException { // We only back up the data under the current "wallpaper" schema with metadata - WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService( + IWallpaperManager wallpaper = (IWallpaperManager)ServiceManager.getService( Context.WALLPAPER_SERVICE); String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }; String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY }; - if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) { - // When the wallpaper has a name, back up the info by itself. - // TODO: Don't rely on the innards of the service object like this! - // TODO: Send a delete for any stored wallpaper image in this case? - files = new String[] { WALLPAPER_INFO }; - keys = new String[] { WALLPAPER_INFO_KEY }; + if (wallpaper != null) { + try { + final String wallpaperName = wallpaper.getName(); + if (wallpaperName != null && wallpaperName.length() > 0) { + // When the wallpaper has a name, back up the info by itself. + // TODO: Don't rely on the innards of the service object like this! + // TODO: Send a delete for any stored wallpaper image in this case? + files = new String[] { WALLPAPER_INFO }; + keys = new String[] { WALLPAPER_INFO_KEY }; + } + } catch (RemoteException re) { + Slog.e(TAG, "Couldn't get wallpaper name\n" + re); + } } addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys)); super.onBackup(oldState, data, newState); @@ -109,9 +117,15 @@ public class SystemBackupAgent extends BackupAgentHelper { try { super.onRestore(data, appVersionCode, newState); - WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService( + IWallpaperManager wallpaper = (IWallpaperManager) ServiceManager.getService( Context.WALLPAPER_SERVICE); - wallpaper.settingsRestored(); + if (wallpaper != null) { + try { + wallpaper.settingsRestored(); + } catch (RemoteException re) { + Slog.e(TAG, "Couldn't restore settings\n" + re); + } + } } catch (IOException ex) { // If there was a failure, delete everything for the wallpaper, this is too aggressive, // but this is hopefully a rare failure. @@ -149,10 +163,16 @@ public class SystemBackupAgent extends BackupAgentHelper { FullBackup.restoreFile(data, size, type, mode, mtime, outFile); if (restoredWallpaper) { - WallpaperManagerService wallpaper = - (WallpaperManagerService)ServiceManager.getService( + IWallpaperManager wallpaper = + (IWallpaperManager)ServiceManager.getService( Context.WALLPAPER_SERVICE); - wallpaper.settingsRestored(); + if (wallpaper != null) { + try { + wallpaper.settingsRestored(); + } catch (RemoteException re) { + Slog.e(TAG, "Couldn't restore settings\n" + re); + } + } } } catch (IOException e) { if (restoredWallpaper) { diff --git a/services/common_time/Android.mk b/services/common_time/Android.mk deleted file mode 100644 index 75eb528..0000000 --- a/services/common_time/Android.mk +++ /dev/null @@ -1,36 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -# -# common_time_service -# - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - common_clock_service.cpp \ - common_time_config_service.cpp \ - common_time_server.cpp \ - common_time_server_api.cpp \ - common_time_server_packets.cpp \ - clock_recovery.cpp \ - common_clock.cpp \ - main.cpp \ - utils.cpp - -# Uncomment to enable vesbose logging and debug service. -#TIME_SERVICE_DEBUG=true -ifeq ($(TIME_SERVICE_DEBUG), true) -LOCAL_SRC_FILES += diag_thread.cpp -LOCAL_CFLAGS += -DTIME_SERVICE_DEBUG -endif - -LOCAL_SHARED_LIBRARIES := \ - libbinder \ - libcommon_time_client \ - libutils \ - liblog - -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := common_time - -include $(BUILD_EXECUTABLE) diff --git a/services/common_time/clock_recovery.cpp b/services/common_time/clock_recovery.cpp deleted file mode 100644 index 3a7c70c..0000000 --- a/services/common_time/clock_recovery.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -/* - * A service that exchanges time synchronization information between - * a master that defines a timeline and clients that follow the timeline. - */ - -#define __STDC_LIMIT_MACROS -#define LOG_TAG "common_time" -#include <utils/Log.h> -#include <stdint.h> - -#include <common_time/local_clock.h> -#include <assert.h> - -#include "clock_recovery.h" -#include "common_clock.h" -#ifdef TIME_SERVICE_DEBUG -#include "diag_thread.h" -#endif - -// Define log macro so we can make LOGV into LOGE when we are exclusively -// debugging this code. -#ifdef TIME_SERVICE_DEBUG -#define LOG_TS ALOGE -#else -#define LOG_TS ALOGV -#endif - -namespace android { - -ClockRecoveryLoop::ClockRecoveryLoop(LocalClock* local_clock, - CommonClock* common_clock) { - assert(NULL != local_clock); - assert(NULL != common_clock); - - local_clock_ = local_clock; - common_clock_ = common_clock; - - local_clock_can_slew_ = local_clock_->initCheck() && - (local_clock_->setLocalSlew(0) == OK); - tgt_correction_ = 0; - cur_correction_ = 0; - - // Precompute the max rate at which we are allowed to change the VCXO - // control. - uint64_t N = 0x10000ull * 1000ull; - uint64_t D = local_clock_->getLocalFreq() * kMinFullRangeSlewChange_mSec; - LinearTransform::reduce(&N, &D); - while ((N > INT32_MAX) || (D > UINT32_MAX)) { - N >>= 1; - D >>= 1; - LinearTransform::reduce(&N, &D); - } - time_to_cur_slew_.a_to_b_numer = static_cast<int32_t>(N); - time_to_cur_slew_.a_to_b_denom = static_cast<uint32_t>(D); - - reset(true, true); - -#ifdef TIME_SERVICE_DEBUG - diag_thread_ = new DiagThread(common_clock_, local_clock_); - if (diag_thread_ != NULL) { - status_t res = diag_thread_->startWorkThread(); - if (res != OK) - ALOGW("Failed to start A@H clock recovery diagnostic thread."); - } else - ALOGW("Failed to allocate diagnostic thread."); -#endif -} - -ClockRecoveryLoop::~ClockRecoveryLoop() { -#ifdef TIME_SERVICE_DEBUG - diag_thread_->stopWorkThread(); -#endif -} - -// Constants. -const float ClockRecoveryLoop::dT = 1.0; -const float ClockRecoveryLoop::Kc = 1.0f; -const float ClockRecoveryLoop::Ti = 15.0f; -const float ClockRecoveryLoop::Tf = 0.05; -const float ClockRecoveryLoop::bias_Fc = 0.01; -const float ClockRecoveryLoop::bias_RC = (dT / (2 * 3.14159f * bias_Fc)); -const float ClockRecoveryLoop::bias_Alpha = (dT / (bias_RC + dT)); -const int64_t ClockRecoveryLoop::panic_thresh_ = 50000; -const int64_t ClockRecoveryLoop::control_thresh_ = 10000; -const float ClockRecoveryLoop::COmin = -100.0f; -const float ClockRecoveryLoop::COmax = 100.0f; -const uint32_t ClockRecoveryLoop::kMinFullRangeSlewChange_mSec = 300; -const int ClockRecoveryLoop::kSlewChangeStepPeriod_mSec = 10; - - -void ClockRecoveryLoop::reset(bool position, bool frequency) { - Mutex::Autolock lock(&lock_); - reset_l(position, frequency); -} - -uint32_t ClockRecoveryLoop::findMinRTTNdx(DisciplineDataPoint* data, - uint32_t count) { - uint32_t min_rtt = 0; - for (uint32_t i = 1; i < count; ++i) - if (data[min_rtt].rtt > data[i].rtt) - min_rtt = i; - - return min_rtt; -} - -bool ClockRecoveryLoop::pushDisciplineEvent(int64_t local_time, - int64_t nominal_common_time, - int64_t rtt) { - Mutex::Autolock lock(&lock_); - - int64_t local_common_time = 0; - common_clock_->localToCommon(local_time, &local_common_time); - int64_t raw_delta = nominal_common_time - local_common_time; - -#ifdef TIME_SERVICE_DEBUG - ALOGE("local=%lld, common=%lld, delta=%lld, rtt=%lld\n", - local_common_time, nominal_common_time, - raw_delta, rtt); -#endif - - // If we have not defined a basis for common time, then we need to use these - // initial points to do so. In order to avoid significant initial error - // from a particularly bad startup data point, we collect the first N data - // points and choose the best of them before moving on. - if (!common_clock_->isValid()) { - if (startup_filter_wr_ < kStartupFilterSize) { - DisciplineDataPoint& d = startup_filter_data_[startup_filter_wr_]; - d.local_time = local_time; - d.nominal_common_time = nominal_common_time; - d.rtt = rtt; - startup_filter_wr_++; - } - - if (startup_filter_wr_ == kStartupFilterSize) { - uint32_t min_rtt = findMinRTTNdx(startup_filter_data_, - kStartupFilterSize); - - common_clock_->setBasis( - startup_filter_data_[min_rtt].local_time, - startup_filter_data_[min_rtt].nominal_common_time); - } - - return true; - } - - int64_t observed_common; - int64_t delta; - float delta_f, dCO; - int32_t tgt_correction; - - if (OK != common_clock_->localToCommon(local_time, &observed_common)) { - // Since we just checked to make certain that this conversion was valid, - // and no one else in the system should be messing with it, if this - // conversion is suddenly invalid, it is a good reason to panic. - ALOGE("Failed to convert local time to common time in %s:%d", - __PRETTY_FUNCTION__, __LINE__); - return false; - } - - // Implement a filter which should match NTP filtering behavior when a - // client is associated with only one peer of lower stratum. Basically, - // always use the best of the N last data points, where best is defined as - // lowest round trip time. NTP uses an N of 8; we use a value of 6. - // - // TODO(johngro) : experiment with other filter strategies. The goal here - // is to mitigate the effects of high RTT data points which typically have - // large asymmetries in the TX/RX legs. Downside of the existing NTP - // approach (particularly because of the PID controller we are using to - // produce the control signal from the filtered data) are that the rate at - // which discipline events are actually acted upon becomes irregular and can - // become drawn out (the time between actionable event can go way up). If - // the system receives a strong high quality data point, the proportional - // component of the controller can produce a strong correction which is left - // in place for too long causing overshoot. In addition, the integral - // component of the system currently is an approximation based on the - // assumption of a more or less homogeneous sampling of the error. Its - // unclear what the effect of undermining this assumption would be right - // now. - - // Two ideas which come to mind immediately would be to... - // 1) Keep a history of more data points (32 or so) and ignore data points - // whose RTT is more than a certain number of standard deviations outside - // of the norm. - // 2) Eliminate the PID controller portion of this system entirely. - // Instead, move to a system which uses a very wide filter (128 data - // points or more) with a sum-of-least-squares line fitting approach to - // tracking the long term drift. This would take the place of the I - // component in the current PID controller. Also use a much more narrow - // outlier-rejector filter (as described in #1) to drive a short term - // correction factor similar to the P component of the PID controller. - assert(filter_wr_ < kFilterSize); - filter_data_[filter_wr_].local_time = local_time; - filter_data_[filter_wr_].observed_common_time = observed_common; - filter_data_[filter_wr_].nominal_common_time = nominal_common_time; - filter_data_[filter_wr_].rtt = rtt; - filter_data_[filter_wr_].point_used = false; - uint32_t current_point = filter_wr_; - filter_wr_ = (filter_wr_ + 1) % kFilterSize; - if (!filter_wr_) - filter_full_ = true; - - uint32_t scan_end = filter_full_ ? kFilterSize : filter_wr_; - uint32_t min_rtt = findMinRTTNdx(filter_data_, scan_end); - // We only use packets with low RTTs for control. If the packet RTT - // is less than the panic threshold, we can probably eat the jitter with the - // control loop. Otherwise, take the packet only if it better than all - // of the packets we have in the history. That way we try to track - // something, even if it is noisy. - if (current_point == min_rtt || rtt < control_thresh_) { - delta_f = delta = nominal_common_time - observed_common; - - last_error_est_valid_ = true; - last_error_est_usec_ = delta; - - // Compute the error then clamp to the panic threshold. If we ever - // exceed this amt of error, its time to panic and reset the system. - // Given that the error in the measurement of the error could be as - // high as the RTT of the data point, we don't actually panic until - // the implied error (delta) is greater than the absolute panic - // threashold plus the RTT. IOW - we don't panic until we are - // absoluely sure that our best case sync is worse than the absolute - // panic threshold. - int64_t effective_panic_thresh = panic_thresh_ + rtt; - if ((delta > effective_panic_thresh) || - (delta < -effective_panic_thresh)) { - // PANIC!!! - reset_l(false, true); - return false; - } - - } else { - // We do not have a good packet to look at, but we also do not want to - // free-run the clock at some crazy slew rate. So we guess the - // trajectory of the clock based on the last controller output and the - // estimated bias of our clock against the master. - // The net effect of this is that CO == CObias after some extended - // period of no feedback. - delta_f = last_delta_f_ - dT*(CO - CObias); - delta = delta_f; - } - - // Velocity form PI control equation. - dCO = Kc * (1.0f + dT/Ti) * delta_f - Kc * last_delta_f_; - CO += dCO * Tf; // Filter CO by applying gain <1 here. - - // Save error terms for later. - last_delta_f_ = delta_f; - - // Clamp CO to +/- 100ppm. - if (CO < COmin) - CO = COmin; - else if (CO > COmax) - CO = COmax; - - // Update the controller bias. - CObias = bias_Alpha * CO + (1.0f - bias_Alpha) * lastCObias; - lastCObias = CObias; - - // Convert PPM to 16-bit int range. Add some guard band (-0.01) so we - // don't get fp weirdness. - tgt_correction = CO * 327.66; - - // If there was a change in the amt of correction to use, update the - // system. - setTargetCorrection_l(tgt_correction); - - LOG_TS("clock_loop %lld %f %f %f %d\n", raw_delta, delta_f, CO, CObias, tgt_correction); - -#ifdef TIME_SERVICE_DEBUG - diag_thread_->pushDisciplineEvent( - local_time, - observed_common, - nominal_common_time, - tgt_correction, - rtt); -#endif - - return true; -} - -int32_t ClockRecoveryLoop::getLastErrorEstimate() { - Mutex::Autolock lock(&lock_); - - if (last_error_est_valid_) - return last_error_est_usec_; - else - return ICommonClock::kErrorEstimateUnknown; -} - -void ClockRecoveryLoop::reset_l(bool position, bool frequency) { - assert(NULL != common_clock_); - - if (position) { - common_clock_->resetBasis(); - startup_filter_wr_ = 0; - } - - if (frequency) { - last_error_est_valid_ = false; - last_error_est_usec_ = 0; - last_delta_f_ = 0.0; - CO = 0.0f; - lastCObias = CObias = 0.0f; - setTargetCorrection_l(0); - applySlew_l(); - } - - filter_wr_ = 0; - filter_full_ = false; -} - -void ClockRecoveryLoop::setTargetCorrection_l(int32_t tgt) { - // When we make a change to the slew rate, we need to be careful to not - // change it too quickly as it can anger some HDMI sinks out there, notably - // some Sony panels from the 2010-2011 timeframe. From experimenting with - // some of these sinks, it seems like swinging from one end of the range to - // another in less that 190mSec or so can start to cause trouble. Adding in - // a hefty margin, we limit the system to a full range sweep in no less than - // 300mSec. - if (tgt_correction_ != tgt) { - int64_t now = local_clock_->getLocalTime(); - status_t res; - - tgt_correction_ = tgt; - - // Set up the transformation to figure out what the slew should be at - // any given point in time in the future. - time_to_cur_slew_.a_zero = now; - time_to_cur_slew_.b_zero = cur_correction_; - - // Make sure the sign of the slope is headed in the proper direction. - bool needs_increase = (cur_correction_ < tgt_correction_); - bool is_increasing = (time_to_cur_slew_.a_to_b_numer > 0); - if (( needs_increase && !is_increasing) || - (!needs_increase && is_increasing)) { - time_to_cur_slew_.a_to_b_numer = -time_to_cur_slew_.a_to_b_numer; - } - - // Finally, figure out when the change will be finished and start the - // slew operation. - time_to_cur_slew_.doReverseTransform(tgt_correction_, - &slew_change_end_time_); - - applySlew_l(); - } -} - -bool ClockRecoveryLoop::applySlew_l() { - bool ret = true; - - // If cur == tgt, there is no ongoing sleq rate change and we are already - // finished. - if (cur_correction_ == tgt_correction_) - goto bailout; - - if (local_clock_can_slew_) { - int64_t now = local_clock_->getLocalTime(); - int64_t tmp; - - if (now >= slew_change_end_time_) { - cur_correction_ = tgt_correction_; - next_slew_change_timeout_.setTimeout(-1); - } else { - time_to_cur_slew_.doForwardTransform(now, &tmp); - - if (tmp > INT16_MAX) - cur_correction_ = INT16_MAX; - else if (tmp < INT16_MIN) - cur_correction_ = INT16_MIN; - else - cur_correction_ = static_cast<int16_t>(tmp); - - next_slew_change_timeout_.setTimeout(kSlewChangeStepPeriod_mSec); - ret = false; - } - - local_clock_->setLocalSlew(cur_correction_); - } else { - // Since we are not actually changing the rate of a HW clock, we don't - // need to worry to much about changing the slew rate so fast that we - // anger any downstream HDMI devices. - cur_correction_ = tgt_correction_; - next_slew_change_timeout_.setTimeout(-1); - - // The SW clock recovery implemented by the common clock class expects - // values expressed in PPM. CO is in ppm. - common_clock_->setSlew(local_clock_->getLocalTime(), CO); - } - -bailout: - return ret; -} - -int ClockRecoveryLoop::applyRateLimitedSlew() { - Mutex::Autolock lock(&lock_); - - int ret = next_slew_change_timeout_.msecTillTimeout(); - if (!ret) { - if (applySlew_l()) - next_slew_change_timeout_.setTimeout(-1); - ret = next_slew_change_timeout_.msecTillTimeout(); - } - - return ret; -} - -} // namespace android diff --git a/services/common_time/clock_recovery.h b/services/common_time/clock_recovery.h deleted file mode 100644 index b6c87ff..0000000 --- a/services/common_time/clock_recovery.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __CLOCK_RECOVERY_H__ -#define __CLOCK_RECOVERY_H__ - -#include <stdint.h> -#include <common_time/ICommonClock.h> -#include <utils/LinearTransform.h> -#include <utils/threads.h> - -#ifdef TIME_SERVICE_DEBUG -#include "diag_thread.h" -#endif - -#include "utils.h" - -namespace android { - -class CommonClock; -class LocalClock; - -class ClockRecoveryLoop { - public: - ClockRecoveryLoop(LocalClock* local_clock, CommonClock* common_clock); - ~ClockRecoveryLoop(); - - void reset(bool position, bool frequency); - bool pushDisciplineEvent(int64_t local_time, - int64_t nominal_common_time, - int64_t data_point_rtt); - int32_t getLastErrorEstimate(); - - // Applies the next step in any ongoing slew change operation. Returns a - // timeout suitable for use with poll/select indicating the number of mSec - // until the next change should be applied. - int applyRateLimitedSlew(); - - private: - - // Tuned using the "Good Gain" method. - // See: - // http://techteach.no/publications/books/dynamics_and_control/tuning_pid_controller.pdf - - // Controller period (1Hz for now). - static const float dT; - - // Controller gain, positive and unitless. Larger values converge faster, - // but can cause instability. - static const float Kc; - - // Integral reset time. Smaller values cause loop to track faster, but can - // also cause instability. - static const float Ti; - - // Controller output filter time constant. Range (0-1). Smaller values make - // output smoother, but slow convergence. - static const float Tf; - - // Low-pass filter for bias tracker. - static const float bias_Fc; // HZ - static const float bias_RC; // Computed in constructor. - static const float bias_Alpha; // Computed inconstructor. - - // The maximum allowed error (as indicated by a pushDisciplineEvent) before - // we panic. - static const int64_t panic_thresh_; - - // The maximum allowed error rtt time for packets to be used for control - // feedback, unless the packet is the best in recent memory. - static const int64_t control_thresh_; - - typedef struct { - int64_t local_time; - int64_t observed_common_time; - int64_t nominal_common_time; - int64_t rtt; - bool point_used; - } DisciplineDataPoint; - - static uint32_t findMinRTTNdx(DisciplineDataPoint* data, uint32_t count); - - void reset_l(bool position, bool frequency); - void setTargetCorrection_l(int32_t tgt); - bool applySlew_l(); - - // The local clock HW abstraction we use as the basis for common time. - LocalClock* local_clock_; - bool local_clock_can_slew_; - - // The common clock we end up controlling along with the lock used to - // serialize operations. - CommonClock* common_clock_; - Mutex lock_; - - // parameters maintained while running and reset during a reset - // of the frequency correction. - bool last_error_est_valid_; - int32_t last_error_est_usec_; - float last_delta_f_; - int32_t integrated_error_; - int32_t tgt_correction_; - int32_t cur_correction_; - LinearTransform time_to_cur_slew_; - int64_t slew_change_end_time_; - Timeout next_slew_change_timeout_; - - // Contoller Output. - float CO; - - // Bias tracking for trajectory estimation. - float CObias; - float lastCObias; - - // Controller output bounds. The controller will not try to - // slew faster that +/-100ppm offset from center per interation. - static const float COmin; - static const float COmax; - - // State kept for filtering the discipline data. - static const uint32_t kFilterSize = 16; - DisciplineDataPoint filter_data_[kFilterSize]; - uint32_t filter_wr_; - bool filter_full_; - - static const uint32_t kStartupFilterSize = 4; - DisciplineDataPoint startup_filter_data_[kStartupFilterSize]; - uint32_t startup_filter_wr_; - - // Minimum number of milliseconds over which we allow a full range change - // (from rail to rail) of the VCXO control signal. This is the rate - // limiting factor which keeps us from changing the clock rate so fast that - // we get in trouble with certain HDMI sinks. - static const uint32_t kMinFullRangeSlewChange_mSec; - - // How much time (in msec) to wait - static const int kSlewChangeStepPeriod_mSec; - -#ifdef TIME_SERVICE_DEBUG - sp<DiagThread> diag_thread_; -#endif -}; - -} // namespace android - -#endif // __CLOCK_RECOVERY_H__ diff --git a/services/common_time/common_clock.cpp b/services/common_time/common_clock.cpp deleted file mode 100644 index c9eb388..0000000 --- a/services/common_time/common_clock.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#define __STDC_LIMIT_MACROS - -#define LOG_TAG "common_time" -#include <utils/Log.h> - -#include <stdint.h> - -#include <utils/Errors.h> -#include <utils/LinearTransform.h> - -#include "common_clock.h" - -namespace android { - -CommonClock::CommonClock() { - cur_slew_ = 0; - cur_trans_valid_ = false; - - cur_trans_.a_zero = 0; - cur_trans_.b_zero = 0; - cur_trans_.a_to_b_numer = local_to_common_freq_numer_ = 1; - cur_trans_.a_to_b_denom = local_to_common_freq_denom_ = 1; - duration_trans_ = cur_trans_; -} - -bool CommonClock::init(uint64_t local_freq) { - Mutex::Autolock lock(&lock_); - - if (!local_freq) - return false; - - uint64_t numer = kCommonFreq; - uint64_t denom = local_freq; - - LinearTransform::reduce(&numer, &denom); - if ((numer > UINT32_MAX) || (denom > UINT32_MAX)) { - ALOGE("Overflow in CommonClock::init while trying to reduce %lld/%lld", - kCommonFreq, local_freq); - return false; - } - - cur_trans_.a_to_b_numer = local_to_common_freq_numer_ = - static_cast<uint32_t>(numer); - cur_trans_.a_to_b_denom = local_to_common_freq_denom_ = - static_cast<uint32_t>(denom); - duration_trans_ = cur_trans_; - - return true; -} - -status_t CommonClock::localToCommon(int64_t local, int64_t *common_out) const { - Mutex::Autolock lock(&lock_); - - if (!cur_trans_valid_) - return INVALID_OPERATION; - - if (!cur_trans_.doForwardTransform(local, common_out)) - return INVALID_OPERATION; - - return OK; -} - -status_t CommonClock::commonToLocal(int64_t common, int64_t *local_out) const { - Mutex::Autolock lock(&lock_); - - if (!cur_trans_valid_) - return INVALID_OPERATION; - - if (!cur_trans_.doReverseTransform(common, local_out)) - return INVALID_OPERATION; - - return OK; -} - -int64_t CommonClock::localDurationToCommonDuration(int64_t localDur) const { - int64_t ret; - duration_trans_.doForwardTransform(localDur, &ret); - return ret; -} - -void CommonClock::setBasis(int64_t local, int64_t common) { - Mutex::Autolock lock(&lock_); - - cur_trans_.a_zero = local; - cur_trans_.b_zero = common; - cur_trans_valid_ = true; -} - -void CommonClock::resetBasis() { - Mutex::Autolock lock(&lock_); - - cur_trans_.a_zero = 0; - cur_trans_.b_zero = 0; - cur_trans_valid_ = false; -} - -status_t CommonClock::setSlew(int64_t change_time, int32_t ppm) { - Mutex::Autolock lock(&lock_); - - int64_t new_local_basis; - int64_t new_common_basis; - - if (cur_trans_valid_) { - new_local_basis = change_time; - if (!cur_trans_.doForwardTransform(change_time, &new_common_basis)) { - ALOGE("Overflow when attempting to set slew rate to %d", ppm); - return INVALID_OPERATION; - } - } else { - new_local_basis = 0; - new_common_basis = 0; - } - - cur_slew_ = ppm; - uint32_t n1 = local_to_common_freq_numer_; - uint32_t n2 = 1000000 + cur_slew_; - - uint32_t d1 = local_to_common_freq_denom_; - uint32_t d2 = 1000000; - - // n1/d1 has already been reduced, no need to do so here. - LinearTransform::reduce(&n1, &d2); - LinearTransform::reduce(&n2, &d1); - LinearTransform::reduce(&n2, &d2); - - cur_trans_.a_zero = new_local_basis; - cur_trans_.b_zero = new_common_basis; - cur_trans_.a_to_b_numer = n1 * n2; - cur_trans_.a_to_b_denom = d1 * d2; - - return OK; -} - -} // namespace android diff --git a/services/common_time/common_clock.h b/services/common_time/common_clock.h deleted file mode 100644 index b786fdc..0000000 --- a/services/common_time/common_clock.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#ifndef __COMMON_CLOCK_H__ -#define __COMMON_CLOCK_H__ - -#include <stdint.h> - -#include <utils/Errors.h> -#include <utils/LinearTransform.h> -#include <utils/threads.h> - -namespace android { - -class CommonClock { - public: - CommonClock(); - - bool init(uint64_t local_freq); - - status_t localToCommon(int64_t local, int64_t *common_out) const; - status_t commonToLocal(int64_t common, int64_t *local_out) const; - int64_t localDurationToCommonDuration(int64_t localDur) const; - uint64_t getCommonFreq() const { return kCommonFreq; } - bool isValid() const { return cur_trans_valid_; } - status_t setSlew(int64_t change_time, int32_t ppm); - void setBasis(int64_t local, int64_t common); - void resetBasis(); - private: - mutable Mutex lock_; - - int32_t cur_slew_; - uint32_t local_to_common_freq_numer_; - uint32_t local_to_common_freq_denom_; - - LinearTransform duration_trans_; - LinearTransform cur_trans_; - bool cur_trans_valid_; - - static const uint64_t kCommonFreq = 1000000ull; -}; - -} // namespace android -#endif // __COMMON_CLOCK_H__ diff --git a/services/common_time/common_clock_service.cpp b/services/common_time/common_clock_service.cpp deleted file mode 100644 index 9ca6f35..0000000 --- a/services/common_time/common_clock_service.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2011 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 <common_time/local_clock.h> -#include <utils/String8.h> - -#include "common_clock_service.h" -#include "common_clock.h" -#include "common_time_server.h" - -namespace android { - -sp<CommonClockService> CommonClockService::instantiate( - CommonTimeServer& timeServer) { - sp<CommonClockService> tcc = new CommonClockService(timeServer); - if (tcc == NULL) - return NULL; - - defaultServiceManager()->addService(ICommonClock::kServiceName, tcc); - return tcc; -} - -status_t CommonClockService::dump(int fd, const Vector<String16>& args) { - Mutex::Autolock lock(mRegistrationLock); - return mTimeServer.dumpClockInterface(fd, args, mListeners.size()); -} - -status_t CommonClockService::isCommonTimeValid(bool* valid, - uint32_t* timelineID) { - return mTimeServer.isCommonTimeValid(valid, timelineID); -} - -status_t CommonClockService::commonTimeToLocalTime(int64_t commonTime, - int64_t* localTime) { - return mTimeServer.getCommonClock().commonToLocal(commonTime, localTime); -} - -status_t CommonClockService::localTimeToCommonTime(int64_t localTime, - int64_t* commonTime) { - return mTimeServer.getCommonClock().localToCommon(localTime, commonTime); -} - -status_t CommonClockService::getCommonTime(int64_t* commonTime) { - return localTimeToCommonTime(mTimeServer.getLocalClock().getLocalTime(), commonTime); -} - -status_t CommonClockService::getCommonFreq(uint64_t* freq) { - *freq = mTimeServer.getCommonClock().getCommonFreq(); - return OK; -} - -status_t CommonClockService::getLocalTime(int64_t* localTime) { - *localTime = mTimeServer.getLocalClock().getLocalTime(); - return OK; -} - -status_t CommonClockService::getLocalFreq(uint64_t* freq) { - *freq = mTimeServer.getLocalClock().getLocalFreq(); - return OK; -} - -status_t CommonClockService::getEstimatedError(int32_t* estimate) { - *estimate = mTimeServer.getEstimatedError(); - return OK; -} - -status_t CommonClockService::getTimelineID(uint64_t* id) { - *id = mTimeServer.getTimelineID(); - return OK; -} - -status_t CommonClockService::getState(State* state) { - *state = mTimeServer.getState(); - return OK; -} - -status_t CommonClockService::getMasterAddr(struct sockaddr_storage* addr) { - return mTimeServer.getMasterAddr(addr); -} - -status_t CommonClockService::registerListener( - const sp<ICommonClockListener>& listener) { - Mutex::Autolock lock(mRegistrationLock); - - { // scoping for autolock pattern - Mutex::Autolock lock(mCallbackLock); - // check whether this is a duplicate - for (size_t i = 0; i < mListeners.size(); i++) { - if (mListeners[i]->asBinder() == listener->asBinder()) - return ALREADY_EXISTS; - } - } - - mListeners.add(listener); - mTimeServer.reevaluateAutoDisableState(0 != mListeners.size()); - return listener->asBinder()->linkToDeath(this); -} - -status_t CommonClockService::unregisterListener( - const sp<ICommonClockListener>& listener) { - Mutex::Autolock lock(mRegistrationLock); - status_t ret_val = NAME_NOT_FOUND; - - { // scoping for autolock pattern - Mutex::Autolock lock(mCallbackLock); - for (size_t i = 0; i < mListeners.size(); i++) { - if (mListeners[i]->asBinder() == listener->asBinder()) { - mListeners[i]->asBinder()->unlinkToDeath(this); - mListeners.removeAt(i); - ret_val = OK; - break; - } - } - } - - mTimeServer.reevaluateAutoDisableState(0 != mListeners.size()); - return ret_val; -} - -void CommonClockService::binderDied(const wp<IBinder>& who) { - Mutex::Autolock lock(mRegistrationLock); - - { // scoping for autolock pattern - Mutex::Autolock lock(mCallbackLock); - for (size_t i = 0; i < mListeners.size(); i++) { - if (mListeners[i]->asBinder() == who) { - mListeners.removeAt(i); - break; - } - } - } - - mTimeServer.reevaluateAutoDisableState(0 != mListeners.size()); -} - -void CommonClockService::notifyOnTimelineChanged(uint64_t timelineID) { - Mutex::Autolock lock(mCallbackLock); - - for (size_t i = 0; i < mListeners.size(); i++) { - mListeners[i]->onTimelineChanged(timelineID); - } -} - -}; // namespace android diff --git a/services/common_time/common_clock_service.h b/services/common_time/common_clock_service.h deleted file mode 100644 index bd663f0..0000000 --- a/services/common_time/common_clock_service.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_COMMON_CLOCK_SERVICE_H -#define ANDROID_COMMON_CLOCK_SERVICE_H - -#include <sys/socket.h> -#include <common_time/ICommonClock.h> - -namespace android { - -class CommonTimeServer; - -class CommonClockService : public BnCommonClock, - public android::IBinder::DeathRecipient { - public: - static sp<CommonClockService> instantiate(CommonTimeServer& timeServer); - - virtual status_t dump(int fd, const Vector<String16>& args); - - virtual status_t isCommonTimeValid(bool* valid, uint32_t *timelineID); - virtual status_t commonTimeToLocalTime(int64_t common_time, - int64_t* local_time); - virtual status_t localTimeToCommonTime(int64_t local_time, - int64_t* common_time); - virtual status_t getCommonTime(int64_t* common_time); - virtual status_t getCommonFreq(uint64_t* freq); - virtual status_t getLocalTime(int64_t* local_time); - virtual status_t getLocalFreq(uint64_t* freq); - virtual status_t getEstimatedError(int32_t* estimate); - virtual status_t getTimelineID(uint64_t* id); - virtual status_t getState(ICommonClock::State* state); - virtual status_t getMasterAddr(struct sockaddr_storage* addr); - - virtual status_t registerListener( - const sp<ICommonClockListener>& listener); - virtual status_t unregisterListener( - const sp<ICommonClockListener>& listener); - - void notifyOnTimelineChanged(uint64_t timelineID); - - private: - CommonClockService(CommonTimeServer& timeServer) - : mTimeServer(timeServer) { }; - - virtual void binderDied(const wp<IBinder>& who); - - CommonTimeServer& mTimeServer; - - // locks used to synchronize access to the list of registered listeners. - // The callback lock is held whenever the list is used to perform callbacks - // or while the list is being modified. The registration lock used to - // serialize access across registerListener, unregisterListener, and - // binderDied. - // - // The reason for two locks is that registerListener, unregisterListener, - // and binderDied each call into the core service and obtain the core - // service thread lock when they call reevaluateAutoDisableState. The core - // service thread obtains the main thread lock whenever its thread is - // running, and sometimes needs to call notifyOnTimelineChanged which then - // obtains the callback lock. If callers of registration functions were - // holding the callback lock when they called into the core service, we - // would have a classic A/B, B/A ordering deadlock. To avoid this, the - // registration functions hold the registration lock for the duration of - // their call, but hold the callback lock only while they mutate the list. - // This way, the list's size cannot change (because of the registration - // lock) during the call into reevaluateAutoDisableState, but the core work - // thread can still safely call notifyOnTimelineChanged while holding the - // main thread lock. - Mutex mCallbackLock; - Mutex mRegistrationLock; - - Vector<sp<ICommonClockListener> > mListeners; -}; - -}; // namespace android - -#endif // ANDROID_COMMON_CLOCK_SERVICE_H diff --git a/services/common_time/common_time_config_service.cpp b/services/common_time/common_time_config_service.cpp deleted file mode 100644 index 9585618..0000000 --- a/services/common_time/common_time_config_service.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#include <utils/String8.h> - -#include "common_time_config_service.h" -#include "common_time_server.h" - -namespace android { - -sp<CommonTimeConfigService> CommonTimeConfigService::instantiate( - CommonTimeServer& timeServer) { - sp<CommonTimeConfigService> ctcs = new CommonTimeConfigService(timeServer); - if (ctcs == NULL) - return NULL; - - defaultServiceManager()->addService(ICommonTimeConfig::kServiceName, ctcs); - return ctcs; -} - -status_t CommonTimeConfigService::dump(int fd, const Vector<String16>& args) { - return mTimeServer.dumpConfigInterface(fd, args); -} - -status_t CommonTimeConfigService::getMasterElectionPriority(uint8_t *priority) { - return mTimeServer.getMasterElectionPriority(priority); -} - -status_t CommonTimeConfigService::setMasterElectionPriority(uint8_t priority) { - return mTimeServer.setMasterElectionPriority(priority); -} - -status_t CommonTimeConfigService::getMasterElectionEndpoint( - struct sockaddr_storage *addr) { - return mTimeServer.getMasterElectionEndpoint(addr); -} - -status_t CommonTimeConfigService::setMasterElectionEndpoint( - const struct sockaddr_storage *addr) { - return mTimeServer.setMasterElectionEndpoint(addr); -} - -status_t CommonTimeConfigService::getMasterElectionGroupId(uint64_t *id) { - return mTimeServer.getMasterElectionGroupId(id); -} - -status_t CommonTimeConfigService::setMasterElectionGroupId(uint64_t id) { - return mTimeServer.setMasterElectionGroupId(id); -} - -status_t CommonTimeConfigService::getInterfaceBinding(String16& ifaceName) { - String8 tmp; - status_t ret = mTimeServer.getInterfaceBinding(tmp); - ifaceName = String16(tmp); - return ret; -} - -status_t CommonTimeConfigService::setInterfaceBinding(const String16& ifaceName) { - String8 tmp(ifaceName); - return mTimeServer.setInterfaceBinding(tmp); -} - -status_t CommonTimeConfigService::getMasterAnnounceInterval(int *interval) { - return mTimeServer.getMasterAnnounceInterval(interval); -} - -status_t CommonTimeConfigService::setMasterAnnounceInterval(int interval) { - return mTimeServer.setMasterAnnounceInterval(interval); -} - -status_t CommonTimeConfigService::getClientSyncInterval(int *interval) { - return mTimeServer.getClientSyncInterval(interval); -} - -status_t CommonTimeConfigService::setClientSyncInterval(int interval) { - return mTimeServer.setClientSyncInterval(interval); -} - -status_t CommonTimeConfigService::getPanicThreshold(int *threshold) { - return mTimeServer.getPanicThreshold(threshold); -} - -status_t CommonTimeConfigService::setPanicThreshold(int threshold) { - return mTimeServer.setPanicThreshold(threshold); -} - -status_t CommonTimeConfigService::getAutoDisable(bool *autoDisable) { - return mTimeServer.getAutoDisable(autoDisable); -} - -status_t CommonTimeConfigService::setAutoDisable(bool autoDisable) { - return mTimeServer.setAutoDisable(autoDisable); -} - -status_t CommonTimeConfigService::forceNetworklessMasterMode() { - return mTimeServer.forceNetworklessMasterMode(); -} - -}; // namespace android diff --git a/services/common_time/common_time_config_service.h b/services/common_time/common_time_config_service.h deleted file mode 100644 index 89806dd..0000000 --- a/services/common_time/common_time_config_service.h +++ /dev/null @@ -1,60 +0,0 @@ -/* * Copyright (C) 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. - */ - -#ifndef ANDROID_COMMON_TIME_CONFIG_SERVICE_H -#define ANDROID_COMMON_TIME_CONFIG_SERVICE_H - -#include <sys/socket.h> -#include <common_time/ICommonTimeConfig.h> - -namespace android { - -class String16; -class CommonTimeServer; - -class CommonTimeConfigService : public BnCommonTimeConfig { - public: - static sp<CommonTimeConfigService> instantiate(CommonTimeServer& timeServer); - - virtual status_t dump(int fd, const Vector<String16>& args); - - virtual status_t getMasterElectionPriority(uint8_t *priority); - virtual status_t setMasterElectionPriority(uint8_t priority); - virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr); - virtual status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr); - virtual status_t getMasterElectionGroupId(uint64_t *id); - virtual status_t setMasterElectionGroupId(uint64_t id); - virtual status_t getInterfaceBinding(String16& ifaceName); - virtual status_t setInterfaceBinding(const String16& ifaceName); - virtual status_t getMasterAnnounceInterval(int *interval); - virtual status_t setMasterAnnounceInterval(int interval); - virtual status_t getClientSyncInterval(int *interval); - virtual status_t setClientSyncInterval(int interval); - virtual status_t getPanicThreshold(int *threshold); - virtual status_t setPanicThreshold(int threshold); - virtual status_t getAutoDisable(bool *autoDisable); - virtual status_t setAutoDisable(bool autoDisable); - virtual status_t forceNetworklessMasterMode(); - - private: - CommonTimeConfigService(CommonTimeServer& timeServer) - : mTimeServer(timeServer) { } - CommonTimeServer& mTimeServer; - -}; - -}; // namespace android - -#endif // ANDROID_COMMON_TIME_CONFIG_SERVICE_H diff --git a/services/common_time/common_time_server.cpp b/services/common_time/common_time_server.cpp deleted file mode 100644 index 21e706f..0000000 --- a/services/common_time/common_time_server.cpp +++ /dev/null @@ -1,1506 +0,0 @@ -/* - * Copyright (C) 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. - */ - -/* - * A service that exchanges time synchronization information between - * a master that defines a timeline and clients that follow the timeline. - */ - -#define LOG_TAG "common_time" -#include <utils/Log.h> - -#include <arpa/inet.h> -#include <assert.h> -#include <fcntl.h> -#include <linux/if_ether.h> -#include <net/if.h> -#include <net/if_arp.h> -#include <netinet/ip.h> -#include <poll.h> -#include <stdio.h> -#include <sys/eventfd.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/socket.h> - -#include <common_time/local_clock.h> -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <utils/Timers.h> - -#include "common_clock_service.h" -#include "common_time_config_service.h" -#include "common_time_server.h" -#include "common_time_server_packets.h" -#include "clock_recovery.h" -#include "common_clock.h" - -#define MAX_INT ((int)0x7FFFFFFF) - -namespace android { - -const char* CommonTimeServer::kDefaultMasterElectionAddr = "255.255.255.255"; -const uint16_t CommonTimeServer::kDefaultMasterElectionPort = 8886; -const uint64_t CommonTimeServer::kDefaultSyncGroupID = 1; -const uint8_t CommonTimeServer::kDefaultMasterPriority = 1; -const uint32_t CommonTimeServer::kDefaultMasterAnnounceIntervalMs = 10000; -const uint32_t CommonTimeServer::kDefaultSyncRequestIntervalMs = 1000; -const uint32_t CommonTimeServer::kDefaultPanicThresholdUsec = 50000; -const bool CommonTimeServer::kDefaultAutoDisable = true; -const int CommonTimeServer::kSetupRetryTimeoutMs = 30000; -const int64_t CommonTimeServer::kNoGoodDataPanicThresholdUsec = 600000000ll; -const uint32_t CommonTimeServer::kRTTDiscardPanicThreshMultiplier = 5; - -// timeout value representing an infinite timeout -const int CommonTimeServer::kInfiniteTimeout = -1; - -/*** Initial state constants ***/ - -// number of WhoIsMaster attempts sent before giving up -const int CommonTimeServer::kInitial_NumWhoIsMasterRetries = 6; - -// timeout used when waiting for a response to a WhoIsMaster request -const int CommonTimeServer::kInitial_WhoIsMasterTimeoutMs = 500; - -/*** Client state constants ***/ - -// number of sync requests that can fail before a client assumes its master -// is dead -const int CommonTimeServer::kClient_NumSyncRequestRetries = 10; - -/*** Master state constants ***/ - -/*** Ronin state constants ***/ - -// number of WhoIsMaster attempts sent before declaring ourselves master -const int CommonTimeServer::kRonin_NumWhoIsMasterRetries = 20; - -// timeout used when waiting for a response to a WhoIsMaster request -const int CommonTimeServer::kRonin_WhoIsMasterTimeoutMs = 500; - -/*** WaitForElection state constants ***/ - -// how long do we wait for an announcement from a master before -// trying another election? -const int CommonTimeServer::kWaitForElection_TimeoutMs = 12500; - -CommonTimeServer::CommonTimeServer() - : Thread(false) - , mState(ICommonClock::STATE_INITIAL) - , mClockRecovery(&mLocalClock, &mCommonClock) - , mSocket(-1) - , mLastPacketRxLocalTime(0) - , mTimelineID(ICommonClock::kInvalidTimelineID) - , mClockSynced(false) - , mCommonClockHasClients(false) - , mStateChangeLog("Recent State Change Events", 30) - , mElectionLog("Recent Master Election Traffic", 30) - , mBadPktLog("Recent Bad Packet RX Info", 8) - , mInitial_WhoIsMasterRequestTimeouts(0) - , mClient_MasterDeviceID(0) - , mClient_MasterDevicePriority(0) - , mRonin_WhoIsMasterRequestTimeouts(0) { - // zero out sync stats - resetSyncStats(); - - // Setup the master election endpoint to use the default. - struct sockaddr_in* meep = - reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP); - memset(&mMasterElectionEP, 0, sizeof(mMasterElectionEP)); - inet_aton(kDefaultMasterElectionAddr, &meep->sin_addr); - meep->sin_family = AF_INET; - meep->sin_port = htons(kDefaultMasterElectionPort); - - // Zero out the master endpoint. - memset(&mMasterEP, 0, sizeof(mMasterEP)); - mMasterEPValid = false; - mBindIfaceValid = false; - setForceLowPriority(false); - - // Set all remaining configuration parameters to their defaults. - mDeviceID = 0; - mSyncGroupID = kDefaultSyncGroupID; - mMasterPriority = kDefaultMasterPriority; - mMasterAnnounceIntervalMs = kDefaultMasterAnnounceIntervalMs; - mSyncRequestIntervalMs = kDefaultSyncRequestIntervalMs; - mPanicThresholdUsec = kDefaultPanicThresholdUsec; - mAutoDisable = kDefaultAutoDisable; - - // Create the eventfd we will use to signal our thread to wake up when - // needed. - mWakeupThreadFD = eventfd(0, EFD_NONBLOCK); - - // seed the random number generator (used to generated timeline IDs) - srand48(static_cast<unsigned int>(systemTime())); -} - -CommonTimeServer::~CommonTimeServer() { - shutdownThread(); - - // No need to grab the lock here. We are in the destructor; if the the user - // has a thread in any of the APIs while the destructor is being called, - // there is a threading problem a the application level we cannot reasonably - // do anything about. - cleanupSocket_l(); - - if (mWakeupThreadFD >= 0) { - close(mWakeupThreadFD); - mWakeupThreadFD = -1; - } -} - -bool CommonTimeServer::startServices() { - // start the ICommonClock service - mICommonClock = CommonClockService::instantiate(*this); - if (mICommonClock == NULL) - return false; - - // start the ICommonTimeConfig service - mICommonTimeConfig = CommonTimeConfigService::instantiate(*this); - if (mICommonTimeConfig == NULL) - return false; - - return true; -} - -bool CommonTimeServer::threadLoop() { - // Register our service interfaces. - if (!startServices()) - return false; - - // Hold the lock while we are in the main thread loop. It will release the - // lock when it blocks, and hold the lock at all other times. - mLock.lock(); - runStateMachine_l(); - mLock.unlock(); - - IPCThreadState::self()->stopProcess(); - return false; -} - -bool CommonTimeServer::runStateMachine_l() { - if (!mLocalClock.initCheck()) - return false; - - if (!mCommonClock.init(mLocalClock.getLocalFreq())) - return false; - - // Enter the initial state. - becomeInitial("startup"); - - // run the state machine - while (!exitPending()) { - struct pollfd pfds[2]; - int rc, timeout; - int eventCnt = 0; - int64_t wakeupTime; - uint32_t t1, t2; - bool needHandleTimeout = false; - - // We are always interested in our wakeup FD. - pfds[eventCnt].fd = mWakeupThreadFD; - pfds[eventCnt].events = POLLIN; - pfds[eventCnt].revents = 0; - eventCnt++; - - // If we have a valid socket, then we are interested in what it has to - // say as well. - if (mSocket >= 0) { - pfds[eventCnt].fd = mSocket; - pfds[eventCnt].events = POLLIN; - pfds[eventCnt].revents = 0; - eventCnt++; - } - - t1 = static_cast<uint32_t>(mCurTimeout.msecTillTimeout()); - t2 = static_cast<uint32_t>(mClockRecovery.applyRateLimitedSlew()); - timeout = static_cast<int>(t1 < t2 ? t1 : t2); - - // Note, we were holding mLock when this function was called. We - // release it only while we are blocking and hold it at all other times. - mLock.unlock(); - rc = poll(pfds, eventCnt, timeout); - wakeupTime = mLocalClock.getLocalTime(); - mLock.lock(); - - // Is it time to shutdown? If so, don't hesitate... just do it. - if (exitPending()) - break; - - // Did the poll fail? This should never happen and is fatal if it does. - if (rc < 0) { - ALOGE("%s:%d poll failed", __PRETTY_FUNCTION__, __LINE__); - return false; - } - - if (rc == 0) { - needHandleTimeout = !mCurTimeout.msecTillTimeout(); - if (needHandleTimeout) - mCurTimeout.setTimeout(kInfiniteTimeout); - } - - // Were we woken up on purpose? If so, clear the eventfd with a read. - if (pfds[0].revents) - clearPendingWakeupEvents_l(); - - // Is out bind address dirty? If so, clean up our socket (if any). - // Alternatively, do we have an active socket but should be auto - // disabled? If so, release the socket and enter the proper sync state. - bool droppedSocket = false; - if (mBindIfaceDirty || ((mSocket >= 0) && shouldAutoDisable())) { - cleanupSocket_l(); - mBindIfaceDirty = false; - droppedSocket = true; - } - - // Do we not have a socket but should have one? If so, try to set one - // up. - if ((mSocket < 0) && mBindIfaceValid && !shouldAutoDisable()) { - if (setupSocket_l()) { - // Success! We are now joining a new network (either coming - // from no network, or coming from a potentially different - // network). Force our priority to be lower so that we defer to - // any other masters which may already be on the network we are - // joining. Later, when we enter either the client or the - // master state, we will clear this flag and go back to our - // normal election priority. - setForceLowPriority(true); - switch (mState) { - // If we were in initial (whether we had a immediately - // before this network or not) we want to simply reset the - // system and start again. Forcing a transition from - // INITIAL to INITIAL should do the job. - case CommonClockService::STATE_INITIAL: - becomeInitial("bound interface"); - break; - - // If we were in the master state, then either we were the - // master in a no-network situation, or we were the master - // of a different network and have moved to a new interface. - // In either case, immediately transition to Ronin at low - // priority. If there is no one in the network we just - // joined, we will become master soon enough. If there is, - // we want to be certain to defer master status to the - // existing timeline currently running on the network. - // - case CommonClockService::STATE_MASTER: - becomeRonin("leaving networkless mode"); - break; - - // If we were in any other state (CLIENT, RONIN, or - // WAIT_FOR_ELECTION) then we must be moving from one - // network to another. We have lost our old master; - // transition to RONIN in an attempt to find a new master. - // If there are none out there, we will just assume - // responsibility for the timeline we used to be a client - // of. - default: - becomeRonin("bound interface"); - break; - } - } else { - // That's odd... we failed to set up our socket. This could be - // due to some transient network change which will work itself - // out shortly; schedule a retry attempt in the near future. - mCurTimeout.setTimeout(kSetupRetryTimeoutMs); - } - - // One way or the other, we don't have any data to process at this - // point (since we just tried to bulid a new socket). Loop back - // around and wait for the next thing to do. - continue; - } else if (droppedSocket) { - // We just lost our socket, and for whatever reason (either no - // config, or auto disable engaged) we are not supposed to rebuild - // one at this time. We are not going to rebuild our socket until - // something about our config/auto-disabled status changes, so we - // are basically in network-less mode. If we are already in either - // INITIAL or MASTER, just stay there until something changes. If - // we are in any other state (CLIENT, RONIN or WAIT_FOR_ELECTION), - // then transition to either INITIAL or MASTER depending on whether - // or not our timeline is valid. - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "Entering networkless mode interface is %s, " - "shouldAutoDisable = %s", - mBindIfaceValid ? "valid" : "invalid", - shouldAutoDisable() ? "true" : "false"); - if ((mState != ICommonClock::STATE_INITIAL) && - (mState != ICommonClock::STATE_MASTER)) { - if (mTimelineID == ICommonClock::kInvalidTimelineID) - becomeInitial("network-less mode"); - else - becomeMaster("network-less mode"); - } - - continue; - } - - // Time to handle the timeouts? - if (needHandleTimeout) { - if (!handleTimeout()) - ALOGE("handleTimeout failed"); - continue; - } - - // Does our socket have data for us (assuming we still have one, we - // may have RXed a packet at the same time as a config change telling us - // to shut our socket down)? If so, process its data. - if ((mSocket >= 0) && (eventCnt > 1) && (pfds[1].revents)) { - mLastPacketRxLocalTime = wakeupTime; - if (!handlePacket()) - ALOGE("handlePacket failed"); - } - } - - cleanupSocket_l(); - return true; -} - -void CommonTimeServer::clearPendingWakeupEvents_l() { - int64_t tmp; - read(mWakeupThreadFD, &tmp, sizeof(tmp)); -} - -void CommonTimeServer::wakeupThread_l() { - int64_t tmp = 1; - write(mWakeupThreadFD, &tmp, sizeof(tmp)); -} - -void CommonTimeServer::cleanupSocket_l() { - if (mSocket >= 0) { - close(mSocket); - mSocket = -1; - } -} - -void CommonTimeServer::shutdownThread() { - // Flag the work thread for shutdown. - this->requestExit(); - - // Signal the thread in case its sleeping. - mLock.lock(); - wakeupThread_l(); - mLock.unlock(); - - // Wait for the thread to exit. - this->join(); -} - -bool CommonTimeServer::setupSocket_l() { - int rc; - bool ret_val = false; - struct sockaddr_in* ipv4_addr = NULL; - char masterElectionEPStr[64]; - const int one = 1; - - // This should never be needed, but if we happened to have an old socket - // lying around, be sure to not leak it before proceeding. - cleanupSocket_l(); - - // If we don't have a valid endpoint to bind to, then how did we get here in - // the first place? Regardless, we know that we are going to fail to bind, - // so don't even try. - if (!mBindIfaceValid) - return false; - - sockaddrToString(mMasterElectionEP, true, masterElectionEPStr, - sizeof(masterElectionEPStr)); - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "Building socket :: bind = %s master election = %s", - mBindIface.string(), masterElectionEPStr); - - // TODO: add proper support for IPv6. Right now, we block IPv6 addresses at - // the configuration interface level. - if (AF_INET != mMasterElectionEP.ss_family) { - mStateChangeLog.log(ANDROID_LOG_WARN, LOG_TAG, - "TODO: add proper IPv6 support"); - goto bailout; - } - - // open a UDP socket for the timeline serivce - mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (mSocket < 0) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to create socket (errno = %d)", errno); - goto bailout; - } - - // Bind to the selected interface using Linux's spiffy SO_BINDTODEVICE. - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", mBindIface.string()); - ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0; - rc = setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, - (void *)&ifr, sizeof(ifr)); - if (rc) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to bind socket at to interface %s " - "(errno = %d)", ifr.ifr_name, errno); - goto bailout; - } - - // Bind our socket to INADDR_ANY and the master election port. The - // interface binding we made using SO_BINDTODEVICE should limit us to - // traffic only on the interface we are interested in. We need to bind to - // INADDR_ANY and the specific master election port in order to be able to - // receive both unicast traffic and master election multicast traffic with - // just a single socket. - struct sockaddr_in bindAddr; - ipv4_addr = reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP); - memcpy(&bindAddr, ipv4_addr, sizeof(bindAddr)); - bindAddr.sin_addr.s_addr = INADDR_ANY; - rc = bind(mSocket, - reinterpret_cast<const sockaddr *>(&bindAddr), - sizeof(bindAddr)); - if (rc) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to bind socket to port %hu (errno = %d)", - ntohs(bindAddr.sin_port), errno); - goto bailout; - } - - if (0xE0000000 == (ntohl(ipv4_addr->sin_addr.s_addr) & 0xF0000000)) { - // If our master election endpoint is a multicast address, be sure to join - // the multicast group. - struct ip_mreq mreq; - mreq.imr_multiaddr = ipv4_addr->sin_addr; - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - rc = setsockopt(mSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &mreq, sizeof(mreq)); - if (rc == -1) { - ALOGE("Failed to join multicast group at %s. (errno = %d)", - masterElectionEPStr, errno); - goto bailout; - } - - // disable loopback of multicast packets - const int zero = 0; - rc = setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_LOOP, - &zero, sizeof(zero)); - if (rc == -1) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to disable multicast loopback " - "(errno = %d)", errno); - goto bailout; - } - } else - if (ntohl(ipv4_addr->sin_addr.s_addr) == 0xFFFFFFFF) { - // If the master election address is the broadcast address, then enable - // the broadcast socket option - rc = setsockopt(mSocket, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)); - if (rc == -1) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to enable broadcast (errno = %d)", - errno); - goto bailout; - } - } else { - // If the master election address is neither broadcast, nor multicast, - // then we are misconfigured. The config API layer should prevent this - // from ever happening. - goto bailout; - } - - // Set the TTL of sent packets to 1. (Time protocol sync should never leave - // the local subnet) - rc = setsockopt(mSocket, IPPROTO_IP, IP_TTL, &one, sizeof(one)); - if (rc == -1) { - mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to set TTL to %d (errno = %d)", one, errno); - goto bailout; - } - - // get the device's unique ID - if (!assignDeviceID()) - goto bailout; - - ret_val = true; - -bailout: - if (!ret_val) - cleanupSocket_l(); - return ret_val; -} - -// generate a unique device ID that can be used for arbitration -bool CommonTimeServer::assignDeviceID() { - if (!mBindIfaceValid) - return false; - - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_addr.sa_family = AF_INET; - strlcpy(ifr.ifr_name, mBindIface.string(), IFNAMSIZ); - - int rc = ioctl(mSocket, SIOCGIFHWADDR, &ifr); - if (rc) { - ALOGE("%s:%d ioctl failed", __PRETTY_FUNCTION__, __LINE__); - return false; - } - - if (ifr.ifr_addr.sa_family != ARPHRD_ETHER) { - ALOGE("%s:%d got non-Ethernet address", __PRETTY_FUNCTION__, __LINE__); - return false; - } - - mDeviceID = 0; - for (int i = 0; i < ETH_ALEN; i++) { - mDeviceID = (mDeviceID << 8) | ifr.ifr_hwaddr.sa_data[i]; - } - - return true; -} - -// generate a new timeline ID -void CommonTimeServer::assignTimelineID() { - do { - mTimelineID = (static_cast<uint64_t>(lrand48()) << 32) - | static_cast<uint64_t>(lrand48()); - } while (mTimelineID == ICommonClock::kInvalidTimelineID); -} - -// Select a preference between the device IDs of two potential masters. -// Returns true if the first ID wins, or false if the second ID wins. -bool CommonTimeServer::arbitrateMaster( - uint64_t deviceID1, uint8_t devicePrio1, - uint64_t deviceID2, uint8_t devicePrio2) { - return ((devicePrio1 > devicePrio2) || - ((devicePrio1 == devicePrio2) && (deviceID1 > deviceID2))); -} - -static void hexDumpToString(const uint8_t* src, size_t src_len, - char* dst, size_t dst_len) { - size_t offset = 0; - size_t i; - - for (i = 0; (i < src_len) && (offset < dst_len); ++i) { - int res; - if (0 == (i % 16)) { - res = snprintf(dst + offset, dst_len - offset, "\n%04x :", i); - if (res < 0) - break; - offset += res; - if (offset >= dst_len) - break; - } - - res = snprintf(dst + offset, dst_len - offset, " %02x", src[i]); - if (res < 0) - break; - offset += res; - } - - dst[dst_len - 1] = 0; -} - -bool CommonTimeServer::handlePacket() { - uint8_t buf[256]; - struct sockaddr_storage srcAddr; - socklen_t srcAddrLen = sizeof(srcAddr); - - ssize_t recvBytes = recvfrom( - mSocket, buf, sizeof(buf), 0, - reinterpret_cast<const sockaddr *>(&srcAddr), &srcAddrLen); - - if (recvBytes < 0) { - mBadPktLog.log(ANDROID_LOG_ERROR, LOG_TAG, - "recvfrom failed (res %d, errno %d)", - recvBytes, errno); - return false; - } - - UniversalTimeServicePacket pkt; - if (pkt.deserializePacket(buf, recvBytes, mSyncGroupID) < 0) { - char hex[256]; - char srcEPStr[64]; - - hexDumpToString(buf, static_cast<size_t>(recvBytes), hex, sizeof(hex)); - sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr)); - - mBadPktLog.log("Failed to parse %d byte packet from %s.%s", - recvBytes, srcEPStr, hex); - return false; - } - - bool result; - switch (pkt.packetType) { - case TIME_PACKET_WHO_IS_MASTER_REQUEST: - result = handleWhoIsMasterRequest(&pkt.p.who_is_master_request, - srcAddr); - break; - - case TIME_PACKET_WHO_IS_MASTER_RESPONSE: - result = handleWhoIsMasterResponse(&pkt.p.who_is_master_response, - srcAddr); - break; - - case TIME_PACKET_SYNC_REQUEST: - result = handleSyncRequest(&pkt.p.sync_request, srcAddr); - break; - - case TIME_PACKET_SYNC_RESPONSE: - result = handleSyncResponse(&pkt.p.sync_response, srcAddr); - break; - - case TIME_PACKET_MASTER_ANNOUNCEMENT: - result = handleMasterAnnouncement(&pkt.p.master_announcement, - srcAddr); - break; - - default: { - char srcEPStr[64]; - sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr)); - - mBadPktLog.log(ANDROID_LOG_WARN, LOG_TAG, - "unknown packet type (%d) from %s", - pkt.packetType, srcEPStr); - - result = false; - } break; - } - - return result; -} - -bool CommonTimeServer::handleTimeout() { - // If we have no socket, then this must be a timeout to retry socket setup. - if (mSocket < 0) - return true; - - switch (mState) { - case ICommonClock::STATE_INITIAL: - return handleTimeoutInitial(); - case ICommonClock::STATE_CLIENT: - return handleTimeoutClient(); - case ICommonClock::STATE_MASTER: - return handleTimeoutMaster(); - case ICommonClock::STATE_RONIN: - return handleTimeoutRonin(); - case ICommonClock::STATE_WAIT_FOR_ELECTION: - return handleTimeoutWaitForElection(); - } - - return false; -} - -bool CommonTimeServer::handleTimeoutInitial() { - if (++mInitial_WhoIsMasterRequestTimeouts == - kInitial_NumWhoIsMasterRetries) { - // none of our attempts to discover a master succeeded, so make - // this device the master - return becomeMaster("initial timeout"); - } else { - // retry the WhoIsMaster request - return sendWhoIsMasterRequest(); - } -} - -bool CommonTimeServer::handleTimeoutClient() { - if (shouldPanicNotGettingGoodData()) - return becomeInitial("timeout panic, no good data"); - - if (mClient_SyncRequestPending) { - mClient_SyncRequestPending = false; - - if (++mClient_SyncRequestTimeouts < kClient_NumSyncRequestRetries) { - // a sync request has timed out, so retry - return sendSyncRequest(); - } else { - // The master has failed to respond to a sync request for too many - // times in a row. Assume the master is dead and start electing - // a new master. - return becomeRonin("master not responding"); - } - } else { - // initiate the next sync request - return sendSyncRequest(); - } -} - -bool CommonTimeServer::handleTimeoutMaster() { - // send another announcement from the master - return sendMasterAnnouncement(); -} - -bool CommonTimeServer::handleTimeoutRonin() { - if (++mRonin_WhoIsMasterRequestTimeouts == kRonin_NumWhoIsMasterRetries) { - // no other master is out there, so we won the election - return becomeMaster("no better masters detected"); - } else { - return sendWhoIsMasterRequest(); - } -} - -bool CommonTimeServer::handleTimeoutWaitForElection() { - return becomeRonin("timeout waiting for election conclusion"); -} - -bool CommonTimeServer::handleWhoIsMasterRequest( - const WhoIsMasterRequestPacket* request, - const sockaddr_storage& srcAddr) { - // Skip our own messages which come back via broadcast loopback. - if (request->senderDeviceID == mDeviceID) - return true; - - char srcEPStr[64]; - sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr)); - mElectionLog.log("RXed WhoIs master request while in state %s. " - "src %s reqTID %016llx ourTID %016llx", - stateToString(mState), srcEPStr, - request->timelineID, mTimelineID); - - if (mState == ICommonClock::STATE_MASTER) { - // is this request related to this master's timeline? - if (request->timelineID != ICommonClock::kInvalidTimelineID && - request->timelineID != mTimelineID) - return true; - - WhoIsMasterResponsePacket pkt; - pkt.initHeader(mTimelineID, mSyncGroupID); - pkt.deviceID = mDeviceID; - pkt.devicePriority = effectivePriority(); - - mElectionLog.log("TXing WhoIs master resp to %s while in state %s. " - "ourTID %016llx ourGID %016llx ourDID %016llx " - "ourPrio %u", - srcEPStr, stateToString(mState), - mTimelineID, mSyncGroupID, - pkt.deviceID, pkt.devicePriority); - - uint8_t buf[256]; - ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); - if (bufSz < 0) - return false; - - ssize_t sendBytes = sendto( - mSocket, buf, bufSz, 0, - reinterpret_cast<const sockaddr *>(&srcAddr), - sizeof(srcAddr)); - if (sendBytes == -1) { - ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__); - return false; - } - } else if (mState == ICommonClock::STATE_RONIN) { - // if we hear a WhoIsMaster request from another device following - // the same timeline and that device wins arbitration, then we will stop - // trying to elect ourselves master and will instead wait for an - // announcement from the election winner - if (request->timelineID != mTimelineID) - return true; - - if (arbitrateMaster(request->senderDeviceID, - request->senderDevicePriority, - mDeviceID, - effectivePriority())) - return becomeWaitForElection("would lose election"); - - return true; - } else if (mState == ICommonClock::STATE_INITIAL) { - // If a group of devices booted simultaneously (e.g. after a power - // outage) and all of them are in the initial state and there is no - // master, then each device may time out and declare itself master at - // the same time. To avoid this, listen for - // WhoIsMaster(InvalidTimeline) requests from peers. If we would lose - // arbitration against that peer, reset our timeout count so that the - // peer has a chance to become master before we time out. - if (request->timelineID == ICommonClock::kInvalidTimelineID && - arbitrateMaster(request->senderDeviceID, - request->senderDevicePriority, - mDeviceID, - effectivePriority())) { - mInitial_WhoIsMasterRequestTimeouts = 0; - } - } - - return true; -} - -bool CommonTimeServer::handleWhoIsMasterResponse( - const WhoIsMasterResponsePacket* response, - const sockaddr_storage& srcAddr) { - // Skip our own messages which come back via broadcast loopback. - if (response->deviceID == mDeviceID) - return true; - - char srcEPStr[64]; - sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr)); - mElectionLog.log("RXed WhoIs master response while in state %s. " - "src %s respTID %016llx respDID %016llx respPrio %u " - "ourTID %016llx", - stateToString(mState), srcEPStr, - response->timelineID, - response->deviceID, - static_cast<uint32_t>(response->devicePriority), - mTimelineID); - - if (mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN) { - return becomeClient(srcAddr, - response->deviceID, - response->devicePriority, - response->timelineID, - "heard whois response"); - } else if (mState == ICommonClock::STATE_CLIENT) { - // if we get multiple responses because there are multiple devices - // who believe that they are master, then follow the master that - // wins arbitration - if (arbitrateMaster(response->deviceID, - response->devicePriority, - mClient_MasterDeviceID, - mClient_MasterDevicePriority)) { - return becomeClient(srcAddr, - response->deviceID, - response->devicePriority, - response->timelineID, - "heard whois response"); - } - } - - return true; -} - -bool CommonTimeServer::handleSyncRequest(const SyncRequestPacket* request, - const sockaddr_storage& srcAddr) { - SyncResponsePacket pkt; - pkt.initHeader(mTimelineID, mSyncGroupID); - - if ((mState == ICommonClock::STATE_MASTER) && - (mTimelineID == request->timelineID)) { - int64_t rxLocalTime = mLastPacketRxLocalTime; - int64_t rxCommonTime; - - // If we are master on an actual network and have actual clients, then - // we are no longer low priority. - setForceLowPriority(false); - - if (OK != mCommonClock.localToCommon(rxLocalTime, &rxCommonTime)) { - return false; - } - - int64_t txLocalTime = mLocalClock.getLocalTime();; - int64_t txCommonTime; - if (OK != mCommonClock.localToCommon(txLocalTime, &txCommonTime)) { - return false; - } - - pkt.nak = 0; - pkt.clientTxLocalTime = request->clientTxLocalTime; - pkt.masterRxCommonTime = rxCommonTime; - pkt.masterTxCommonTime = txCommonTime; - } else { - pkt.nak = 1; - pkt.clientTxLocalTime = 0; - pkt.masterRxCommonTime = 0; - pkt.masterTxCommonTime = 0; - } - - uint8_t buf[256]; - ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); - if (bufSz < 0) - return false; - - ssize_t sendBytes = sendto( - mSocket, &buf, bufSz, 0, - reinterpret_cast<const sockaddr *>(&srcAddr), - sizeof(srcAddr)); - if (sendBytes == -1) { - ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__); - return false; - } - - return true; -} - -bool CommonTimeServer::handleSyncResponse( - const SyncResponsePacket* response, - const sockaddr_storage& srcAddr) { - if (mState != ICommonClock::STATE_CLIENT) - return true; - - assert(mMasterEPValid); - if (!sockaddrMatch(srcAddr, mMasterEP, true)) { - char srcEP[64], expectedEP[64]; - sockaddrToString(srcAddr, true, srcEP, sizeof(srcEP)); - sockaddrToString(mMasterEP, true, expectedEP, sizeof(expectedEP)); - ALOGI("Dropping sync response from unexpected address." - " Expected %s Got %s", expectedEP, srcEP); - return true; - } - - if (response->nak) { - // if our master is no longer accepting requests, then we need to find - // a new master - return becomeRonin("master NAK'ed"); - } - - mClient_SyncRequestPending = 0; - mClient_SyncRequestTimeouts = 0; - mClient_PacketRTTLog.logRX(response->clientTxLocalTime, - mLastPacketRxLocalTime); - - bool result; - if (!(mClient_SyncRespsRXedFromCurMaster++)) { - // the first request/response exchange between a client and a master - // may take unusually long due to ARP, so discard it. - result = true; - } else { - int64_t clientTxLocalTime = response->clientTxLocalTime; - int64_t clientRxLocalTime = mLastPacketRxLocalTime; - int64_t masterTxCommonTime = response->masterTxCommonTime; - int64_t masterRxCommonTime = response->masterRxCommonTime; - - int64_t rtt = (clientRxLocalTime - clientTxLocalTime); - int64_t avgLocal = (clientTxLocalTime + clientRxLocalTime) >> 1; - int64_t avgCommon = (masterTxCommonTime + masterRxCommonTime) >> 1; - - // if the RTT of the packet is significantly larger than the panic - // threshold, we should simply discard it. Its better to do nothing - // than to take cues from a packet like that. - int rttCommon = mCommonClock.localDurationToCommonDuration(rtt); - if (rttCommon > (static_cast<int64_t>(mPanicThresholdUsec) * - kRTTDiscardPanicThreshMultiplier)) { - ALOGV("Dropping sync response with RTT of %lld uSec", rttCommon); - mClient_ExpiredSyncRespsRXedFromCurMaster++; - if (shouldPanicNotGettingGoodData()) - return becomeInitial("RX panic, no good data"); - } else { - result = mClockRecovery.pushDisciplineEvent(avgLocal, avgCommon, rttCommon); - mClient_LastGoodSyncRX = clientRxLocalTime; - - if (result) { - // indicate to listeners that we've synced to the common timeline - notifyClockSync(); - } else { - ALOGE("Panic! Observed clock sync error is too high to tolerate," - " resetting state machine and starting over."); - notifyClockSyncLoss(); - return becomeInitial("panic"); - } - } - } - - mCurTimeout.setTimeout(mSyncRequestIntervalMs); - return result; -} - -bool CommonTimeServer::handleMasterAnnouncement( - const MasterAnnouncementPacket* packet, - const sockaddr_storage& srcAddr) { - uint64_t newDeviceID = packet->deviceID; - uint8_t newDevicePrio = packet->devicePriority; - uint64_t newTimelineID = packet->timelineID; - - // Skip our own messages which come back via broadcast loopback. - if (newDeviceID == mDeviceID) - return true; - - char srcEPStr[64]; - sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr)); - mElectionLog.log("RXed master announcement while in state %s. " - "src %s srcDevID %lld srcPrio %u srcTID %016llx", - stateToString(mState), srcEPStr, - newDeviceID, static_cast<uint32_t>(newDevicePrio), - newTimelineID); - - if (mState == ICommonClock::STATE_INITIAL || - mState == ICommonClock::STATE_RONIN || - mState == ICommonClock::STATE_WAIT_FOR_ELECTION) { - // if we aren't currently following a master, then start following - // this new master - return becomeClient(srcAddr, - newDeviceID, - newDevicePrio, - newTimelineID, - "heard master announcement"); - } else if (mState == ICommonClock::STATE_CLIENT) { - // if the new master wins arbitration against our current master, - // then become a client of the new master - if (arbitrateMaster(newDeviceID, - newDevicePrio, - mClient_MasterDeviceID, - mClient_MasterDevicePriority)) - return becomeClient(srcAddr, - newDeviceID, - newDevicePrio, - newTimelineID, - "heard master announcement"); - } else if (mState == ICommonClock::STATE_MASTER) { - // two masters are competing - if the new one wins arbitration, then - // cease acting as master - if (arbitrateMaster(newDeviceID, newDevicePrio, - mDeviceID, effectivePriority())) - return becomeClient(srcAddr, newDeviceID, - newDevicePrio, newTimelineID, - "heard master announcement"); - } - - return true; -} - -bool CommonTimeServer::sendWhoIsMasterRequest() { - assert(mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN); - - // If we have no socket, then we must be in the unconfigured initial state. - // Don't report any errors, just don't try to send the initial who-is-master - // query. Eventually, our network will either become configured, or we will - // be forced into network-less master mode by higher level code. - if (mSocket < 0) { - assert(mState == ICommonClock::STATE_INITIAL); - return true; - } - - bool ret = false; - WhoIsMasterRequestPacket pkt; - pkt.initHeader(mSyncGroupID); - pkt.senderDeviceID = mDeviceID; - pkt.senderDevicePriority = effectivePriority(); - - uint8_t buf[256]; - ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); - if (bufSz >= 0) { - char dstEPStr[64]; - sockaddrToString(mMasterElectionEP, true, dstEPStr, sizeof(dstEPStr)); - mElectionLog.log("TXing WhoIs master request to %s while in state %s. " - "ourTID %016llx ourGID %016llx ourDID %016llx " - "ourPrio %u", - dstEPStr, stateToString(mState), - mTimelineID, mSyncGroupID, - pkt.senderDeviceID, pkt.senderDevicePriority); - - ssize_t sendBytes = sendto( - mSocket, buf, bufSz, 0, - reinterpret_cast<const sockaddr *>(&mMasterElectionEP), - sizeof(mMasterElectionEP)); - if (sendBytes < 0) - ALOGE("WhoIsMaster sendto failed (errno %d)", errno); - ret = true; - } - - if (mState == ICommonClock::STATE_INITIAL) { - mCurTimeout.setTimeout(kInitial_WhoIsMasterTimeoutMs); - } else { - mCurTimeout.setTimeout(kRonin_WhoIsMasterTimeoutMs); - } - - return ret; -} - -bool CommonTimeServer::sendSyncRequest() { - // If we are sending sync requests, then we must be in the client state and - // we must have a socket (when we have no network, we are only supposed to - // be in INITIAL or MASTER) - assert(mState == ICommonClock::STATE_CLIENT); - assert(mSocket >= 0); - - bool ret = false; - SyncRequestPacket pkt; - pkt.initHeader(mTimelineID, mSyncGroupID); - pkt.clientTxLocalTime = mLocalClock.getLocalTime(); - - if (!mClient_FirstSyncTX) - mClient_FirstSyncTX = pkt.clientTxLocalTime; - - mClient_PacketRTTLog.logTX(pkt.clientTxLocalTime); - - uint8_t buf[256]; - ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); - if (bufSz >= 0) { - ssize_t sendBytes = sendto( - mSocket, buf, bufSz, 0, - reinterpret_cast<const sockaddr *>(&mMasterEP), - sizeof(mMasterEP)); - if (sendBytes < 0) - ALOGE("SyncRequest sendto failed (errno %d)", errno); - ret = true; - } - - mClient_SyncsSentToCurMaster++; - mCurTimeout.setTimeout(mSyncRequestIntervalMs); - mClient_SyncRequestPending = true; - - return ret; -} - -bool CommonTimeServer::sendMasterAnnouncement() { - bool ret = false; - assert(mState == ICommonClock::STATE_MASTER); - - // If we are being asked to send a master announcement, but we have no - // socket, we must be in network-less master mode. Don't bother to send the - // announcement, and don't bother to schedule a timeout. When the network - // comes up, the work thread will get poked and start the process of - // figuring out who the current master should be. - if (mSocket < 0) { - mCurTimeout.setTimeout(kInfiniteTimeout); - return true; - } - - MasterAnnouncementPacket pkt; - pkt.initHeader(mTimelineID, mSyncGroupID); - pkt.deviceID = mDeviceID; - pkt.devicePriority = effectivePriority(); - - uint8_t buf[256]; - ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); - if (bufSz >= 0) { - char dstEPStr[64]; - sockaddrToString(mMasterElectionEP, true, dstEPStr, sizeof(dstEPStr)); - mElectionLog.log("TXing Master announcement to %s while in state %s. " - "ourTID %016llx ourGID %016llx ourDID %016llx " - "ourPrio %u", - dstEPStr, stateToString(mState), - mTimelineID, mSyncGroupID, - pkt.deviceID, pkt.devicePriority); - - ssize_t sendBytes = sendto( - mSocket, buf, bufSz, 0, - reinterpret_cast<const sockaddr *>(&mMasterElectionEP), - sizeof(mMasterElectionEP)); - if (sendBytes < 0) - ALOGE("MasterAnnouncement sendto failed (errno %d)", errno); - ret = true; - } - - mCurTimeout.setTimeout(mMasterAnnounceIntervalMs); - return ret; -} - -bool CommonTimeServer::becomeClient(const sockaddr_storage& masterEP, - uint64_t masterDeviceID, - uint8_t masterDevicePriority, - uint64_t timelineID, - const char* cause) { - char newEPStr[64], oldEPStr[64]; - sockaddrToString(masterEP, true, newEPStr, sizeof(newEPStr)); - sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr)); - - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "%s --> CLIENT (%s) :%s" - " OldMaster: %02x-%014llx::%016llx::%s" - " NewMaster: %02x-%014llx::%016llx::%s", - stateToString(mState), cause, - (mTimelineID != timelineID) ? " (new timeline)" : "", - mClient_MasterDevicePriority, mClient_MasterDeviceID, - mTimelineID, oldEPStr, - masterDevicePriority, masterDeviceID, - timelineID, newEPStr); - - if (mTimelineID != timelineID) { - // start following a new timeline - mTimelineID = timelineID; - mClockRecovery.reset(true, true); - notifyClockSyncLoss(); - } else { - // start following a new master on the existing timeline - mClockRecovery.reset(false, true); - } - - mMasterEP = masterEP; - mMasterEPValid = true; - - // If we are on a real network as a client of a real master, then we should - // no longer force low priority. If our master disappears, we should have - // the high priority bit set during the election to replace the master - // because this group was a real group and not a singleton created in - // networkless mode. - setForceLowPriority(false); - - mClient_MasterDeviceID = masterDeviceID; - mClient_MasterDevicePriority = masterDevicePriority; - resetSyncStats(); - - setState(ICommonClock::STATE_CLIENT); - - // add some jitter to when the various clients send their requests - // in order to reduce the likelihood that a group of clients overload - // the master after receiving a master announcement - usleep((lrand48() % 100) * 1000); - - return sendSyncRequest(); -} - -bool CommonTimeServer::becomeMaster(const char* cause) { - uint64_t oldTimelineID = mTimelineID; - if (mTimelineID == ICommonClock::kInvalidTimelineID) { - // this device has not been following any existing timeline, - // so it will create a new timeline and declare itself master - assert(!mCommonClock.isValid()); - - // set the common time basis - mCommonClock.setBasis(mLocalClock.getLocalTime(), 0); - - // assign an arbitrary timeline iD - assignTimelineID(); - - // notify listeners that we've created a common timeline - notifyClockSync(); - } - - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "%s --> MASTER (%s) : %s timeline %016llx", - stateToString(mState), cause, - (oldTimelineID == mTimelineID) ? "taking ownership of" - : "creating new", - mTimelineID); - - memset(&mMasterEP, 0, sizeof(mMasterEP)); - mMasterEPValid = false; - mClient_MasterDevicePriority = effectivePriority(); - mClient_MasterDeviceID = mDeviceID; - mClockRecovery.reset(false, true); - resetSyncStats(); - - setState(ICommonClock::STATE_MASTER); - return sendMasterAnnouncement(); -} - -bool CommonTimeServer::becomeRonin(const char* cause) { - // If we were the client of a given timeline, but had never received even a - // single time sync packet, then we transition back to Initial instead of - // Ronin. If we transition to Ronin and end up becoming the new Master, we - // will be unable to service requests for other clients because we never - // actually knew what time it was. By going to initial, we ensure that - // other clients who know what time it is, but would lose master arbitration - // in the Ronin case, will step up and become the proper new master of the - // old timeline. - - char oldEPStr[64]; - sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr)); - memset(&mMasterEP, 0, sizeof(mMasterEP)); - mMasterEPValid = false; - - if (mCommonClock.isValid()) { - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "%s --> RONIN (%s) : lost track of previously valid timeline " - "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)", - stateToString(mState), cause, - mClient_MasterDevicePriority, mClient_MasterDeviceID, - mTimelineID, oldEPStr, - mClient_SyncsSentToCurMaster, - mClient_SyncRespsRXedFromCurMaster, - mClient_ExpiredSyncRespsRXedFromCurMaster); - - mRonin_WhoIsMasterRequestTimeouts = 0; - setState(ICommonClock::STATE_RONIN); - return sendWhoIsMasterRequest(); - } else { - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "%s --> INITIAL (%s) : never synced timeline " - "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)", - stateToString(mState), cause, - mClient_MasterDevicePriority, mClient_MasterDeviceID, - mTimelineID, oldEPStr, - mClient_SyncsSentToCurMaster, - mClient_SyncRespsRXedFromCurMaster, - mClient_ExpiredSyncRespsRXedFromCurMaster); - - return becomeInitial("ronin, no timeline"); - } -} - -bool CommonTimeServer::becomeWaitForElection(const char* cause) { - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "%s --> WAIT_FOR_ELECTION (%s) : dropping out of election," - " waiting %d mSec for completion.", - stateToString(mState), cause, kWaitForElection_TimeoutMs); - - setState(ICommonClock::STATE_WAIT_FOR_ELECTION); - mCurTimeout.setTimeout(kWaitForElection_TimeoutMs); - return true; -} - -bool CommonTimeServer::becomeInitial(const char* cause) { - mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG, - "Entering INITIAL (%s), total reset.", - cause); - - setState(ICommonClock::STATE_INITIAL); - - // reset clock recovery - mClockRecovery.reset(true, true); - - // reset internal state bookkeeping. - mCurTimeout.setTimeout(kInfiniteTimeout); - memset(&mMasterEP, 0, sizeof(mMasterEP)); - mMasterEPValid = false; - mLastPacketRxLocalTime = 0; - mTimelineID = ICommonClock::kInvalidTimelineID; - mClockSynced = false; - mInitial_WhoIsMasterRequestTimeouts = 0; - mClient_MasterDeviceID = 0; - mClient_MasterDevicePriority = 0; - mRonin_WhoIsMasterRequestTimeouts = 0; - resetSyncStats(); - - // send the first request to discover the master - return sendWhoIsMasterRequest(); -} - -void CommonTimeServer::notifyClockSync() { - if (!mClockSynced) { - mClockSynced = true; - mICommonClock->notifyOnTimelineChanged(mTimelineID); - } -} - -void CommonTimeServer::notifyClockSyncLoss() { - if (mClockSynced) { - mClockSynced = false; - mICommonClock->notifyOnTimelineChanged( - ICommonClock::kInvalidTimelineID); - } -} - -void CommonTimeServer::setState(ICommonClock::State s) { - mState = s; -} - -const char* CommonTimeServer::stateToString(ICommonClock::State s) { - switch(s) { - case ICommonClock::STATE_INITIAL: - return "INITIAL"; - case ICommonClock::STATE_CLIENT: - return "CLIENT"; - case ICommonClock::STATE_MASTER: - return "MASTER"; - case ICommonClock::STATE_RONIN: - return "RONIN"; - case ICommonClock::STATE_WAIT_FOR_ELECTION: - return "WAIT_FOR_ELECTION"; - default: - return "unknown"; - } -} - -void CommonTimeServer::sockaddrToString(const sockaddr_storage& addr, - bool addrValid, - char* buf, size_t bufLen) { - if (!bufLen || !buf) - return; - - if (addrValid) { - switch (addr.ss_family) { - case AF_INET: { - const struct sockaddr_in* sa = - reinterpret_cast<const struct sockaddr_in*>(&addr); - unsigned long a = ntohl(sa->sin_addr.s_addr); - uint16_t p = ntohs(sa->sin_port); - snprintf(buf, bufLen, "%lu.%lu.%lu.%lu:%hu", - ((a >> 24) & 0xFF), ((a >> 16) & 0xFF), - ((a >> 8) & 0xFF), (a & 0xFF), p); - } break; - - case AF_INET6: { - const struct sockaddr_in6* sa = - reinterpret_cast<const struct sockaddr_in6*>(&addr); - const uint8_t* a = sa->sin6_addr.s6_addr; - uint16_t p = ntohs(sa->sin6_port); - snprintf(buf, bufLen, - "%02X%02X:%02X%02X:%02X%02X:%02X%02X:" - "%02X%02X:%02X%02X:%02X%02X:%02X%02X port %hd", - a[0], a[1], a[ 2], a[ 3], a[ 4], a[ 5], a[ 6], a[ 7], - a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], - p); - } break; - - default: - snprintf(buf, bufLen, - "<unknown sockaddr family %d>", addr.ss_family); - break; - } - } else { - snprintf(buf, bufLen, "<none>"); - } - - buf[bufLen - 1] = 0; -} - -bool CommonTimeServer::sockaddrMatch(const sockaddr_storage& a1, - const sockaddr_storage& a2, - bool matchAddressOnly) { - if (a1.ss_family != a2.ss_family) - return false; - - switch (a1.ss_family) { - case AF_INET: { - const struct sockaddr_in* sa1 = - reinterpret_cast<const struct sockaddr_in*>(&a1); - const struct sockaddr_in* sa2 = - reinterpret_cast<const struct sockaddr_in*>(&a2); - - if (sa1->sin_addr.s_addr != sa2->sin_addr.s_addr) - return false; - - return (matchAddressOnly || (sa1->sin_port == sa2->sin_port)); - } break; - - case AF_INET6: { - const struct sockaddr_in6* sa1 = - reinterpret_cast<const struct sockaddr_in6*>(&a1); - const struct sockaddr_in6* sa2 = - reinterpret_cast<const struct sockaddr_in6*>(&a2); - - if (memcmp(&sa1->sin6_addr, &sa2->sin6_addr, sizeof(sa2->sin6_addr))) - return false; - - return (matchAddressOnly || (sa1->sin6_port == sa2->sin6_port)); - } break; - - // Huh? We don't deal in non-IPv[46] addresses. Not sure how we got - // here, but we don't know how to comapre these addresses and simply - // default to a no-match decision. - default: return false; - } -} - -bool CommonTimeServer::shouldPanicNotGettingGoodData() { - if (mClient_FirstSyncTX) { - int64_t now = mLocalClock.getLocalTime(); - int64_t delta = now - (mClient_LastGoodSyncRX - ? mClient_LastGoodSyncRX - : mClient_FirstSyncTX); - int64_t deltaUsec = mCommonClock.localDurationToCommonDuration(delta); - - if (deltaUsec >= kNoGoodDataPanicThresholdUsec) - return true; - } - - return false; -} - -void CommonTimeServer::PacketRTTLog::logTX(int64_t txTime) { - txTimes[wrPtr] = txTime; - rxTimes[wrPtr] = 0; - wrPtr = (wrPtr + 1) % RTT_LOG_SIZE; - if (!wrPtr) - logFull = true; -} - -void CommonTimeServer::PacketRTTLog::logRX(int64_t txTime, int64_t rxTime) { - if (!logFull && !wrPtr) - return; - - uint32_t i = logFull ? wrPtr : 0; - do { - if (txTimes[i] == txTime) { - rxTimes[i] = rxTime; - break; - } - i = (i + 1) % RTT_LOG_SIZE; - } while (i != wrPtr); -} - -} // namespace android diff --git a/services/common_time/common_time_server.h b/services/common_time/common_time_server.h deleted file mode 100644 index 6e18050..0000000 --- a/services/common_time/common_time_server.h +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#ifndef ANDROID_COMMON_TIME_SERVER_H -#define ANDROID_COMMON_TIME_SERVER_H - -#include <arpa/inet.h> -#include <stdint.h> -#include <sys/socket.h> - -#include <common_time/ICommonClock.h> -#include <common_time/local_clock.h> -#include <utils/String8.h> - -#include "clock_recovery.h" -#include "common_clock.h" -#include "common_time_server_packets.h" -#include "utils.h" - -#define RTT_LOG_SIZE 30 - -namespace android { - -class CommonClockService; -class CommonTimeConfigService; - -/***** time service implementation *****/ - -class CommonTimeServer : public Thread { - public: - CommonTimeServer(); - ~CommonTimeServer(); - - bool startServices(); - - // Common Clock API methods - CommonClock& getCommonClock() { return mCommonClock; } - LocalClock& getLocalClock() { return mLocalClock; } - uint64_t getTimelineID(); - int32_t getEstimatedError(); - ICommonClock::State getState(); - status_t getMasterAddr(struct sockaddr_storage* addr); - status_t isCommonTimeValid(bool* valid, uint32_t* timelineID); - - // Config API methods - status_t getMasterElectionPriority(uint8_t *priority); - status_t setMasterElectionPriority(uint8_t priority); - status_t getMasterElectionEndpoint(struct sockaddr_storage *addr); - status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr); - status_t getMasterElectionGroupId(uint64_t *id); - status_t setMasterElectionGroupId(uint64_t id); - status_t getInterfaceBinding(String8& ifaceName); - status_t setInterfaceBinding(const String8& ifaceName); - status_t getMasterAnnounceInterval(int *interval); - status_t setMasterAnnounceInterval(int interval); - status_t getClientSyncInterval(int *interval); - status_t setClientSyncInterval(int interval); - status_t getPanicThreshold(int *threshold); - status_t setPanicThreshold(int threshold); - status_t getAutoDisable(bool *autoDisable); - status_t setAutoDisable(bool autoDisable); - status_t forceNetworklessMasterMode(); - - // Method used by the CommonClockService to notify the core service about - // changes in the number of active common clock clients. - void reevaluateAutoDisableState(bool commonClockHasClients); - - status_t dumpClockInterface(int fd, const Vector<String16>& args, - size_t activeClients); - status_t dumpConfigInterface(int fd, const Vector<String16>& args); - - private: - class PacketRTTLog { - public: - PacketRTTLog() { - resetLog(); - } - - void resetLog() { - wrPtr = 0; - logFull = 0; - } - - void logTX(int64_t txTime); - void logRX(int64_t txTime, int64_t rxTime); - void dumpLog(int fd, const CommonClock& cclk); - - private: - uint32_t wrPtr; - bool logFull; - int64_t txTimes[RTT_LOG_SIZE]; - int64_t rxTimes[RTT_LOG_SIZE]; - }; - - bool threadLoop(); - - bool runStateMachine_l(); - bool setupSocket_l(); - - void assignTimelineID(); - bool assignDeviceID(); - - static bool arbitrateMaster(uint64_t deviceID1, uint8_t devicePrio1, - uint64_t deviceID2, uint8_t devicePrio2); - - bool handlePacket(); - bool handleWhoIsMasterRequest (const WhoIsMasterRequestPacket* request, - const sockaddr_storage& srcAddr); - bool handleWhoIsMasterResponse(const WhoIsMasterResponsePacket* response, - const sockaddr_storage& srcAddr); - bool handleSyncRequest (const SyncRequestPacket* request, - const sockaddr_storage& srcAddr); - bool handleSyncResponse (const SyncResponsePacket* response, - const sockaddr_storage& srcAddr); - bool handleMasterAnnouncement (const MasterAnnouncementPacket* packet, - const sockaddr_storage& srcAddr); - - bool handleTimeout(); - bool handleTimeoutInitial(); - bool handleTimeoutClient(); - bool handleTimeoutMaster(); - bool handleTimeoutRonin(); - bool handleTimeoutWaitForElection(); - - bool sendWhoIsMasterRequest(); - bool sendSyncRequest(); - bool sendMasterAnnouncement(); - - bool becomeClient(const sockaddr_storage& masterAddr, - uint64_t masterDeviceID, - uint8_t masterDevicePriority, - uint64_t timelineID, - const char* cause); - bool becomeMaster(const char* cause); - bool becomeRonin(const char* cause); - bool becomeWaitForElection(const char* cause); - bool becomeInitial(const char* cause); - - void notifyClockSync(); - void notifyClockSyncLoss(); - - ICommonClock::State mState; - void setState(ICommonClock::State s); - - void clearPendingWakeupEvents_l(); - void wakeupThread_l(); - void cleanupSocket_l(); - void shutdownThread(); - - inline uint8_t effectivePriority() const { - return (mMasterPriority & 0x7F) | - (mForceLowPriority ? 0x00 : 0x80); - } - - inline bool shouldAutoDisable() const { - return (mAutoDisable && !mCommonClockHasClients); - } - - inline void resetSyncStats() { - mClient_SyncRequestPending = false; - mClient_SyncRequestTimeouts = 0; - mClient_SyncsSentToCurMaster = 0; - mClient_SyncRespsRXedFromCurMaster = 0; - mClient_ExpiredSyncRespsRXedFromCurMaster = 0; - mClient_FirstSyncTX = 0; - mClient_LastGoodSyncRX = 0; - mClient_PacketRTTLog.resetLog(); - } - - bool shouldPanicNotGettingGoodData(); - - // Helper to keep track of the state machine's current timeout - Timeout mCurTimeout; - - // common clock, local clock abstraction, and clock recovery loop - CommonClock mCommonClock; - LocalClock mLocalClock; - ClockRecoveryLoop mClockRecovery; - - // implementation of ICommonClock - sp<CommonClockService> mICommonClock; - - // implementation of ICommonTimeConfig - sp<CommonTimeConfigService> mICommonTimeConfig; - - // UDP socket for the time sync protocol - int mSocket; - - // eventfd used to wakeup the work thread in response to configuration - // changes. - int mWakeupThreadFD; - - // timestamp captured when a packet is received - int64_t mLastPacketRxLocalTime; - - // ID of the timeline that this device is following - uint64_t mTimelineID; - - // flag for whether the clock has been synced to a timeline - bool mClockSynced; - - // flag used to indicate that clients should be considered to be lower - // priority than all of their peers during elections. This flag is set and - // cleared by the state machine. It is set when the client joins a new - // network. If the client had been a master in the old network (or an - // isolated master with no network connectivity) it should defer to any - // masters which may already be on the network. It will be cleared whenever - // the state machine transitions to the master state. - bool mForceLowPriority; - inline void setForceLowPriority(bool val) { - mForceLowPriority = val; - if (mState == ICommonClock::STATE_MASTER) - mClient_MasterDevicePriority = effectivePriority(); - } - - // Lock to synchronize access to internal state and configuration. - Mutex mLock; - - // Flag updated by the common clock service to indicate that it does or does - // not currently have registered clients. When the the auto disable flag is - // cleared on the common time service, the service will participate in - // network synchronization whenever it has a valid network interface to bind - // to. When the auto disable flag is set on the common time service, it - // will only participate in network synchronization when it has both a valid - // interface AND currently active common clock clients. - bool mCommonClockHasClients; - - // Internal logs used for dumpsys. - LogRing mStateChangeLog; - LogRing mElectionLog; - LogRing mBadPktLog; - - // Configuration info - struct sockaddr_storage mMasterElectionEP; // Endpoint over which we conduct master election - String8 mBindIface; // Endpoint for the service to bind to. - bool mBindIfaceValid; // whether or not the bind Iface is valid. - bool mBindIfaceDirty; // whether or not the bind Iface is valid. - struct sockaddr_storage mMasterEP; // Endpoint of our current master (if any) - bool mMasterEPValid; - uint64_t mDeviceID; // unique ID of this device - uint64_t mSyncGroupID; // synchronization group ID of this device. - uint8_t mMasterPriority; // Priority of this device in master election. - uint32_t mMasterAnnounceIntervalMs; - uint32_t mSyncRequestIntervalMs; - uint32_t mPanicThresholdUsec; - bool mAutoDisable; - - // Config defaults. - static const char* kDefaultMasterElectionAddr; - static const uint16_t kDefaultMasterElectionPort; - static const uint64_t kDefaultSyncGroupID; - static const uint8_t kDefaultMasterPriority; - static const uint32_t kDefaultMasterAnnounceIntervalMs; - static const uint32_t kDefaultSyncRequestIntervalMs; - static const uint32_t kDefaultPanicThresholdUsec; - static const bool kDefaultAutoDisable; - - // Priority mask and shift fields. - static const uint64_t kDeviceIDMask; - static const uint8_t kDevicePriorityMask; - static const uint8_t kDevicePriorityHiLowBit; - static const uint32_t kDevicePriorityShift; - - // Unconfgurable constants - static const int kSetupRetryTimeoutMs; - static const int64_t kNoGoodDataPanicThresholdUsec; - static const uint32_t kRTTDiscardPanicThreshMultiplier; - - /*** status while in the Initial state ***/ - int mInitial_WhoIsMasterRequestTimeouts; - static const int kInitial_NumWhoIsMasterRetries; - static const int kInitial_WhoIsMasterTimeoutMs; - - /*** status while in the Client state ***/ - uint64_t mClient_MasterDeviceID; - uint8_t mClient_MasterDevicePriority; - bool mClient_SyncRequestPending; - int mClient_SyncRequestTimeouts; - uint32_t mClient_SyncsSentToCurMaster; - uint32_t mClient_SyncRespsRXedFromCurMaster; - uint32_t mClient_ExpiredSyncRespsRXedFromCurMaster; - int64_t mClient_FirstSyncTX; - int64_t mClient_LastGoodSyncRX; - PacketRTTLog mClient_PacketRTTLog; - static const int kClient_NumSyncRequestRetries; - - - /*** status while in the Master state ***/ - static const uint32_t kDefaultMaster_AnnouncementIntervalMs; - - /*** status while in the Ronin state ***/ - int mRonin_WhoIsMasterRequestTimeouts; - static const int kRonin_NumWhoIsMasterRetries; - static const int kRonin_WhoIsMasterTimeoutMs; - - /*** status while in the WaitForElection state ***/ - static const int kWaitForElection_TimeoutMs; - - static const int kInfiniteTimeout; - - static const char* stateToString(ICommonClock::State s); - static void sockaddrToString(const sockaddr_storage& addr, bool addrValid, - char* buf, size_t bufLen); - static bool sockaddrMatch(const sockaddr_storage& a1, - const sockaddr_storage& a2, - bool matchAddressOnly); -}; - -} // namespace android - -#endif // ANDROID_COMMON_TIME_SERVER_H diff --git a/services/common_time/common_time_server_api.cpp b/services/common_time/common_time_server_api.cpp deleted file mode 100644 index e157071..0000000 --- a/services/common_time/common_time_server_api.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (C) 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. - */ - -/* - * A service that exchanges time synchronization information between - * a master that defines a timeline and clients that follow the timeline. - */ - -#define LOG_TAG "common_time" -#include <utils/Log.h> - -#include <binder/IServiceManager.h> -#include <binder/IPCThreadState.h> - -#include "common_time_server.h" - -namespace android { - -// -// Clock API -// -uint64_t CommonTimeServer::getTimelineID() { - AutoMutex _lock(&mLock); - return mTimelineID; -} - -ICommonClock::State CommonTimeServer::getState() { - AutoMutex _lock(&mLock); - return mState; -} - -status_t CommonTimeServer::getMasterAddr(struct sockaddr_storage* addr) { - AutoMutex _lock(&mLock); - if (mMasterEPValid) { - memcpy(addr, &mMasterEP, sizeof(*addr)); - return OK; - } - - return UNKNOWN_ERROR; -} - -int32_t CommonTimeServer::getEstimatedError() { - AutoMutex _lock(&mLock); - - if (ICommonClock::STATE_MASTER == mState) - return 0; - - if (!mClockSynced) - return ICommonClock::kErrorEstimateUnknown; - - return mClockRecovery.getLastErrorEstimate(); -} - -status_t CommonTimeServer::isCommonTimeValid(bool* valid, - uint32_t* timelineID) { - AutoMutex _lock(&mLock); - *valid = mCommonClock.isValid(); - *timelineID = mTimelineID; - return OK; -} - -// -// Config API -// -status_t CommonTimeServer::getMasterElectionPriority(uint8_t *priority) { - AutoMutex _lock(&mLock); - *priority = mMasterPriority; - return OK; -} - -status_t CommonTimeServer::setMasterElectionPriority(uint8_t priority) { - AutoMutex _lock(&mLock); - - if (priority > 0x7F) - return BAD_VALUE; - - mMasterPriority = priority; - return OK; -} - -status_t CommonTimeServer::getMasterElectionEndpoint( - struct sockaddr_storage *addr) { - AutoMutex _lock(&mLock); - memcpy(addr, &mMasterElectionEP, sizeof(*addr)); - return OK; -} - -status_t CommonTimeServer::setMasterElectionEndpoint( - const struct sockaddr_storage *addr) { - AutoMutex _lock(&mLock); - - if (!addr) - return BAD_VALUE; - - // TODO: add proper support for IPv6 - if (addr->ss_family != AF_INET) - return BAD_VALUE; - - // Only multicast and broadcast endpoints with explicit ports are allowed. - uint16_t ipv4Port = ntohs( - reinterpret_cast<const struct sockaddr_in*>(addr)->sin_port); - if (!ipv4Port) - return BAD_VALUE; - - uint32_t ipv4Addr = ntohl( - reinterpret_cast<const struct sockaddr_in*>(addr)->sin_addr.s_addr); - if ((ipv4Addr != 0xFFFFFFFF) && (0xE0000000 != (ipv4Addr & 0xF0000000))) - return BAD_VALUE; - - memcpy(&mMasterElectionEP, addr, sizeof(mMasterElectionEP)); - - // Force a rebind in order to change election enpoints. - mBindIfaceDirty = true; - wakeupThread_l(); - return OK; -} - -status_t CommonTimeServer::getMasterElectionGroupId(uint64_t *id) { - AutoMutex _lock(&mLock); - *id = mSyncGroupID; - return OK; -} - -status_t CommonTimeServer::setMasterElectionGroupId(uint64_t id) { - AutoMutex _lock(&mLock); - mSyncGroupID = id; - return OK; -} - -status_t CommonTimeServer::getInterfaceBinding(String8& ifaceName) { - AutoMutex _lock(&mLock); - if (!mBindIfaceValid) - return INVALID_OPERATION; - ifaceName = mBindIface; - return OK; -} - -status_t CommonTimeServer::setInterfaceBinding(const String8& ifaceName) { - AutoMutex _lock(&mLock); - - mBindIfaceDirty = true; - if (ifaceName.size()) { - mBindIfaceValid = true; - mBindIface = ifaceName; - } else { - mBindIfaceValid = false; - mBindIface.clear(); - } - - wakeupThread_l(); - return OK; -} - -status_t CommonTimeServer::getMasterAnnounceInterval(int *interval) { - AutoMutex _lock(&mLock); - *interval = mMasterAnnounceIntervalMs; - return OK; -} - -status_t CommonTimeServer::setMasterAnnounceInterval(int interval) { - AutoMutex _lock(&mLock); - - if (interval > (6 *3600000)) // Max interval is once every 6 hrs - return BAD_VALUE; - - if (interval < 500) // Min interval is once per 0.5 seconds - return BAD_VALUE; - - mMasterAnnounceIntervalMs = interval; - if (ICommonClock::STATE_MASTER == mState) { - int pendingTimeout = mCurTimeout.msecTillTimeout(); - if ((kInfiniteTimeout == pendingTimeout) || - (pendingTimeout > interval)) { - mCurTimeout.setTimeout(mMasterAnnounceIntervalMs); - wakeupThread_l(); - } - } - - return OK; -} - -status_t CommonTimeServer::getClientSyncInterval(int *interval) { - AutoMutex _lock(&mLock); - *interval = mSyncRequestIntervalMs; - return OK; -} - -status_t CommonTimeServer::setClientSyncInterval(int interval) { - AutoMutex _lock(&mLock); - - if (interval > (3600000)) // Max interval is once every 60 min - return BAD_VALUE; - - if (interval < 250) // Min interval is once per 0.25 seconds - return BAD_VALUE; - - mSyncRequestIntervalMs = interval; - if (ICommonClock::STATE_CLIENT == mState) { - int pendingTimeout = mCurTimeout.msecTillTimeout(); - if ((kInfiniteTimeout == pendingTimeout) || - (pendingTimeout > interval)) { - mCurTimeout.setTimeout(mSyncRequestIntervalMs); - wakeupThread_l(); - } - } - - return OK; -} - -status_t CommonTimeServer::getPanicThreshold(int *threshold) { - AutoMutex _lock(&mLock); - *threshold = mPanicThresholdUsec; - return OK; -} - -status_t CommonTimeServer::setPanicThreshold(int threshold) { - AutoMutex _lock(&mLock); - - if (threshold < 1000) // Min threshold is 1mSec - return BAD_VALUE; - - mPanicThresholdUsec = threshold; - return OK; -} - -status_t CommonTimeServer::getAutoDisable(bool *autoDisable) { - AutoMutex _lock(&mLock); - *autoDisable = mAutoDisable; - return OK; -} - -status_t CommonTimeServer::setAutoDisable(bool autoDisable) { - AutoMutex _lock(&mLock); - mAutoDisable = autoDisable; - wakeupThread_l(); - return OK; -} - -status_t CommonTimeServer::forceNetworklessMasterMode() { - AutoMutex _lock(&mLock); - - // Can't force networkless master mode if we are currently bound to a - // network. - if (mSocket >= 0) - return INVALID_OPERATION; - - becomeMaster("force networkless"); - - return OK; -} - -void CommonTimeServer::reevaluateAutoDisableState(bool commonClockHasClients) { - AutoMutex _lock(&mLock); - bool needWakeup = (mAutoDisable && mMasterEPValid && - (commonClockHasClients != mCommonClockHasClients)); - - mCommonClockHasClients = commonClockHasClients; - - if (needWakeup) { - ALOGI("Waking up service, auto-disable is engaged and service now has%s" - " clients", mCommonClockHasClients ? "" : " no"); - wakeupThread_l(); - } -} - -#define dump_printf(a, b...) do { \ - int res; \ - res = snprintf(buffer, sizeof(buffer), a, b); \ - buffer[sizeof(buffer) - 1] = 0; \ - if (res > 0) \ - write(fd, buffer, res); \ -} while (0) -#define checked_percentage(a, b) ((0 == b) ? 0.0f : ((100.0f * a) / b)) - -status_t CommonTimeServer::dumpClockInterface(int fd, - const Vector<String16>& args, - size_t activeClients) { - AutoMutex _lock(&mLock); - const size_t SIZE = 256; - char buffer[SIZE]; - - if (checkCallingPermission(String16("android.permission.DUMP")) == false) { - snprintf(buffer, SIZE, "Permission Denial: " - "can't dump CommonClockService from pid=%d, uid=%d\n", - IPCThreadState::self()->getCallingPid(), - IPCThreadState::self()->getCallingUid()); - write(fd, buffer, strlen(buffer)); - } else { - int64_t commonTime; - int64_t localTime; - bool synced; - char maStr[64]; - - localTime = mLocalClock.getLocalTime(); - synced = (OK == mCommonClock.localToCommon(localTime, &commonTime)); - sockaddrToString(mMasterEP, mMasterEPValid, maStr, sizeof(maStr)); - - dump_printf("Common Clock Service Status\nLocal time : %lld\n", - localTime); - - if (synced) - dump_printf("Common time : %lld\n", commonTime); - else - dump_printf("Common time : %s\n", "not synced"); - - dump_printf("Timeline ID : %016llx\n", mTimelineID); - dump_printf("State : %s\n", stateToString(mState)); - dump_printf("Master Addr : %s\n", maStr); - - - if (synced) { - int32_t est = (ICommonClock::STATE_MASTER != mState) - ? mClockRecovery.getLastErrorEstimate() - : 0; - dump_printf("Error Est. : %.3f msec\n", - static_cast<float>(est) / 1000.0); - } else { - dump_printf("Error Est. : %s\n", "unknown"); - } - - dump_printf("Syncs TXes : %u\n", mClient_SyncsSentToCurMaster); - dump_printf("Syncs RXes : %u (%.2f%%)\n", - mClient_SyncRespsRXedFromCurMaster, - checked_percentage( - mClient_SyncRespsRXedFromCurMaster, - mClient_SyncsSentToCurMaster)); - dump_printf("RXs Expired : %u (%.2f%%)\n", - mClient_ExpiredSyncRespsRXedFromCurMaster, - checked_percentage( - mClient_ExpiredSyncRespsRXedFromCurMaster, - mClient_SyncsSentToCurMaster)); - - if (!mClient_LastGoodSyncRX) { - dump_printf("Last Good RX : %s\n", "unknown"); - } else { - int64_t localDelta, usecDelta; - localDelta = localTime - mClient_LastGoodSyncRX; - usecDelta = mCommonClock.localDurationToCommonDuration(localDelta); - dump_printf("Last Good RX : %lld uSec ago\n", usecDelta); - } - - dump_printf("Active Clients : %u\n", activeClients); - mClient_PacketRTTLog.dumpLog(fd, mCommonClock); - mStateChangeLog.dumpLog(fd); - mElectionLog.dumpLog(fd); - mBadPktLog.dumpLog(fd); - } - - return NO_ERROR; -} - -status_t CommonTimeServer::dumpConfigInterface(int fd, - const Vector<String16>& args) { - AutoMutex _lock(&mLock); - const size_t SIZE = 256; - char buffer[SIZE]; - - if (checkCallingPermission(String16("android.permission.DUMP")) == false) { - snprintf(buffer, SIZE, "Permission Denial: " - "can't dump CommonTimeConfigService from pid=%d, uid=%d\n", - IPCThreadState::self()->getCallingPid(), - IPCThreadState::self()->getCallingUid()); - write(fd, buffer, strlen(buffer)); - } else { - char meStr[64]; - - sockaddrToString(mMasterElectionEP, true, meStr, sizeof(meStr)); - - dump_printf("Common Time Config Service Status\n" - "Bound Interface : %s\n", - mBindIfaceValid ? mBindIface.string() : "<unbound>"); - dump_printf("Master Election Endpoint : %s\n", meStr); - dump_printf("Master Election Group ID : %016llx\n", mSyncGroupID); - dump_printf("Master Announce Interval : %d mSec\n", - mMasterAnnounceIntervalMs); - dump_printf("Client Sync Interval : %d mSec\n", - mSyncRequestIntervalMs); - dump_printf("Panic Threshold : %d uSec\n", - mPanicThresholdUsec); - dump_printf("Base ME Prio : 0x%02x\n", - static_cast<uint32_t>(mMasterPriority)); - dump_printf("Effective ME Prio : 0x%02x\n", - static_cast<uint32_t>(effectivePriority())); - dump_printf("Auto Disable Allowed : %s\n", - mAutoDisable ? "yes" : "no"); - dump_printf("Auto Disable Engaged : %s\n", - shouldAutoDisable() ? "yes" : "no"); - } - - return NO_ERROR; -} - -void CommonTimeServer::PacketRTTLog::dumpLog(int fd, const CommonClock& cclk) { - const size_t SIZE = 256; - char buffer[SIZE]; - uint32_t avail = !logFull ? wrPtr : RTT_LOG_SIZE; - - if (!avail) - return; - - dump_printf("\nPacket Log (%d entries)\n", avail); - - uint32_t ndx = 0; - uint32_t i = logFull ? wrPtr : 0; - do { - if (rxTimes[i]) { - int64_t delta = rxTimes[i] - txTimes[i]; - int64_t deltaUsec = cclk.localDurationToCommonDuration(delta); - dump_printf("pkt[%2d] : localTX %12lld localRX %12lld " - "(%.3f msec RTT)\n", - ndx, txTimes[i], rxTimes[i], - static_cast<float>(deltaUsec) / 1000.0); - } else { - dump_printf("pkt[%2d] : localTX %12lld localRX never\n", - ndx, txTimes[i]); - } - i = (i + 1) % RTT_LOG_SIZE; - ndx++; - } while (i != wrPtr); -} - -#undef dump_printf -#undef checked_percentage - -} // namespace android diff --git a/services/common_time/common_time_server_packets.cpp b/services/common_time/common_time_server_packets.cpp deleted file mode 100644 index 9833c37..0000000 --- a/services/common_time/common_time_server_packets.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (C) 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. - */ - -/* - * A service that exchanges time synchronization information between - * a master that defines a timeline and clients that follow the timeline. - */ - -#define LOG_TAG "common_time" -#include <utils/Log.h> - -#include <arpa/inet.h> -#include <stdint.h> - -#include "common_time_server_packets.h" - -namespace android { - -const uint32_t TimeServicePacketHeader::kMagic = - (static_cast<uint32_t>('c') << 24) | - (static_cast<uint32_t>('c') << 16) | - (static_cast<uint32_t>('l') << 8) | - static_cast<uint32_t>('k'); - -const uint16_t TimeServicePacketHeader::kCurVersion = 1; - -#define SERIALIZE_FIELD(field_name, type, converter) \ - do { \ - if ((offset + sizeof(field_name)) > length) \ - return -1; \ - *((type*)(data + offset)) = converter(field_name); \ - offset += sizeof(field_name); \ - } while (0) -#define SERIALIZE_INT16(field_name) SERIALIZE_FIELD(field_name, int16_t, htons) -#define SERIALIZE_INT32(field_name) SERIALIZE_FIELD(field_name, int32_t, htonl) -#define SERIALIZE_INT64(field_name) SERIALIZE_FIELD(field_name, int64_t, htonq) - -#define DESERIALIZE_FIELD(field_name, type, converter) \ - do { \ - if ((offset + sizeof(field_name)) > length) \ - return -1; \ - field_name = converter(*((type*)(data + offset))); \ - offset += sizeof(field_name); \ - } while (0) -#define DESERIALIZE_INT16(field_name) DESERIALIZE_FIELD(field_name, int16_t, ntohs) -#define DESERIALIZE_INT32(field_name) DESERIALIZE_FIELD(field_name, int32_t, ntohl) -#define DESERIALIZE_INT64(field_name) DESERIALIZE_FIELD(field_name, int64_t, ntohq) - -#define kDevicePriorityShift 56 -#define kDeviceIDMask ((static_cast<uint64_t>(1) << kDevicePriorityShift) - 1) - -inline uint64_t packDeviceID(uint64_t devID, uint8_t prio) { - return (devID & kDeviceIDMask) | - (static_cast<uint64_t>(prio) << kDevicePriorityShift); -} - -inline uint64_t unpackDeviceID(uint64_t packed) { - return (packed & kDeviceIDMask); -} - -inline uint8_t unpackDevicePriority(uint64_t packed) { - return static_cast<uint8_t>(packed >> kDevicePriorityShift); -} - -ssize_t TimeServicePacketHeader::serializeHeader(uint8_t* data, - uint32_t length) { - ssize_t offset = 0; - int16_t pktType = static_cast<int16_t>(packetType); - SERIALIZE_INT32(magic); - SERIALIZE_INT16(version); - SERIALIZE_INT16(pktType); - SERIALIZE_INT64(timelineID); - SERIALIZE_INT64(syncGroupID); - return offset; -} - -ssize_t TimeServicePacketHeader::deserializeHeader(const uint8_t* data, - uint32_t length) { - ssize_t offset = 0; - int16_t tmp; - DESERIALIZE_INT32(magic); - DESERIALIZE_INT16(version); - DESERIALIZE_INT16(tmp); - DESERIALIZE_INT64(timelineID); - DESERIALIZE_INT64(syncGroupID); - packetType = static_cast<TimeServicePacketType>(tmp); - return offset; -} - -ssize_t TimeServicePacketHeader::serializePacket(uint8_t* data, - uint32_t length) { - ssize_t ret, tmp; - - ret = serializeHeader(data, length); - if (ret < 0) - return ret; - - data += ret; - length -= ret; - - switch (packetType) { - case TIME_PACKET_WHO_IS_MASTER_REQUEST: - tmp =((WhoIsMasterRequestPacket*)(this))->serializePacket(data, - length); - break; - case TIME_PACKET_WHO_IS_MASTER_RESPONSE: - tmp =((WhoIsMasterResponsePacket*)(this))->serializePacket(data, - length); - break; - case TIME_PACKET_SYNC_REQUEST: - tmp =((SyncRequestPacket*)(this))->serializePacket(data, length); - break; - case TIME_PACKET_SYNC_RESPONSE: - tmp =((SyncResponsePacket*)(this))->serializePacket(data, length); - break; - case TIME_PACKET_MASTER_ANNOUNCEMENT: - tmp =((MasterAnnouncementPacket*)(this))->serializePacket(data, - length); - break; - default: - return -1; - } - - if (tmp < 0) - return tmp; - - return ret + tmp; -} - -ssize_t UniversalTimeServicePacket::deserializePacket( - const uint8_t* data, - uint32_t length, - uint64_t expectedSyncGroupID) { - ssize_t ret; - TimeServicePacketHeader* header; - if (length < 8) - return -1; - - packetType = ntohs(*((uint16_t*)(data + 6))); - switch (packetType) { - case TIME_PACKET_WHO_IS_MASTER_REQUEST: - ret = p.who_is_master_request.deserializePacket(data, length); - header = &p.who_is_master_request; - break; - case TIME_PACKET_WHO_IS_MASTER_RESPONSE: - ret = p.who_is_master_response.deserializePacket(data, length); - header = &p.who_is_master_response; - break; - case TIME_PACKET_SYNC_REQUEST: - ret = p.sync_request.deserializePacket(data, length); - header = &p.sync_request; - break; - case TIME_PACKET_SYNC_RESPONSE: - ret = p.sync_response.deserializePacket(data, length); - header = &p.sync_response; - break; - case TIME_PACKET_MASTER_ANNOUNCEMENT: - ret = p.master_announcement.deserializePacket(data, length); - header = &p.master_announcement; - break; - default: - return -1; - } - - if ((ret >= 0) && !header->checkPacket(expectedSyncGroupID)) - ret = -1; - - return ret; -} - -ssize_t WhoIsMasterRequestPacket::serializePacket(uint8_t* data, - uint32_t length) { - ssize_t offset = serializeHeader(data, length); - if (offset > 0) { - uint64_t packed = packDeviceID(senderDeviceID, senderDevicePriority); - SERIALIZE_INT64(packed); - } - return offset; -} - -ssize_t WhoIsMasterRequestPacket::deserializePacket(const uint8_t* data, - uint32_t length) { - ssize_t offset = deserializeHeader(data, length); - if (offset > 0) { - uint64_t packed; - DESERIALIZE_INT64(packed); - senderDeviceID = unpackDeviceID(packed); - senderDevicePriority = unpackDevicePriority(packed); - } - return offset; -} - -ssize_t WhoIsMasterResponsePacket::serializePacket(uint8_t* data, - uint32_t length) { - ssize_t offset = serializeHeader(data, length); - if (offset > 0) { - uint64_t packed = packDeviceID(deviceID, devicePriority); - SERIALIZE_INT64(packed); - } - return offset; -} - -ssize_t WhoIsMasterResponsePacket::deserializePacket(const uint8_t* data, - uint32_t length) { - ssize_t offset = deserializeHeader(data, length); - if (offset > 0) { - uint64_t packed; - DESERIALIZE_INT64(packed); - deviceID = unpackDeviceID(packed); - devicePriority = unpackDevicePriority(packed); - } - return offset; -} - -ssize_t SyncRequestPacket::serializePacket(uint8_t* data, - uint32_t length) { - ssize_t offset = serializeHeader(data, length); - if (offset > 0) { - SERIALIZE_INT64(clientTxLocalTime); - } - return offset; -} - -ssize_t SyncRequestPacket::deserializePacket(const uint8_t* data, - uint32_t length) { - ssize_t offset = deserializeHeader(data, length); - if (offset > 0) { - DESERIALIZE_INT64(clientTxLocalTime); - } - return offset; -} - -ssize_t SyncResponsePacket::serializePacket(uint8_t* data, - uint32_t length) { - ssize_t offset = serializeHeader(data, length); - if (offset > 0) { - SERIALIZE_INT64(clientTxLocalTime); - SERIALIZE_INT64(masterRxCommonTime); - SERIALIZE_INT64(masterTxCommonTime); - SERIALIZE_INT32(nak); - } - return offset; -} - -ssize_t SyncResponsePacket::deserializePacket(const uint8_t* data, - uint32_t length) { - ssize_t offset = deserializeHeader(data, length); - if (offset > 0) { - DESERIALIZE_INT64(clientTxLocalTime); - DESERIALIZE_INT64(masterRxCommonTime); - DESERIALIZE_INT64(masterTxCommonTime); - DESERIALIZE_INT32(nak); - } - return offset; -} - -ssize_t MasterAnnouncementPacket::serializePacket(uint8_t* data, - uint32_t length) { - ssize_t offset = serializeHeader(data, length); - if (offset > 0) { - uint64_t packed = packDeviceID(deviceID, devicePriority); - SERIALIZE_INT64(packed); - } - return offset; -} - -ssize_t MasterAnnouncementPacket::deserializePacket(const uint8_t* data, - uint32_t length) { - ssize_t offset = deserializeHeader(data, length); - if (offset > 0) { - uint64_t packed; - DESERIALIZE_INT64(packed); - deviceID = unpackDeviceID(packed); - devicePriority = unpackDevicePriority(packed); - } - return offset; -} - -} // namespace android - diff --git a/services/common_time/common_time_server_packets.h b/services/common_time/common_time_server_packets.h deleted file mode 100644 index 57ba8a2..0000000 --- a/services/common_time/common_time_server_packets.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#ifndef ANDROID_COMMON_TIME_SERVER_PACKETS_H -#define ANDROID_COMMON_TIME_SERVER_PACKETS_H - -#include <stdint.h> -#include <common_time/ICommonClock.h> - -namespace android { - -/***** time sync protocol packets *****/ - -enum TimeServicePacketType { - TIME_PACKET_WHO_IS_MASTER_REQUEST = 1, - TIME_PACKET_WHO_IS_MASTER_RESPONSE, - TIME_PACKET_SYNC_REQUEST, - TIME_PACKET_SYNC_RESPONSE, - TIME_PACKET_MASTER_ANNOUNCEMENT, -}; - -class TimeServicePacketHeader { - public: - friend class UniversalTimeServicePacket; - // magic number identifying the protocol - uint32_t magic; - - // protocol version of the packet - uint16_t version; - - // type of the packet - TimeServicePacketType packetType; - - // the timeline ID - uint64_t timelineID; - - // synchronization group this packet belongs to (used to operate multiple - // synchronization domains which all use the same master election endpoint) - uint64_t syncGroupID; - - ssize_t serializePacket(uint8_t* data, uint32_t length); - - protected: - void initHeader(TimeServicePacketType type, - const uint64_t tlID, - const uint64_t groupID) { - magic = kMagic; - version = kCurVersion; - packetType = type; - timelineID = tlID; - syncGroupID = groupID; - } - - bool checkPacket(uint64_t expectedSyncGroupID) const { - return ((magic == kMagic) && - (version == kCurVersion) && - (!expectedSyncGroupID || (syncGroupID == expectedSyncGroupID))); - } - - ssize_t serializeHeader(uint8_t* data, uint32_t length); - ssize_t deserializeHeader(const uint8_t* data, uint32_t length); - - private: - static const uint32_t kMagic; - static const uint16_t kCurVersion; -}; - -// packet querying for a suitable master -class WhoIsMasterRequestPacket : public TimeServicePacketHeader { - public: - uint64_t senderDeviceID; - uint8_t senderDevicePriority; - - void initHeader(const uint64_t groupID) { - TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_REQUEST, - ICommonClock::kInvalidTimelineID, - groupID); - } - - ssize_t serializePacket(uint8_t* data, uint32_t length); - ssize_t deserializePacket(const uint8_t* data, uint32_t length); -}; - -// response to a WhoIsMaster request -class WhoIsMasterResponsePacket : public TimeServicePacketHeader { - public: - uint64_t deviceID; - uint8_t devicePriority; - - void initHeader(const uint64_t tlID, const uint64_t groupID) { - TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_RESPONSE, - tlID, groupID); - } - - ssize_t serializePacket(uint8_t* data, uint32_t length); - ssize_t deserializePacket(const uint8_t* data, uint32_t length); -}; - -// packet sent by a client requesting correspondence between local -// and common time -class SyncRequestPacket : public TimeServicePacketHeader { - public: - // local time when this request was transmitted - int64_t clientTxLocalTime; - - void initHeader(const uint64_t tlID, const uint64_t groupID) { - TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_REQUEST, - tlID, groupID); - } - - ssize_t serializePacket(uint8_t* data, uint32_t length); - ssize_t deserializePacket(const uint8_t* data, uint32_t length); -}; - -// response to a sync request sent by the master -class SyncResponsePacket : public TimeServicePacketHeader { - public: - // local time when this request was transmitted by the client - int64_t clientTxLocalTime; - - // common time when the master received the request - int64_t masterRxCommonTime; - - // common time when the master transmitted the response - int64_t masterTxCommonTime; - - // flag that is set if the recipient of the sync request is not acting - // as a master for the requested timeline - uint32_t nak; - - void initHeader(const uint64_t tlID, const uint64_t groupID) { - TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_RESPONSE, - tlID, groupID); - } - - ssize_t serializePacket(uint8_t* data, uint32_t length); - ssize_t deserializePacket(const uint8_t* data, uint32_t length); -}; - -// announcement of the master's presence -class MasterAnnouncementPacket : public TimeServicePacketHeader { - public: - // the master's device ID - uint64_t deviceID; - uint8_t devicePriority; - - void initHeader(const uint64_t tlID, const uint64_t groupID) { - TimeServicePacketHeader::initHeader(TIME_PACKET_MASTER_ANNOUNCEMENT, - tlID, groupID); - } - - ssize_t serializePacket(uint8_t* data, uint32_t length); - ssize_t deserializePacket(const uint8_t* data, uint32_t length); -}; - -class UniversalTimeServicePacket { - public: - uint16_t packetType; - union { - WhoIsMasterRequestPacket who_is_master_request; - WhoIsMasterResponsePacket who_is_master_response; - SyncRequestPacket sync_request; - SyncResponsePacket sync_response; - MasterAnnouncementPacket master_announcement; - } p; - - ssize_t deserializePacket(const uint8_t* data, - uint32_t length, - uint64_t expectedSyncGroupID); -}; - -}; // namespace android - -#endif // ANDROID_COMMON_TIME_SERVER_PACKETS_H - - diff --git a/services/common_time/diag_thread.cpp b/services/common_time/diag_thread.cpp deleted file mode 100644 index 4cb9551..0000000 --- a/services/common_time/diag_thread.cpp +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "common_time" -#include <utils/Log.h> - -#include <fcntl.h> -#include <linux/in.h> -#include <linux/tcp.h> -#include <poll.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> -#include <utils/Errors.h> -#include <utils/misc.h> - -#include <common_time/local_clock.h> - -#include "common_clock.h" -#include "diag_thread.h" - -#define kMaxEvents 16 -#define kListenPort 9876 - -static bool setNonblocking(int fd) { - int flags = fcntl(fd, F_GETFL); - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { - ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)", - fd, errno); - return false; - } - - return true; -} - -static bool setNodelay(int fd) { - int tmp = 1; - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)) < 0) { - ALOGE("Failed to set socket (%d) to no-delay mode (errno %d)", - fd, errno); - return false; - } - - return true; -} - -namespace android { - -DiagThread::DiagThread(CommonClock* common_clock, LocalClock* local_clock) { - common_clock_ = common_clock; - local_clock_ = local_clock; - listen_fd_ = -1; - data_fd_ = -1; - kernel_logID_basis_known_ = false; - discipline_log_ID_ = 0; -} - -DiagThread::~DiagThread() { -} - -status_t DiagThread::startWorkThread() { - status_t res; - stopWorkThread(); - res = run("Diag"); - - if (res != OK) - ALOGE("Failed to start work thread (res = %d)", res); - - return res; -} - -void DiagThread::stopWorkThread() { - status_t res; - res = requestExitAndWait(); // block until thread exit. - if (res != OK) - ALOGE("Failed to stop work thread (res = %d)", res); -} - -bool DiagThread::openListenSocket() { - bool ret = false; - int flags; - cleanupListenSocket(); - - if ((listen_fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { - ALOGE("Socket failed."); - goto bailout; - } - - // Set non-blocking operation - if (!setNonblocking(listen_fd_)) - goto bailout; - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(kListenPort); - - if (bind(listen_fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) { - ALOGE("Bind failed."); - goto bailout; - } - - if (listen(listen_fd_, 1) < 0) { - ALOGE("Listen failed."); - goto bailout; - } - - ret = true; -bailout: - if (!ret) - cleanupListenSocket(); - - return ret; -} - -void DiagThread::cleanupListenSocket() { - if (listen_fd_ >= 0) { - int res; - - struct linger l; - l.l_onoff = 1; - l.l_linger = 0; - - setsockopt(listen_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l)); - shutdown(listen_fd_, SHUT_RDWR); - close(listen_fd_); - listen_fd_ = -1; - } -} - -void DiagThread::cleanupDataSocket() { - if (data_fd_ >= 0) { - int res; - - struct linger l; - l.l_onoff = 1; - l.l_linger = 0; - - setsockopt(data_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l)); - shutdown(data_fd_, SHUT_RDWR); - close(data_fd_); - data_fd_ = -1; - } -} - -void DiagThread::resetLogIDs() { - // Drain and discard all of the events from the kernel - struct local_time_debug_event events[kMaxEvents]; - while(local_clock_->getDebugLog(events, kMaxEvents) > 0) - ; - - { - Mutex::Autolock lock(&discipline_log_lock_); - discipline_log_.clear(); - discipline_log_ID_ = 0; - } - - kernel_logID_basis_known_ = false; -} - -void DiagThread::pushDisciplineEvent(int64_t observed_local_time, - int64_t observed_common_time, - int64_t nominal_common_time, - int32_t total_correction, - int32_t rtt) { - Mutex::Autolock lock(&discipline_log_lock_); - - DisciplineEventRecord evt; - - evt.event_id = discipline_log_ID_++; - - evt.action_local_time = local_clock_->getLocalTime(); - common_clock_->localToCommon(evt.action_local_time, - &evt.action_common_time); - - evt.observed_local_time = observed_local_time; - evt.observed_common_time = observed_common_time; - evt.nominal_common_time = nominal_common_time; - evt.total_correction = total_correction; - evt.rtt = rtt; - - discipline_log_.push_back(evt); - while (discipline_log_.size() > kMaxDisciplineLogSize) - discipline_log_.erase(discipline_log_.begin()); -} - -bool DiagThread::threadLoop() { - struct pollfd poll_fds[1]; - - if (!openListenSocket()) { - ALOGE("Failed to open listen socket"); - goto bailout; - } - - while (!exitPending()) { - memset(&poll_fds, 0, sizeof(poll_fds)); - - if (data_fd_ < 0) { - poll_fds[0].fd = listen_fd_; - poll_fds[0].events = POLLIN; - } else { - poll_fds[0].fd = data_fd_; - poll_fds[0].events = POLLRDHUP | POLLIN; - } - - int poll_res = poll(poll_fds, NELEM(poll_fds), 50); - if (poll_res < 0) { - ALOGE("Fatal error (%d,%d) while waiting on events", - poll_res, errno); - goto bailout; - } - - if (exitPending()) - break; - - if (poll_fds[0].revents) { - if (poll_fds[0].fd == listen_fd_) { - data_fd_ = accept(listen_fd_, NULL, NULL); - - if (data_fd_ < 0) { - ALOGW("Failed accept on socket %d with err %d", - listen_fd_, errno); - } else { - if (!setNonblocking(data_fd_)) - cleanupDataSocket(); - if (!setNodelay(data_fd_)) - cleanupDataSocket(); - } - } else - if (poll_fds[0].fd == data_fd_) { - if (poll_fds[0].revents & POLLRDHUP) { - // Connection hung up; time to clean up. - cleanupDataSocket(); - } else - if (poll_fds[0].revents & POLLIN) { - uint8_t cmd; - if (read(data_fd_, &cmd, sizeof(cmd)) > 0) { - switch(cmd) { - case 'r': - case 'R': - resetLogIDs(); - break; - } - } - } - } - } - - struct local_time_debug_event events[kMaxEvents]; - int amt = local_clock_->getDebugLog(events, kMaxEvents); - - if (amt > 0) { - for (int i = 0; i < amt; i++) { - struct local_time_debug_event& e = events[i]; - - if (!kernel_logID_basis_known_) { - kernel_logID_basis_ = e.local_timesync_event_id; - kernel_logID_basis_known_ = true; - } - - char buf[1024]; - int64_t common_time; - status_t res = common_clock_->localToCommon(e.local_time, - &common_time); - snprintf(buf, sizeof(buf), "E,%lld,%lld,%lld,%d\n", - e.local_timesync_event_id - kernel_logID_basis_, - e.local_time, - common_time, - (OK == res) ? 1 : 0); - buf[sizeof(buf) - 1] = 0; - - if (data_fd_ >= 0) - write(data_fd_, buf, strlen(buf)); - } - } - - { // scope for autolock pattern - Mutex::Autolock lock(&discipline_log_lock_); - - while (discipline_log_.size() > 0) { - char buf[1024]; - DisciplineEventRecord& e = *discipline_log_.begin(); - snprintf(buf, sizeof(buf), - "D,%lld,%lld,%lld,%lld,%lld,%lld,%d,%d\n", - e.event_id, - e.action_local_time, - e.action_common_time, - e.observed_local_time, - e.observed_common_time, - e.nominal_common_time, - e.total_correction, - e.rtt); - buf[sizeof(buf) - 1] = 0; - - if (data_fd_ >= 0) - write(data_fd_, buf, strlen(buf)); - - discipline_log_.erase(discipline_log_.begin()); - } - } - } - -bailout: - cleanupDataSocket(); - cleanupListenSocket(); - return false; -} - -} // namespace android diff --git a/services/common_time/diag_thread.h b/services/common_time/diag_thread.h deleted file mode 100644 index c630e0d..0000000 --- a/services/common_time/diag_thread.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __DIAG_THREAD_H__ -#define __DIAG_THREAD_H__ - -#include <utils/List.h> -#include <utils/threads.h> - -namespace android { - -class CommonClock; -class LocalClock; - -class DiagThread : public Thread { - public: - DiagThread(CommonClock* common_clock, LocalClock* local_clock); - ~DiagThread(); - - status_t startWorkThread(); - void stopWorkThread(); - virtual bool threadLoop(); - - void pushDisciplineEvent(int64_t observed_local_time, - int64_t observed_common_time, - int64_t nominal_common_time, - int32_t total_correction, - int32_t rtt); - - private: - typedef struct { - int64_t event_id; - int64_t action_local_time; - int64_t action_common_time; - int64_t observed_local_time; - int64_t observed_common_time; - int64_t nominal_common_time; - int32_t total_correction; - int32_t rtt; - } DisciplineEventRecord; - - bool openListenSocket(); - void cleanupListenSocket(); - void cleanupDataSocket(); - void resetLogIDs(); - - CommonClock* common_clock_; - LocalClock* local_clock_; - int listen_fd_; - int data_fd_; - - int64_t kernel_logID_basis_; - bool kernel_logID_basis_known_; - - static const size_t kMaxDisciplineLogSize = 16; - Mutex discipline_log_lock_; - List<DisciplineEventRecord> discipline_log_; - int64_t discipline_log_ID_; -}; - -} // namespace android - -#endif //__ DIAG_THREAD_H__ diff --git a/services/common_time/main.cpp b/services/common_time/main.cpp deleted file mode 100644 index 49eb30a..0000000 --- a/services/common_time/main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 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. - */ - -/* - * A service that exchanges time synchronization information between - * a master that defines a timeline and clients that follow the timeline. - */ - -#define LOG_TAG "common_time" -#include <utils/Log.h> - -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> - -#include "common_time_server.h" - -int main(int argc, char *argv[]) { - using namespace android; - - sp<CommonTimeServer> service = new CommonTimeServer(); - if (service == NULL) - return 1; - - ProcessState::self()->startThreadPool(); - service->run("CommonTimeServer", ANDROID_PRIORITY_NORMAL); - - IPCThreadState::self()->joinThreadPool(); - return 0; -} - diff --git a/services/common_time/utils.cpp b/services/common_time/utils.cpp deleted file mode 100644 index ed2c77d..0000000 --- a/services/common_time/utils.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#define LOG_TAG "common_time" -#include <utils/Log.h> - -#include "utils.h" - -namespace android { - -void Timeout::setTimeout(int msec) { - if (msec < 0) { - mSystemEndTime = 0; - return; - } - - mSystemEndTime = systemTime() + (static_cast<nsecs_t>(msec) * 1000000); -} - -int Timeout::msecTillTimeout(nsecs_t nowTime) { - if (!mSystemEndTime) { - return -1; - } - - if (mSystemEndTime < nowTime) { - return 0; - } - - nsecs_t delta = mSystemEndTime - nowTime; - delta += 999999; - delta /= 1000000; - if (delta > 0x7FFFFFFF) { - return 0x7FFFFFFF; - } - - return static_cast<int>(delta); -} - -LogRing::LogRing(const char* header, size_t entries) - : mSize(entries) - , mWr(0) - , mIsFull(false) - , mHeader(header) { - mRingBuffer = new Entry[mSize]; - if (NULL == mRingBuffer) - ALOGE("Failed to allocate log ring with %u entries.", mSize); -} - -LogRing::~LogRing() { - if (NULL != mRingBuffer) - delete[] mRingBuffer; -} - -void LogRing::log(int prio, const char* tag, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - internalLog(prio, tag, fmt, argp); - va_end(argp); -} - -void LogRing::log(const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - internalLog(0, NULL, fmt, argp); - va_end(argp); -} - -void LogRing::internalLog(int prio, - const char* tag, - const char* fmt, - va_list argp) { - if (NULL != mRingBuffer) { - Mutex::Autolock lock(&mLock); - String8 s(String8::formatV(fmt, argp)); - Entry* last = NULL; - - if (mIsFull || mWr) - last = &(mRingBuffer[(mWr + mSize - 1) % mSize]); - - - if ((NULL != last) && !last->s.compare(s)) { - gettimeofday(&(last->last_ts), NULL); - ++last->count; - } else { - gettimeofday(&mRingBuffer[mWr].first_ts, NULL); - mRingBuffer[mWr].last_ts = mRingBuffer[mWr].first_ts; - mRingBuffer[mWr].count = 1; - mRingBuffer[mWr].s.setTo(s); - - mWr = (mWr + 1) % mSize; - if (!mWr) - mIsFull = true; - } - } - - if (NULL != tag) - LOG_PRI_VA(prio, tag, fmt, argp); -} - -void LogRing::dumpLog(int fd) { - if (NULL == mRingBuffer) - return; - - Mutex::Autolock lock(&mLock); - - if (!mWr && !mIsFull) - return; - - char buf[1024]; - int res; - size_t start = mIsFull ? mWr : 0; - size_t count = mIsFull ? mSize : mWr; - static const char* kTimeFmt = "%a %b %d %Y %H:%M:%S"; - - res = snprintf(buf, sizeof(buf), "\n%s\n", mHeader); - if (res > 0) - write(fd, buf, res); - - for (size_t i = 0; i < count; ++i) { - struct tm t; - char timebuf[64]; - char repbuf[96]; - size_t ndx = (start + i) % mSize; - - if (1 != mRingBuffer[ndx].count) { - localtime_r(&mRingBuffer[ndx].last_ts.tv_sec, &t); - strftime(timebuf, sizeof(timebuf), kTimeFmt, &t); - snprintf(repbuf, sizeof(repbuf), - " (repeated %d times, last was %s.%03ld)", - mRingBuffer[ndx].count, - timebuf, - mRingBuffer[ndx].last_ts.tv_usec / 1000); - repbuf[sizeof(repbuf) - 1] = 0; - } else { - repbuf[0] = 0; - } - - localtime_r(&mRingBuffer[ndx].first_ts.tv_sec, &t); - strftime(timebuf, sizeof(timebuf), kTimeFmt, &t); - res = snprintf(buf, sizeof(buf), "[%2d] %s.%03ld :: %s%s\n", - i, timebuf, - mRingBuffer[ndx].first_ts.tv_usec / 1000, - mRingBuffer[ndx].s.string(), - repbuf); - - if (res > 0) - write(fd, buf, res); - } -} - -} // namespace android diff --git a/services/common_time/utils.h b/services/common_time/utils.h deleted file mode 100644 index c28cf0a..0000000 --- a/services/common_time/utils.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#ifndef __UTILS_H__ -#define __UTILS_H__ - -#include <stdint.h> -#include <unistd.h> - -#include <utils/String8.h> -#include <utils/threads.h> -#include <utils/Timers.h> - -namespace android { - -class Timeout { - public: - Timeout() : mSystemEndTime(0) { } - - // Set a timeout which should occur msec milliseconds from now. - // Negative values will cancel any current timeout; - void setTimeout(int msec); - - // Return the number of milliseconds until the timeout occurs, or -1 if - // no timeout is scheduled. - int msecTillTimeout(nsecs_t nowTime); - int msecTillTimeout() { return msecTillTimeout(systemTime()); } - - private: - // The systemTime() at which the timeout will be complete, or 0 if no - // timeout is currently scheduled. - nsecs_t mSystemEndTime; -}; - -class LogRing { - public: - LogRing(const char* header, size_t entries); - ~LogRing(); - - // Send a log message to logcat as well as storing it in the ring buffer. - void log(int prio, const char* tag, const char* fmt, ...); - - // Add a log message the ring buffer, do not send the message to logcat. - void log(const char* fmt, ...); - - // Dump the log to an fd (dumpsys style) - void dumpLog(int fd); - - private: - class Entry { - public: - uint32_t count; - struct timeval first_ts; - struct timeval last_ts; - String8 s; - }; - - Mutex mLock; - Entry* mRingBuffer; - size_t mSize; - size_t mWr; - bool mIsFull; - const char* mHeader; - - void internalLog(int prio, const char* tag, const char* fmt, va_list va); -}; - -} // namespace android - -#endif // __UTILS_H__ diff --git a/services/core/Android.mk b/services/core/Android.mk new file mode 100644 index 0000000..5c45201 --- /dev/null +++ b/services/core/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.core + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) \ + java/com/android/server/EventLogTags.logtags \ + java/com/android/server/am/EventLogTags.logtags + +LOCAL_JAVA_LIBRARIES := android.policy telephony-common + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 5ae9a6d..96063d5 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -31,6 +31,7 @@ import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; @@ -64,54 +65,51 @@ import static android.app.AlarmManager.ELAPSED_REALTIME; import com.android.internal.util.LocalLog; -class AlarmManagerService extends IAlarmManager.Stub { +class AlarmManagerService extends SystemService { // The threshold for how long an alarm can be late before we print a // warning message. The time duration is in milliseconds. private static final long LATE_ALARM_THRESHOLD = 10 * 1000; private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP; private static final int RTC_MASK = 1 << RTC; - private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; + private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME; - private static final int TIME_CHANGED_MASK = 1 << 16; - private static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK; + static final int TIME_CHANGED_MASK = 1 << 16; + static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK; // Mask for testing whether a given alarm type is wakeup vs non-wakeup - private static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup - - private static final String TAG = "AlarmManager"; - private static final String ClockReceiver_TAG = "ClockReceiver"; - private static final boolean localLOGV = false; - private static final boolean DEBUG_BATCH = localLOGV || false; - private static final boolean DEBUG_VALIDATE = localLOGV || false; - private static final int ALARM_EVENT = 1; - private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; + static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup + + static final String TAG = "AlarmManager"; + static final String ClockReceiver_TAG = "ClockReceiver"; + static final boolean localLOGV = false; + static final boolean DEBUG_BATCH = localLOGV || false; + static final boolean DEBUG_VALIDATE = localLOGV || false; + static final int ALARM_EVENT = 1; + static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; - private static final Intent mBackgroundIntent + static final Intent mBackgroundIntent = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND); - private static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder(); + static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder(); - private static final boolean WAKEUP_STATS = false; + static final boolean WAKEUP_STATS = false; - private final Context mContext; + final LocalLog mLog = new LocalLog(TAG); - private final LocalLog mLog = new LocalLog(TAG); + final Object mLock = new Object(); - private Object mLock = new Object(); - - private int mDescriptor; + long mNativeData; private long mNextWakeup; private long mNextNonWakeup; - private int mBroadcastRefCount = 0; - private PowerManager.WakeLock mWakeLock; - private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>(); - private final AlarmThread mWaitThread = new AlarmThread(); - private final AlarmHandler mHandler = new AlarmHandler(); - private ClockReceiver mClockReceiver; + int mBroadcastRefCount = 0; + PowerManager.WakeLock mWakeLock; + ArrayList<InFlight> mInFlight = new ArrayList<InFlight>(); + final AlarmHandler mHandler = new AlarmHandler(); + ClockReceiver mClockReceiver; private UninstallReceiver mUninstallReceiver; - private final ResultReceiver mResultReceiver = new ResultReceiver(); - private final PendingIntent mTimeTickSender; - private final PendingIntent mDateChangeSender; + final ResultReceiver mResultReceiver = new ResultReceiver(); + PendingIntent mTimeTickSender; + PendingIntent mDateChangeSender; class WakeupEvent { public long when; @@ -125,8 +123,8 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - private final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>(); - private final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day + final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>(); + final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day static final class Batch { long start; // These endpoints are always in ELAPSED @@ -317,9 +315,13 @@ class AlarmManagerService extends IAlarmManager.Stub { } // minimum recurrence period or alarm futurity for us to be able to fuzz it - private static final long MIN_FUZZABLE_INTERVAL = 10000; - private static final BatchTimeOrder sBatchOrder = new BatchTimeOrder(); - private final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>(); + static final long MIN_FUZZABLE_INTERVAL = 10000; + static final BatchTimeOrder sBatchOrder = new BatchTimeOrder(); + final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>(); + + public AlarmManagerService(Context context) { + super(context); + } static long convertToElapsed(long when, int type) { final boolean isRtc = (type == RTC || type == RTC_WAKEUP); @@ -403,7 +405,7 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - private static final class InFlight extends Intent { + static final class InFlight extends Intent { final PendingIntent mPendingIntent; final WorkSource mWorkSource; final Pair<String, ComponentName> mTarget; @@ -427,7 +429,7 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - private static final class FilterStats { + static final class FilterStats { final BroadcastStats mBroadcastStats; final Pair<String, ComponentName> mTarget; @@ -443,7 +445,7 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - private static final class BroadcastStats { + static final class BroadcastStats { final String mPackageName; long aggregateTime; @@ -459,68 +461,101 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - private final HashMap<String, BroadcastStats> mBroadcastStats + final HashMap<String, BroadcastStats> mBroadcastStats = new HashMap<String, BroadcastStats>(); - public AlarmManagerService(Context context) { - mContext = context; - mDescriptor = init(); + @Override + public void onStart() { + mNativeData = init(); mNextWakeup = mNextNonWakeup = 0; // We have to set current TimeZone info to kernel // because kernel doesn't keep this after reboot - String tz = SystemProperties.get(TIMEZONE_PROPERTY); - if (tz != null) { - setTimeZone(tz); - } + setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY)); - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0, + mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0, new Intent(Intent.ACTION_TIME_TICK).addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND), 0, UserHandle.ALL); Intent intent = new Intent(Intent.ACTION_DATE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - mDateChangeSender = PendingIntent.getBroadcastAsUser(context, 0, intent, + mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent, Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL); // now that we have initied the driver schedule the alarm - mClockReceiver= new ClockReceiver(); + mClockReceiver = new ClockReceiver(); mClockReceiver.scheduleTimeTickEvent(); mClockReceiver.scheduleDateChangedEvent(); mUninstallReceiver = new UninstallReceiver(); - if (mDescriptor != -1) { - mWaitThread.start(); + if (mNativeData != 0) { + AlarmThread waitThread = new AlarmThread(); + waitThread.start(); } else { Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler."); } + + publishBinderService(Context.ALARM_SERVICE, mService); } - + + @Override protected void finalize() throws Throwable { try { - close(mDescriptor); + close(mNativeData); } finally { super.finalize(); } } - @Override - public void set(int type, long triggerAtTime, long windowLength, long interval, - PendingIntent operation, WorkSource workSource) { - if (workSource != null) { - mContext.enforceCallingPermission( - android.Manifest.permission.UPDATE_DEVICE_STATS, - "AlarmManager.set"); + void setTimeZoneImpl(String tz) { + if (TextUtils.isEmpty(tz)) { + return; } - set(type, triggerAtTime, windowLength, interval, operation, false, workSource); + TimeZone zone = TimeZone.getTimeZone(tz); + // Prevent reentrant calls from stepping on each other when writing + // the time zone property + boolean timeZoneWasChanged = false; + synchronized (this) { + String current = SystemProperties.get(TIMEZONE_PROPERTY); + if (current == null || !current.equals(zone.getID())) { + if (localLOGV) { + Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID()); + } + timeZoneWasChanged = true; + SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); + } + + // Update the kernel timezone information + // Kernel tracks time offsets as 'minutes west of GMT' + int gmtOffset = zone.getOffset(System.currentTimeMillis()); + setKernelTimezone(mNativeData, -(gmtOffset / 60000)); + } + + TimeZone.setDefault(null); + + if (timeZoneWasChanged) { + Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + intent.putExtra("time-zone", zone.getID()); + getContext().sendBroadcastAsUser(intent, UserHandle.ALL); + } } - public void set(int type, long triggerAtTime, long windowLength, long interval, + void removeImpl(PendingIntent operation) { + if (operation == null) { + return; + } + synchronized (mLock) { + removeLocked(operation); + } + } + + void setImpl(int type, long triggerAtTime, long windowLength, long interval, PendingIntent operation, boolean isStandalone, WorkSource workSource) { if (operation == null) { Slog.w(TAG, "set/setRepeating ignored because there is no intent"); @@ -606,231 +641,64 @@ class AlarmManagerService extends IAlarmManager.Stub { rescheduleKernelAlarmsLocked(); } - private void logBatchesLocked() { - ByteArrayOutputStream bs = new ByteArrayOutputStream(2048); - PrintWriter pw = new PrintWriter(bs); - final long nowRTC = System.currentTimeMillis(); - final long nowELAPSED = SystemClock.elapsedRealtime(); - final int NZ = mAlarmBatches.size(); - for (int iz = 0; iz < NZ; iz++) { - Batch bz = mAlarmBatches.get(iz); - pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz); - dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC); - pw.flush(); - Slog.v(TAG, bs.toString()); - bs.reset(); - } - } - - private boolean validateConsistencyLocked() { - if (DEBUG_VALIDATE) { - long lastTime = Long.MIN_VALUE; - final int N = mAlarmBatches.size(); - for (int i = 0; i < N; i++) { - Batch b = mAlarmBatches.get(i); - if (b.start >= lastTime) { - // duplicate start times are okay because of standalone batches - lastTime = b.start; - } else { - Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order"); - logBatchesLocked(); - return false; - } - } - } - return true; - } - - private Batch findFirstWakeupBatchLocked() { - final int N = mAlarmBatches.size(); - for (int i = 0; i < N; i++) { - Batch b = mAlarmBatches.get(i); - if (b.hasWakeups()) { - return b; + private final IBinder mService = new IAlarmManager.Stub() { + @Override + public void set(int type, long triggerAtTime, long windowLength, long interval, + PendingIntent operation, WorkSource workSource) { + if (workSource != null) { + getContext().enforceCallingPermission( + android.Manifest.permission.UPDATE_DEVICE_STATS, + "AlarmManager.set"); } - } - return null; - } - private void rescheduleKernelAlarmsLocked() { - // Schedule the next upcoming wakeup alarm. If there is a deliverable batch - // prior to that which contains no wakeups, we schedule that as well. - if (mAlarmBatches.size() > 0) { - final Batch firstWakeup = findFirstWakeupBatchLocked(); - final Batch firstBatch = mAlarmBatches.get(0); - if (firstWakeup != null && mNextWakeup != firstWakeup.start) { - mNextWakeup = firstWakeup.start; - setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start); - } - if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) { - mNextNonWakeup = firstBatch.start; - setLocked(ELAPSED_REALTIME, firstBatch.start); - } + setImpl(type, triggerAtTime, windowLength, interval, operation, + false, workSource); } - } - - public void setTime(long millis) { - mContext.enforceCallingOrSelfPermission( - "android.permission.SET_TIME", - "setTime"); - - SystemClock.setCurrentTimeMillis(millis); - } - - public void setTimeZone(String tz) { - mContext.enforceCallingOrSelfPermission( - "android.permission.SET_TIME_ZONE", - "setTimeZone"); - - long oldId = Binder.clearCallingIdentity(); - try { - if (TextUtils.isEmpty(tz)) return; - TimeZone zone = TimeZone.getTimeZone(tz); - // Prevent reentrant calls from stepping on each other when writing - // the time zone property - boolean timeZoneWasChanged = false; - synchronized (this) { - String current = SystemProperties.get(TIMEZONE_PROPERTY); - if (current == null || !current.equals(zone.getID())) { - if (localLOGV) { - Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID()); - } - timeZoneWasChanged = true; - SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); - } - - // Update the kernel timezone information - // Kernel tracks time offsets as 'minutes west of GMT' - int gmtOffset = zone.getOffset(System.currentTimeMillis()); - setKernelTimezone(mDescriptor, -(gmtOffset / 60000)); - } - - TimeZone.setDefault(null); - if (timeZoneWasChanged) { - Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - intent.putExtra("time-zone", zone.getID()); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } - } finally { - Binder.restoreCallingIdentity(oldId); - } - } - - public void remove(PendingIntent operation) { - if (operation == null) { - return; - } - synchronized (mLock) { - removeLocked(operation); - } - } - - public void removeLocked(PendingIntent operation) { - boolean didRemove = false; - for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { - Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(operation); - if (b.size() == 0) { - mAlarmBatches.remove(i); - } - } + @Override + public void setTime(long millis) { + getContext().enforceCallingOrSelfPermission( + "android.permission.SET_TIME", + "setTime"); - if (didRemove) { - if (DEBUG_BATCH) { - Slog.v(TAG, "remove(operation) changed bounds; rebatching"); - } - rebatchAllAlarmsLocked(true); - rescheduleKernelAlarmsLocked(); + SystemClock.setCurrentTimeMillis(millis); } - } - public void removeLocked(String packageName) { - boolean didRemove = false; - for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { - Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(packageName); - if (b.size() == 0) { - mAlarmBatches.remove(i); + @Override + public void setTimeZone(String tz) { + getContext().enforceCallingOrSelfPermission( + "android.permission.SET_TIME_ZONE", + "setTimeZone"); + + final long oldId = Binder.clearCallingIdentity(); + try { + setTimeZoneImpl(tz); + } finally { + Binder.restoreCallingIdentity(oldId); } } - if (didRemove) { - if (DEBUG_BATCH) { - Slog.v(TAG, "remove(package) changed bounds; rebatching"); - } - rebatchAllAlarmsLocked(true); - rescheduleKernelAlarmsLocked(); - } - } + @Override + public void remove(PendingIntent operation) { + removeImpl(operation); - public void removeUserLocked(int userHandle) { - boolean didRemove = false; - for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { - Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(userHandle); - if (b.size() == 0) { - mAlarmBatches.remove(i); - } } - if (didRemove) { - if (DEBUG_BATCH) { - Slog.v(TAG, "remove(user) changed bounds; rebatching"); + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump AlarmManager from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; } - rebatchAllAlarmsLocked(true); - rescheduleKernelAlarmsLocked(); - } - } - public boolean lookForPackageLocked(String packageName) { - for (int i = 0; i < mAlarmBatches.size(); i++) { - Batch b = mAlarmBatches.get(i); - if (b.hasPackage(packageName)) { - return true; - } + dumpImpl(pw); } - return false; - } + }; - private void setLocked(int type, long when) - { - if (mDescriptor != -1) - { - // The kernel never triggers alarms with negative wakeup times - // so we ensure they are positive. - long alarmSeconds, alarmNanoseconds; - if (when < 0) { - alarmSeconds = 0; - alarmNanoseconds = 0; - } else { - alarmSeconds = when / 1000; - alarmNanoseconds = (when % 1000) * 1000 * 1000; - } - - set(mDescriptor, type, alarmSeconds, alarmNanoseconds); - } - else - { - Message msg = Message.obtain(); - msg.what = ALARM_EVENT; - - mHandler.removeMessages(ALARM_EVENT); - mHandler.sendMessageAtTime(msg, when); - } - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump AlarmManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - + void dumpImpl(PrintWriter pw) { synchronized (mLock) { pw.println("Current Alarm Manager state:"); final long nowRTC = System.currentTimeMillis(); @@ -980,6 +848,159 @@ class AlarmManagerService extends IAlarmManager.Stub { } } + private void logBatchesLocked() { + ByteArrayOutputStream bs = new ByteArrayOutputStream(2048); + PrintWriter pw = new PrintWriter(bs); + final long nowRTC = System.currentTimeMillis(); + final long nowELAPSED = SystemClock.elapsedRealtime(); + final int NZ = mAlarmBatches.size(); + for (int iz = 0; iz < NZ; iz++) { + Batch bz = mAlarmBatches.get(iz); + pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz); + dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC); + pw.flush(); + Slog.v(TAG, bs.toString()); + bs.reset(); + } + } + + private boolean validateConsistencyLocked() { + if (DEBUG_VALIDATE) { + long lastTime = Long.MIN_VALUE; + final int N = mAlarmBatches.size(); + for (int i = 0; i < N; i++) { + Batch b = mAlarmBatches.get(i); + if (b.start >= lastTime) { + // duplicate start times are okay because of standalone batches + lastTime = b.start; + } else { + Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order"); + logBatchesLocked(); + return false; + } + } + } + return true; + } + + private Batch findFirstWakeupBatchLocked() { + final int N = mAlarmBatches.size(); + for (int i = 0; i < N; i++) { + Batch b = mAlarmBatches.get(i); + if (b.hasWakeups()) { + return b; + } + } + return null; + } + + void rescheduleKernelAlarmsLocked() { + // Schedule the next upcoming wakeup alarm. If there is a deliverable batch + // prior to that which contains no wakeups, we schedule that as well. + if (mAlarmBatches.size() > 0) { + final Batch firstWakeup = findFirstWakeupBatchLocked(); + final Batch firstBatch = mAlarmBatches.get(0); + if (firstWakeup != null && mNextWakeup != firstWakeup.start) { + mNextWakeup = firstWakeup.start; + setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start); + } + if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) { + mNextNonWakeup = firstBatch.start; + setLocked(ELAPSED_REALTIME, firstBatch.start); + } + } + } + + private void removeLocked(PendingIntent operation) { + boolean didRemove = false; + for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { + Batch b = mAlarmBatches.get(i); + didRemove |= b.remove(operation); + if (b.size() == 0) { + mAlarmBatches.remove(i); + } + } + + if (didRemove) { + if (DEBUG_BATCH) { + Slog.v(TAG, "remove(operation) changed bounds; rebatching"); + } + rebatchAllAlarmsLocked(true); + rescheduleKernelAlarmsLocked(); + } + } + + void removeLocked(String packageName) { + boolean didRemove = false; + for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { + Batch b = mAlarmBatches.get(i); + didRemove |= b.remove(packageName); + if (b.size() == 0) { + mAlarmBatches.remove(i); + } + } + + if (didRemove) { + if (DEBUG_BATCH) { + Slog.v(TAG, "remove(package) changed bounds; rebatching"); + } + rebatchAllAlarmsLocked(true); + rescheduleKernelAlarmsLocked(); + } + } + + void removeUserLocked(int userHandle) { + boolean didRemove = false; + for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { + Batch b = mAlarmBatches.get(i); + didRemove |= b.remove(userHandle); + if (b.size() == 0) { + mAlarmBatches.remove(i); + } + } + + if (didRemove) { + if (DEBUG_BATCH) { + Slog.v(TAG, "remove(user) changed bounds; rebatching"); + } + rebatchAllAlarmsLocked(true); + rescheduleKernelAlarmsLocked(); + } + } + + boolean lookForPackageLocked(String packageName) { + for (int i = 0; i < mAlarmBatches.size(); i++) { + Batch b = mAlarmBatches.get(i); + if (b.hasPackage(packageName)) { + return true; + } + } + return false; + } + + private void setLocked(int type, long when) { + if (mNativeData != 0) { + // The kernel never triggers alarms with negative wakeup times + // so we ensure they are positive. + long alarmSeconds, alarmNanoseconds; + if (when < 0) { + alarmSeconds = 0; + alarmNanoseconds = 0; + } else { + alarmSeconds = when / 1000; + alarmNanoseconds = (when % 1000) * 1000 * 1000; + } + + set(mNativeData, type, alarmSeconds, alarmNanoseconds); + } else { + Message msg = Message.obtain(); + msg.what = ALARM_EVENT; + + mHandler.removeMessages(ALARM_EVENT); + mHandler.sendMessageAtTime(msg, when); + } + } + private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, String prefix, String label, long now) { for (int i=list.size()-1; i>=0; i--) { @@ -1014,13 +1035,13 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - private native int init(); - private native void close(int fd); - private native void set(int fd, int type, long seconds, long nanoseconds); - private native int waitForAlarm(int fd); - private native int setKernelTimezone(int fd, int minuteswest); + private native long init(); + private native void close(long nativeData); + private native void set(long nativeData, int type, long seconds, long nanoseconds); + private native int waitForAlarm(long nativeData); + private native int setKernelTimezone(long nativeData, int minuteswest); - private void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) { + void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) { // batches are temporally sorted, so we need only pull from the // start of the list until we either empty it or hit a batch // that is not yet deliverable @@ -1158,7 +1179,7 @@ class AlarmManagerService extends IAlarmManager.Stub { while (true) { - int result = waitForAlarm(mDescriptor); + int result = waitForAlarm(mNativeData); triggerList.clear(); @@ -1166,13 +1187,13 @@ class AlarmManagerService extends IAlarmManager.Stub { if (DEBUG_BATCH) { Slog.v(TAG, "Time changed notification from kernel; rebatching"); } - remove(mTimeTickSender); + removeImpl(mTimeTickSender); rebatchAllAlarms(); mClockReceiver.scheduleTimeTickEvent(); Intent intent = new Intent(Intent.ACTION_TIME_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + getContext().sendBroadcastAsUser(intent, UserHandle.ALL); } synchronized (mLock) { @@ -1206,7 +1227,7 @@ class AlarmManagerService extends IAlarmManager.Stub { Alarm alarm = triggerList.get(i); try { if (localLOGV) Slog.v(TAG, "sending alarm " + alarm); - alarm.operation.send(mContext, 0, + alarm.operation.send(getContext(), 0, mBackgroundIntent.putExtra( Intent.EXTRA_ALARM_COUNT, alarm.count), mResultReceiver, mHandler); @@ -1248,7 +1269,7 @@ class AlarmManagerService extends IAlarmManager.Stub { if (alarm.repeatInterval > 0) { // This IntentSender is no longer valid, but this // is a repeating alarm, so toss the hoser. - remove(alarm.operation); + removeImpl(alarm.operation); } } catch (RuntimeException e) { Slog.w(TAG, "Failure sending alarm.", e); @@ -1310,7 +1331,7 @@ class AlarmManagerService extends IAlarmManager.Stub { if (alarm.repeatInterval > 0) { // This IntentSender is no longer valid, but this // is a repeating alarm, so toss the hoser. - remove(alarm.operation); + removeImpl(alarm.operation); } } } @@ -1323,7 +1344,7 @@ class AlarmManagerService extends IAlarmManager.Stub { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_TIME_TICK); filter.addAction(Intent.ACTION_DATE_CHANGED); - mContext.registerReceiver(this, filter); + getContext().registerReceiver(this, filter); } @Override @@ -1340,7 +1361,7 @@ class AlarmManagerService extends IAlarmManager.Stub { // daylight savings information. TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY)); int gmtOffset = zone.getOffset(System.currentTimeMillis()); - setKernelTimezone(mDescriptor, -(gmtOffset / 60000)); + setKernelTimezone(mNativeData, -(gmtOffset / 60000)); scheduleDateChangedEvent(); } } @@ -1354,7 +1375,7 @@ class AlarmManagerService extends IAlarmManager.Stub { final long tickEventDelay = nextTime - currentTime; final WorkSource workSource = null; // Let system take blame for time tick events. - set(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0, + setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0, 0, mTimeTickSender, true, workSource); } @@ -1368,7 +1389,7 @@ class AlarmManagerService extends IAlarmManager.Stub { calendar.add(Calendar.DAY_OF_MONTH, 1); final WorkSource workSource = null; // Let system take blame for date change events. - set(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource); + setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource); } } @@ -1379,12 +1400,12 @@ class AlarmManagerService extends IAlarmManager.Stub { filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); filter.addDataScheme("package"); - mContext.registerReceiver(this, filter); + getContext().registerReceiver(this, filter); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); sdFilter.addAction(Intent.ACTION_USER_STOPPED); - mContext.registerReceiver(this, sdFilter); + getContext().registerReceiver(this, sdFilter); } @Override diff --git a/services/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index a1a0d47..e5615c0 100644 --- a/services/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -186,9 +186,9 @@ public class AppOpsService extends IAppOpsService.Stub { } } - public AppOpsService(File storagePath) { + public AppOpsService(File storagePath, Handler handler) { mFile = new AtomicFile(storagePath); - mHandler = new Handler(); + mHandler = handler; readState(); } diff --git a/services/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java index 26b4652..3fb006b 100644 --- a/services/java/com/android/server/AssetAtlasService.java +++ b/services/core/java/com/android/server/AssetAtlasService.java @@ -288,8 +288,8 @@ public class AssetAtlasService extends IAssetAtlas.Stub { } canvas.drawBitmap(bitmap, 0.0f, 0.0f, null); canvas.restore(); - - atlasMap[mapIndex++] = bitmap.mNativeBitmap; + // TODO: Change mAtlasMap to long[] to support 64-bit systems + atlasMap[mapIndex++] = (int) bitmap.mNativeBitmap; atlasMap[mapIndex++] = entry.x; atlasMap[mapIndex++] = entry.y; atlasMap[mapIndex++] = entry.rotated ? 1 : 0; diff --git a/services/java/com/android/server/AttributeCache.java b/services/core/java/com/android/server/AttributeCache.java index 427dbc0..427dbc0 100644 --- a/services/java/com/android/server/AttributeCache.java +++ b/services/core/java/com/android/server/AttributeCache.java diff --git a/services/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 5f3f894..cc9055d 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -19,6 +19,8 @@ package com.android.server; import android.os.BatteryStats; import com.android.internal.app.IBatteryStats; import com.android.server.am.BatteryStatsService; +import com.android.server.lights.Light; +import com.android.server.lights.LightsManager; import android.app.ActivityManagerNative; import android.content.ContentResolver; @@ -134,13 +136,10 @@ public final class BatteryService extends Binder { private boolean mSentLowBatteryBroadcast = false; - private BatteryListener mBatteryPropertiesListener; - private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar; - - public BatteryService(Context context, LightsService lights) { + public BatteryService(Context context, LightsManager lightsManager) { mContext = context; mHandler = new Handler(true /*async*/); - mLed = new Led(context, lights); + mLed = new Led(context, lightsManager); mBatteryStats = BatteryStatsService.getService(); mCriticalBatteryLevel = mContext.getResources().getInteger( @@ -158,13 +157,11 @@ public final class BatteryService extends Binder { "DEVPATH=/devices/virtual/switch/invalid_charger"); } - mBatteryPropertiesListener = new BatteryListener(); - IBinder b = ServiceManager.getService("batterypropreg"); - mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b); - + final IBatteryPropertiesRegistrar batteryPropertiesRegistrar = + IBatteryPropertiesRegistrar.Stub.asInterface(b); try { - mBatteryPropertiesRegistrar.registerListener(mBatteryPropertiesListener); + batteryPropertiesRegistrar.registerListener(new BatteryListener()); } catch (RemoteException e) { // Should never happen. } @@ -688,7 +685,7 @@ public final class BatteryService extends Binder { }; private final class Led { - private final LightsService.Light mBatteryLight; + private final Light mBatteryLight; private final int mBatteryLowARGB; private final int mBatteryMediumARGB; @@ -696,8 +693,8 @@ public final class BatteryService extends Binder { private final int mBatteryLedOn; private final int mBatteryLedOff; - public Led(Context context, LightsService lights) { - mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY); + public Led(Context context, LightsManager lights) { + mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY); mBatteryLowARGB = context.getResources().getInteger( com.android.internal.R.integer.config_notificationsBatteryLowARGB); @@ -723,7 +720,7 @@ public final class BatteryService extends Binder { mBatteryLight.setColor(mBatteryLowARGB); } else { // Flash red when battery is low and not charging - mBatteryLight.setFlashing(mBatteryLowARGB, LightsService.LIGHT_FLASH_TIMED, + mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED, mBatteryLedOn, mBatteryLedOff); } } else if (status == BatteryManager.BATTERY_STATUS_CHARGING @@ -743,8 +740,14 @@ public final class BatteryService extends Binder { } private final class BatteryListener extends IBatteryPropertiesListener.Stub { + @Override public void batteryPropertiesChanged(BatteryProperties props) { - BatteryService.this.update(props); + final long identity = Binder.clearCallingIdentity(); + try { + BatteryService.this.update(props); + } finally { + Binder.restoreCallingIdentity(identity); + } } } } diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 546324a..546324a 100644 --- a/services/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java diff --git a/services/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java index da1b254..7249985 100644 --- a/services/java/com/android/server/BootReceiver.java +++ b/services/core/java/com/android/server/BootReceiver.java @@ -106,20 +106,33 @@ public class BootReceiver extends BroadcastReceiver { .append("Kernel: ") .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n")) .append("\n").toString(); + final String bootReason = SystemProperties.get("ro.boot.bootreason", null); String recovery = RecoverySystem.handleAftermath(); if (recovery != null && db != null) { db.addText("SYSTEM_RECOVERY_LOG", headers + recovery); } + String lastKmsgFooter = ""; + if (bootReason != null) { + lastKmsgFooter = new StringBuilder(512) + .append("\n") + .append("Boot info:\n") + .append("Last boot reason: ").append(bootReason).append("\n") + .toString(); + } + if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) { String now = Long.toString(System.currentTimeMillis()); SystemProperties.set("ro.runtime.firstboot", now); if (db != null) db.addText("SYSTEM_BOOT", headers); // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile()) - addFileToDropBox(db, prefs, headers, "/proc/last_kmsg", - -LOG_SIZE, "SYSTEM_LAST_KMSG"); + addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter, + "/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG"); + addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter, + "/sys/fs/pstore/console-ramoops", -LOG_SIZE, + "SYSTEM_LAST_KMSG"); addFileToDropBox(db, prefs, headers, "/cache/recovery/log", -LOG_SIZE, "SYSTEM_RECOVERY_LOG"); addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console", @@ -159,6 +172,14 @@ public class BootReceiver extends BroadcastReceiver { private static void addFileToDropBox( DropBoxManager db, SharedPreferences prefs, String headers, String filename, int maxSize, String tag) throws IOException { + addFileWithFootersToDropBox(db, prefs, headers, "", filename, maxSize, + tag); + } + + private static void addFileWithFootersToDropBox( + DropBoxManager db, SharedPreferences prefs, + String headers, String footers, String filename, int maxSize, + String tag) throws IOException { if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled File file = new File(filename); @@ -174,7 +195,7 @@ public class BootReceiver extends BroadcastReceiver { } Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")"); - db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n")); + db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") + footers); } private static void addAuditErrorsToDropBox(DropBoxManager db, SharedPreferences prefs, @@ -184,6 +205,11 @@ public class BootReceiver extends BroadcastReceiver { File file = new File("/proc/last_kmsg"); long fileTime = file.lastModified(); + if (fileTime <= 0) { + file = new File("/sys/fs/pstore/console-ramoops"); + fileTime = file.lastModified(); + } + if (fileTime <= 0) return; // File does not exist if (prefs != null) { diff --git a/services/java/com/android/server/BrickReceiver.java b/services/core/java/com/android/server/BrickReceiver.java index cff3805..cff3805 100644 --- a/services/java/com/android/server/BrickReceiver.java +++ b/services/core/java/com/android/server/BrickReceiver.java diff --git a/services/java/com/android/server/CertBlacklister.java b/services/core/java/com/android/server/CertBlacklister.java index 8b167d7..8b167d7 100644 --- a/services/java/com/android/server/CertBlacklister.java +++ b/services/core/java/com/android/server/CertBlacklister.java diff --git a/services/java/com/android/server/CommonTimeManagementService.java b/services/core/java/com/android/server/CommonTimeManagementService.java index 710fb9d..710fb9d 100644 --- a/services/java/com/android/server/CommonTimeManagementService.java +++ b/services/core/java/com/android/server/CommonTimeManagementService.java diff --git a/services/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 41a0e6b..57ee031 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -26,6 +26,7 @@ import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIMAX; +import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; @@ -72,6 +73,7 @@ import android.net.NetworkState; import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.Proxy; +import android.net.ProxyDataTracker; import android.net.ProxyProperties; import android.net.RouteInfo; import android.net.SamplingDataTracker; @@ -736,6 +738,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { return makeWimaxStateTracker(mContext, mTrackerHandler); case TYPE_ETHERNET: return EthernetDataTracker.getInstance(); + case TYPE_PROXY: + return new ProxyDataTracker(); default: throw new IllegalArgumentException( "Trying to create a NetworkStateTracker for an unknown radio type: " @@ -1637,9 +1641,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { return false; } NetworkStateTracker tracker = mNetTrackers[networkType]; - DetailedState netState = tracker.getNetworkInfo().getDetailedState(); + DetailedState netState = DetailedState.DISCONNECTED; + if (tracker != null) { + netState = tracker.getNetworkInfo().getDetailedState(); + } - if (tracker == null || (netState != DetailedState.CONNECTED && + if ((netState != DetailedState.CONNECTED && netState != DetailedState.CAPTIVE_PORTAL_CHECK) || tracker.isTeardownRequested()) { if (VDBG) { diff --git a/services/java/com/android/server/ConsumerIrService.java b/services/core/java/com/android/server/ConsumerIrService.java index 783dff1..783dff1 100644 --- a/services/java/com/android/server/ConsumerIrService.java +++ b/services/core/java/com/android/server/ConsumerIrService.java diff --git a/services/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java index a478b2f..a478b2f 100644 --- a/services/java/com/android/server/CountryDetectorService.java +++ b/services/core/java/com/android/server/CountryDetectorService.java diff --git a/services/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java index ac25dc5..ac25dc5 100644 --- a/services/java/com/android/server/DiskStatsService.java +++ b/services/core/java/com/android/server/DiskStatsService.java diff --git a/services/core/java/com/android/server/DisplayThread.java b/services/core/java/com/android/server/DisplayThread.java new file mode 100644 index 0000000..528ba0a --- /dev/null +++ b/services/core/java/com/android/server/DisplayThread.java @@ -0,0 +1,56 @@ +/* + * 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.server; + +import android.os.Handler; + +/** + * Shared singleton foreground thread for the system. This is a thread for + * operations that affect what's on the display, which needs to have a minimum + * of latency. This thread should pretty much only be used by the WindowManager, + * DisplayManager, and InputManager to perform quick operations in real time. + */ +public final class DisplayThread extends ServiceThread { + private static DisplayThread sInstance; + private static Handler sHandler; + + private DisplayThread() { + super("android.display", android.os.Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/); + } + + private static void ensureThreadLocked() { + if (sInstance == null) { + sInstance = new DisplayThread(); + sInstance.start(); + sHandler = new Handler(sInstance.getLooper()); + } + } + + public static DisplayThread get() { + synchronized (UiThread.class) { + ensureThreadLocked(); + return sInstance; + } + } + + public static Handler getHandler() { + synchronized (UiThread.class) { + ensureThreadLocked(); + return sHandler; + } + } +} diff --git a/services/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java index 4a8bf72..4a8bf72 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/core/java/com/android/server/DockObserver.java diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java index 29b04da..29b04da 100644 --- a/services/java/com/android/server/DropBoxManagerService.java +++ b/services/core/java/com/android/server/DropBoxManagerService.java diff --git a/services/java/com/android/server/EntropyMixer.java b/services/core/java/com/android/server/EntropyMixer.java index fbb66f9..cfdbf7d 100644 --- a/services/java/com/android/server/EntropyMixer.java +++ b/services/core/java/com/android/server/EntropyMixer.java @@ -36,7 +36,8 @@ import android.util.Slog; /** * A service designed to load and periodically save "randomness" - * for the Linux kernel. + * for the Linux kernel RNG and to mix in data from Hardware RNG (if present) + * into the Linux RNG. * * <p>When a Linux system starts up, the entropy pool associated with * {@code /dev/random} may be in a fairly predictable state. Applications which @@ -45,6 +46,13 @@ import android.util.Slog; * this effect, it's helpful to carry the entropy pool information across * shutdowns and startups. * + * <p>On systems with Hardware RNG (/dev/hw_random), a block of output from HW + * RNG is mixed into the Linux RNG on EntropyMixer's startup and whenever + * EntropyMixer periodically runs to save a block of output from Linux RNG on + * disk. This mixing is done in a way that does not increase the Linux RNG's + * entropy estimate is not increased. This is to avoid having to trust/verify + * the quality and authenticity of the "randomness" of the HW RNG. + * * <p>This class was modeled after the script in * <a href="http://www.kernel.org/doc/man-pages/online/pages/man4/random.4.html">man * 4 random</a>. @@ -57,6 +65,7 @@ public class EntropyMixer extends Binder { private static final long START_NANOTIME = System.nanoTime(); private final String randomDevice; + private final String hwRandomDevice; private final String entropyFile; /** @@ -69,6 +78,7 @@ public class EntropyMixer extends Binder { Slog.e(TAG, "Will not process invalid message"); return; } + addHwRandomEntropy(); writeEntropy(); scheduleEntropyWriter(); } @@ -82,18 +92,25 @@ public class EntropyMixer extends Binder { }; public EntropyMixer(Context context) { - this(context, getSystemDir() + "/entropy.dat", "/dev/urandom"); + this(context, getSystemDir() + "/entropy.dat", "/dev/urandom", "/dev/hw_random"); } /** Test only interface, not for public use */ - public EntropyMixer(Context context, String entropyFile, String randomDevice) { + public EntropyMixer( + Context context, + String entropyFile, + String randomDevice, + String hwRandomDevice) { if (randomDevice == null) { throw new NullPointerException("randomDevice"); } + if (hwRandomDevice == null) { throw new NullPointerException("hwRandomDevice"); } if (entropyFile == null) { throw new NullPointerException("entropyFile"); } this.randomDevice = randomDevice; + this.hwRandomDevice = hwRandomDevice; this.entropyFile = entropyFile; loadInitialEntropy(); addDeviceSpecificEntropy(); + addHwRandomEntropy(); writeEntropy(); scheduleEntropyWriter(); IntentFilter broadcastFilter = new IntentFilter(Intent.ACTION_SHUTDOWN); @@ -168,6 +185,20 @@ public class EntropyMixer extends Binder { } } + /** + * Mixes in the output from HW RNG (if present) into the Linux RNG. + */ + private void addHwRandomEntropy() { + try { + RandomBlock.fromFile(hwRandomDevice).toFile(randomDevice, false); + Slog.i(TAG, "Added HW RNG output to entropy pool"); + } catch (FileNotFoundException ignored) { + // HW RNG not present/exposed -- ignore + } catch (IOException e) { + Slog.w(TAG, "Failed to add HW RNG output to entropy pool", e); + } + } + private static String getSystemDir() { File dataDir = Environment.getDataDirectory(); File systemDir = new File(dataDir, "system"); diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 399e7d1..399e7d1 100644 --- a/services/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags diff --git a/services/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java index 3b655f2..03765db 100644 --- a/services/java/com/android/server/FgThread.java +++ b/services/core/java/com/android/server/FgThread.java @@ -17,7 +17,6 @@ package com.android.server; import android.os.Handler; -import android.os.HandlerThread; /** * Shared singleton foreground thread for the system. This is a thread for regular @@ -27,12 +26,12 @@ import android.os.HandlerThread; * simply being a background priority), which can cause operations scheduled on it * to be delayed for a user-noticeable amount of time. */ -public final class FgThread extends HandlerThread { +public final class FgThread extends ServiceThread { private static FgThread sInstance; private static Handler sHandler; private FgThread() { - super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT); + super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/); } private static void ensureThreadLocked() { @@ -40,12 +39,6 @@ public final class FgThread extends HandlerThread { sInstance = new FgThread(); sInstance.start(); sHandler = new Handler(sInstance.getLooper()); - sHandler.post(new Runnable() { - @Override - public void run() { - android.os.Process.setCanSelfBackground(false); - } - }); } } diff --git a/services/java/com/android/server/INativeDaemonConnectorCallbacks.java b/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java index 6fbf713..6fbf713 100644 --- a/services/java/com/android/server/INativeDaemonConnectorCallbacks.java +++ b/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java diff --git a/services/java/com/android/server/IdleMaintenanceService.java b/services/core/java/com/android/server/IdleMaintenanceService.java index b0a1aca..b0a1aca 100644 --- a/services/java/com/android/server/IdleMaintenanceService.java +++ b/services/core/java/com/android/server/IdleMaintenanceService.java diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index a996dbd..bbec329 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -28,7 +28,7 @@ import com.android.internal.view.IInputMethodClient; import com.android.internal.view.IInputMethodManager; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.InputBindResult; -import com.android.server.EventLogTags; +import com.android.server.statusbar.StatusBarManagerService; import com.android.server.wm.WindowManagerService; import org.xmlpull.v1.XmlPullParser; @@ -632,7 +632,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mImeSwitcherNotification.vibrate = null; // Tag this notification specially so SystemUI knows it's important - mImeSwitcherNotification.kind = new String[] { "android.system.imeswitcher" }; + mImeSwitcherNotification.extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true); + mImeSwitcherNotification.category = Notification.CATEGORY_SYSTEM; Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER); mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); diff --git a/services/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java index 64b0487..64b0487 100644 --- a/services/java/com/android/server/IntentResolver.java +++ b/services/core/java/com/android/server/IntentResolver.java diff --git a/services/java/com/android/server/IoThread.java b/services/core/java/com/android/server/IoThread.java index 09f2af7..0f29857 100644 --- a/services/java/com/android/server/IoThread.java +++ b/services/core/java/com/android/server/IoThread.java @@ -17,19 +17,18 @@ package com.android.server; import android.os.Handler; -import android.os.HandlerThread; /** * Shared singleton I/O thread for the system. This is a thread for non-background * service operations that can potential block briefly on network IO operations * (not waiting for data itself, but communicating with network daemons). */ -public final class IoThread extends HandlerThread { +public final class IoThread extends ServiceThread { private static IoThread sInstance; private static Handler sHandler; private IoThread() { - super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT); + super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/); } private static void ensureThreadLocked() { @@ -37,12 +36,6 @@ public final class IoThread extends HandlerThread { sInstance = new IoThread(); sInstance.start(); sHandler = new Handler(sInstance.getLooper()); - sHandler.post(new Runnable() { - @Override - public void run() { - android.os.Process.setCanSelfBackground(false); - } - }); } } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index eebd1c5..eebd1c5 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java diff --git a/services/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index 35e7afa..35e7afa 100644 --- a/services/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java index 86f57d1..e570b0b 100644 --- a/services/java/com/android/server/MasterClearReceiver.java +++ b/services/core/java/com/android/server/MasterClearReceiver.java @@ -37,13 +37,15 @@ public class MasterClearReceiver extends BroadcastReceiver { } } + final boolean shutdown = intent.getBooleanExtra("shutdown", false); + Slog.w(TAG, "!!! FACTORY RESET !!!"); // The reboot call is blocking, so we need to do it on another thread. Thread thr = new Thread("Reboot") { @Override public void run() { try { - RecoverySystem.rebootWipeUserData(context); + RecoverySystem.rebootWipeUserData(context, shutdown); Log.wtf(TAG, "Still running after master clear?!"); } catch (IOException e) { Slog.e(TAG, "Can't perform master clear/factory reset", e); diff --git a/services/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index e60231a..816ae69 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -877,7 +877,7 @@ class MountService extends IMountService.Stub /* Send the media unmounted event first */ if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); - sendStorageIntent(Environment.MEDIA_UNMOUNTED, volume, UserHandle.ALL); + sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL); if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed"); updatePublicVolumeState(volume, Environment.MEDIA_REMOVED); @@ -1164,6 +1164,7 @@ class MountService extends IMountService.Stub private void sendStorageIntent(String action, StorageVolume volume, UserHandle user) { final Intent intent = new Intent(action, Uri.parse("file://" + volume.getPath())); intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, volume); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); Slog.d(TAG, "sendStorageIntent " + intent + " to " + user); mContext.sendBroadcastAsUser(intent, user); } @@ -1411,7 +1412,7 @@ class MountService extends IMountService.Stub public void unregisterListener(IMountServiceListener listener) { synchronized (mListeners) { for(MountServiceBinderListener bl : mListeners) { - if (bl.mListener == listener) { + if (bl.mListener.asBinder() == listener.asBinder()) { mListeners.remove(mListeners.indexOf(bl)); listener.asBinder().unlinkToDeath(bl, 0); return; diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 417d6d8..417d6d8 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java diff --git a/services/java/com/android/server/NativeDaemonConnectorException.java b/services/core/java/com/android/server/NativeDaemonConnectorException.java index 590bbcc..590bbcc 100644 --- a/services/java/com/android/server/NativeDaemonConnectorException.java +++ b/services/core/java/com/android/server/NativeDaemonConnectorException.java diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/core/java/com/android/server/NativeDaemonEvent.java index 2095152..2095152 100644 --- a/services/java/com/android/server/NativeDaemonEvent.java +++ b/services/core/java/com/android/server/NativeDaemonEvent.java diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 72fce62..71e7bac 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -136,6 +136,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub public static final int BandwidthControl = 601; public static final int InterfaceClassActivity = 613; public static final int InterfaceAddressChange = 614; + public static final int InterfaceDnsServerInfo = 615; } /** @@ -404,11 +405,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub /** * Notify our observers of a new or updated interface address. */ - private void notifyAddressUpdated(String address, String iface, int flags, int scope) { + private void notifyAddressUpdated(String iface, LinkAddress address) { final int length = mObservers.beginBroadcast(); for (int i = 0; i < length; i++) { try { - mObservers.getBroadcastItem(i).addressUpdated(address, iface, flags, scope); + mObservers.getBroadcastItem(i).addressUpdated(iface, address); } catch (RemoteException e) { } catch (RuntimeException e) { } @@ -419,11 +420,26 @@ public class NetworkManagementService extends INetworkManagementService.Stub /** * Notify our observers of a deleted interface address. */ - private void notifyAddressRemoved(String address, String iface, int flags, int scope) { + private void notifyAddressRemoved(String iface, LinkAddress address) { final int length = mObservers.beginBroadcast(); for (int i = 0; i < length; i++) { try { - mObservers.getBroadcastItem(i).addressRemoved(address, iface, flags, scope); + mObservers.getBroadcastItem(i).addressRemoved(iface, address); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } + } + mObservers.finishBroadcast(); + } + + /** + * Notify our observers of DNS server information received. + */ + private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) { + final int length = mObservers.beginBroadcast(); + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime, addresses); } catch (RemoteException e) { } catch (RuntimeException e) { } @@ -455,6 +471,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub @Override public boolean onEvent(int code, String raw, String[] cooked) { + String errorMessage = String.format("Invalid event from daemon (%s)", raw); switch (code) { case NetdResponseCode.InterfaceChange: /* @@ -465,8 +482,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub * "NNN Iface linkstatus <name> <up/down>" */ if (cooked.length < 4 || !cooked[1].equals("Iface")) { - throw new IllegalStateException( - String.format("Invalid event from daemon (%s)", raw)); + throw new IllegalStateException(errorMessage); } if (cooked[2].equals("added")) { notifyInterfaceAdded(cooked[3]); @@ -481,8 +497,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up")); return true; } - throw new IllegalStateException( - String.format("Invalid event from daemon (%s)", raw)); + throw new IllegalStateException(errorMessage); // break; case NetdResponseCode.BandwidthControl: /* @@ -490,15 +505,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub * Format: "NNN limit alert <alertName> <ifaceName>" */ if (cooked.length < 5 || !cooked[1].equals("limit")) { - throw new IllegalStateException( - String.format("Invalid event from daemon (%s)", raw)); + throw new IllegalStateException(errorMessage); } if (cooked[2].equals("alert")) { notifyLimitReached(cooked[3], cooked[4]); return true; } - throw new IllegalStateException( - String.format("Invalid event from daemon (%s)", raw)); + throw new IllegalStateException(errorMessage); // break; case NetdResponseCode.InterfaceClassActivity: /* @@ -506,8 +519,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub * Format: "NNN IfaceClass <active/idle> <label>" */ if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) { - throw new IllegalStateException( - String.format("Invalid event from daemon (%s)", raw)); + throw new IllegalStateException(errorMessage); } boolean isActive = cooked[2].equals("active"); notifyInterfaceClassActivity(cooked[3], isActive); @@ -519,24 +531,46 @@ public class NetworkManagementService extends INetworkManagementService.Stub * Format: "NNN Address updated <addr> <iface> <flags> <scope>" * "NNN Address removed <addr> <iface> <flags> <scope>" */ - String msg = String.format("Invalid event from daemon (%s)", raw); - if (cooked.length < 6 || !cooked[1].equals("Address")) { - throw new IllegalStateException(msg); + if (cooked.length < 7 || !cooked[1].equals("Address")) { + throw new IllegalStateException(errorMessage); } - int flags; - int scope; + String iface = cooked[4]; + LinkAddress address; try { - flags = Integer.parseInt(cooked[5]); - scope = Integer.parseInt(cooked[6]); - } catch(NumberFormatException e) { - throw new IllegalStateException(msg); + int flags = Integer.parseInt(cooked[5]); + int scope = Integer.parseInt(cooked[6]); + address = new LinkAddress(cooked[3], flags, scope); + } catch(NumberFormatException e) { // Non-numeric lifetime or scope. + throw new IllegalStateException(errorMessage, e); + } catch(IllegalArgumentException e) { // Malformed/invalid IP address. + throw new IllegalStateException(errorMessage, e); } if (cooked[2].equals("updated")) { - notifyAddressUpdated(cooked[3], cooked[4], flags, scope); + notifyAddressUpdated(iface, address); } else { - notifyAddressRemoved(cooked[3], cooked[4], flags, scope); + notifyAddressRemoved(iface, address); + } + return true; + // break; + case NetdResponseCode.InterfaceDnsServerInfo: + /* + * Information about available DNS servers has been received. + * Format: "NNN DnsInfo servers <interface> <lifetime> <servers>" + */ + long lifetime; // Actually a 32-bit unsigned integer. + + if (cooked.length == 6 && + cooked[1].equals("DnsInfo") && + cooked[2].equals("servers")) { + try { + lifetime = Long.parseLong(cooked[4]); + } catch (NumberFormatException e) { + throw new IllegalStateException(errorMessage); + } + String[] servers = cooked[5].split(","); + notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers); } return true; // break; diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index fddb54e..fddb54e 100644 --- a/services/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java diff --git a/services/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 16d2468..8df93f1 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -38,10 +38,13 @@ import android.util.SparseArray; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.concurrent.CountDownLatch; import com.android.internal.app.IBatteryStats; @@ -152,25 +155,40 @@ public class NsdService extends INsdManager.Stub { class DefaultState extends State { @Override public boolean processMessage(Message msg) { + ClientInfo cInfo = null; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { AsyncChannel c = (AsyncChannel) msg.obj; if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); - ClientInfo cInfo = new ClientInfo(c, msg.replyTo); + cInfo = new ClientInfo(c, msg.replyTo); mClients.put(msg.replyTo, cInfo); } else { Slog.e(TAG, "Client connection failure, error=" + msg.arg1); } break; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { - Slog.e(TAG, "Send failed, client connection lost"); - } else { - if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + switch (msg.arg1) { + case AsyncChannel.STATUS_SEND_UNSUCCESSFUL: + Slog.e(TAG, "Send failed, client connection lost"); + break; + case AsyncChannel.STATUS_REMOTE_DISCONNECTION: + if (DBG) Slog.d(TAG, "Client disconnected"); + break; + default: + if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + break; + } + cInfo = mClients.get(msg.replyTo); + if (cInfo != null) { + cInfo.expungeAllRequests(); + mClients.remove(msg.replyTo); + } + //Last client + if (mClients.size() == 0) { + stopMDnsDaemon(); } - mClients.remove(msg.replyTo); break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: AsyncChannel ac = new AsyncChannel(); @@ -248,13 +266,15 @@ public class NsdService extends INsdManager.Stub { return false; } - private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { + private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) { clientInfo.mClientIds.put(clientId, globalId); + clientInfo.mClientRequests.put(clientId, what); mIdToClientInfoMap.put(globalId, clientInfo); } private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { clientInfo.mClientIds.remove(clientId); + clientInfo.mClientRequests.remove(clientId); mIdToClientInfoMap.remove(globalId); } @@ -274,10 +294,6 @@ public class NsdService extends INsdManager.Stub { result = NOT_HANDLED; break; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - //Last client - if (mClients.size() == 1) { - stopMDnsDaemon(); - } result = NOT_HANDLED; break; case NsdManager.DISABLE: @@ -301,7 +317,7 @@ public class NsdService extends INsdManager.Stub { Slog.d(TAG, "Discover " + msg.arg2 + " " + id + servInfo.getServiceType()); } - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo); } else { stopServiceDiscovery(id); @@ -340,7 +356,7 @@ public class NsdService extends INsdManager.Stub { id = getUniqueId(); if (registerService(id, (NsdServiceInfo) msg.obj)) { if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id); - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); // Return success after mDns reports success } else { unregisterService(id); @@ -381,7 +397,7 @@ public class NsdService extends INsdManager.Stub { id = getUniqueId(); if (resolveService(id, servInfo)) { clientInfo.mResolvedService = new NsdServiceInfo(); - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); } else { replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); @@ -430,14 +446,14 @@ public class NsdService extends INsdManager.Stub { case NativeResponseCode.SERVICE_FOUND: /* NNN uniqueId serviceName regType domain */ if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw); - servInfo = new NsdServiceInfo(cooked[2], cooked[3], null); + servInfo = new NsdServiceInfo(cooked[2], cooked[3]); clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0, clientId, servInfo); break; case NativeResponseCode.SERVICE_LOST: /* NNN uniqueId serviceName regType domain */ if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw); - servInfo = new NsdServiceInfo(cooked[2], cooked[3], null); + servInfo = new NsdServiceInfo(cooked[2], cooked[3]); clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0, clientId, servInfo); break; @@ -450,7 +466,7 @@ public class NsdService extends INsdManager.Stub { case NativeResponseCode.SERVICE_REGISTERED: /* NNN regId serviceName regType */ if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw); - servInfo = new NsdServiceInfo(cooked[2], null, null); + servInfo = new NsdServiceInfo(cooked[2], null); clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED, id, clientId, servInfo); break; @@ -487,7 +503,7 @@ public class NsdService extends INsdManager.Stub { int id2 = getUniqueId(); if (getAddrInfo(id2, cooked[3])) { - storeRequestMap(clientId, id2, clientInfo); + storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); } else { clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR, clientId); @@ -666,9 +682,22 @@ public class NsdService extends INsdManager.Stub { private boolean registerService(int regId, NsdServiceInfo service) { if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service); try { - //Add txtlen and txtdata - mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(), + Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(), service.getServiceType(), service.getPort()); + + // Add TXT records as additional arguments. + Map<String, byte[]> txtRecords = service.getAttributes(); + for (String key : txtRecords.keySet()) { + try { + // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data. + cmd.appendArg(String.format(Locale.US, "%s=%s", key, + new String(txtRecords.get(key), "UTF_8"))); + } catch (UnsupportedEncodingException e) { + Slog.e(TAG, "Failed to encode txtRecord " + e); + } + } + + mNativeConnector.execute(cmd); } catch(NativeDaemonConnectorException e) { Slog.e(TAG, "Failed to execute registerService " + e); return false; @@ -827,6 +856,9 @@ public class NsdService extends INsdManager.Stub { /* A map from client id to unique id sent to mDns */ private SparseArray<Integer> mClientIds = new SparseArray<Integer>(); + /* A map from client id to the type of the request we had received */ + private SparseArray<Integer> mClientRequests = new SparseArray<Integer>(); + private ClientInfo(AsyncChannel c, Messenger m) { mChannel = c; mMessenger = m; @@ -840,10 +872,41 @@ public class NsdService extends INsdManager.Stub { sb.append("mMessenger ").append(mMessenger).append("\n"); sb.append("mResolvedService ").append(mResolvedService).append("\n"); for(int i = 0; i< mClientIds.size(); i++) { - sb.append("clientId ").append(mClientIds.keyAt(i)); - sb.append(" mDnsId ").append(mClientIds.valueAt(i)).append("\n"); + int clientID = mClientIds.keyAt(i); + sb.append("clientId ").append(clientID). + append(" mDnsId ").append(mClientIds.valueAt(i)). + append(" type ").append(mClientRequests.get(clientID)).append("\n"); } return sb.toString(); } + + // Remove any pending requests from the global map when we get rid of a client, + // and send cancellations to the daemon. + private void expungeAllRequests() { + int globalId, clientId, i; + for (i = 0; i < mClientIds.size(); i++) { + clientId = mClientIds.keyAt(i); + globalId = mClientIds.valueAt(i); + mIdToClientInfoMap.remove(globalId); + if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId + + " global-ID " + globalId + " type " + mClientRequests.get(clientId)); + switch (mClientRequests.get(clientId)) { + case NsdManager.DISCOVER_SERVICES: + stopServiceDiscovery(globalId); + break; + case NsdManager.RESOLVE_SERVICE: + stopResolveService(globalId); + break; + case NsdManager.REGISTER_SERVICE: + unregisterService(globalId); + break; + default: + break; + } + } + mClientIds.clear(); + mClientRequests.clear(); + } + } } diff --git a/services/java/com/android/server/RandomBlock.java b/services/core/java/com/android/server/RandomBlock.java index e5d7301..6d6d901 100644 --- a/services/java/com/android/server/RandomBlock.java +++ b/services/core/java/com/android/server/RandomBlock.java @@ -27,13 +27,13 @@ import java.io.InputStream; import java.io.RandomAccessFile; /** - * A 4k block of random {@code byte}s. + * A block of 512 random {@code byte}s. */ class RandomBlock { private static final String TAG = "RandomBlock"; private static final boolean DEBUG = false; - private static final int BLOCK_SIZE = 4096; + private static final int BLOCK_SIZE = 512; private byte[] block = new byte[BLOCK_SIZE]; private RandomBlock() { } diff --git a/services/java/com/android/server/RecognitionManagerService.java b/services/core/java/com/android/server/RecognitionManagerService.java index c2e749d..c2e749d 100644 --- a/services/java/com/android/server/RecognitionManagerService.java +++ b/services/core/java/com/android/server/RecognitionManagerService.java diff --git a/services/java/com/android/server/SamplingProfilerService.java b/services/core/java/com/android/server/SamplingProfilerService.java index fbf1aa4..fbf1aa4 100644 --- a/services/java/com/android/server/SamplingProfilerService.java +++ b/services/core/java/com/android/server/SamplingProfilerService.java diff --git a/services/java/com/android/server/SerialService.java b/services/core/java/com/android/server/SerialService.java index 1abe458..1abe458 100644 --- a/services/java/com/android/server/SerialService.java +++ b/services/core/java/com/android/server/SerialService.java diff --git a/services/core/java/com/android/server/ServiceThread.java b/services/core/java/com/android/server/ServiceThread.java new file mode 100644 index 0000000..bce64af --- /dev/null +++ b/services/core/java/com/android/server/ServiceThread.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.os.HandlerThread; +import android.os.Process; +import android.os.StrictMode; +import android.util.Slog; + +/** + * Special handler thread that we create for system services that require their own loopers. + */ +public class ServiceThread extends HandlerThread { + private static final String TAG = "ServiceThread"; + + private final boolean mAllowIo; + + public ServiceThread(String name, int priority, boolean allowIo) { + super(name, priority); + mAllowIo = allowIo; + } + + @Override + public void run() { + Process.setCanSelfBackground(false); + + // For debug builds, log event loop stalls to dropbox for analysis. + if (!mAllowIo && StrictMode.conditionallyEnableDebugLogging()) { + Slog.i(TAG, "Enabled StrictMode logging for " + getName() + " looper."); + } + + super.run(); + } +}
\ No newline at end of file diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java index 5c7bfab..5c7bfab 100644 --- a/services/java/com/android/server/ServiceWatcher.java +++ b/services/core/java/com/android/server/ServiceWatcher.java diff --git a/services/java/com/android/server/ShutdownActivity.java b/services/core/java/com/android/server/ShutdownActivity.java index be65141..be65141 100644 --- a/services/java/com/android/server/ShutdownActivity.java +++ b/services/core/java/com/android/server/ShutdownActivity.java diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 699d79e..699d79e 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java index 0964767..0964767 100644 --- a/services/java/com/android/server/TextServicesManagerService.java +++ b/services/core/java/com/android/server/TextServicesManagerService.java diff --git a/services/java/com/android/server/TwilightCalculator.java b/services/core/java/com/android/server/TwilightCalculator.java index a5c93b5..a5c93b5 100644 --- a/services/java/com/android/server/TwilightCalculator.java +++ b/services/core/java/com/android/server/TwilightCalculator.java diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 062be01..f59edc7 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -34,9 +34,9 @@ import android.content.res.Configuration; import android.os.BatteryManager; import android.os.Binder; import android.os.Handler; +import android.os.IBinder; import android.os.PowerManager; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; import android.provider.Settings; import android.service.dreams.Sandman; @@ -47,9 +47,11 @@ import java.io.PrintWriter; import com.android.internal.R; import com.android.internal.app.DisableCarModeActivity; -import com.android.server.TwilightService.TwilightState; +import com.android.server.twilight.TwilightListener; +import com.android.server.twilight.TwilightManager; +import com.android.server.twilight.TwilightState; -final class UiModeManagerService extends IUiModeManager.Stub { +final class UiModeManagerService extends SystemService { private static final String TAG = UiModeManager.class.getSimpleName(); private static final boolean LOG = false; @@ -57,40 +59,41 @@ final class UiModeManagerService extends IUiModeManager.Stub { private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true; private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true; - private final Context mContext; - private final TwilightService mTwilightService; - private final Handler mHandler = new Handler(); - final Object mLock = new Object(); - private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + int mNightMode = UiModeManager.MODE_NIGHT_NO; - private int mNightMode = UiModeManager.MODE_NIGHT_NO; private boolean mCarModeEnabled = false; private boolean mCharging = false; - private final int mDefaultUiModeType; - private final boolean mCarModeKeepsScreenOn; - private final boolean mDeskModeKeepsScreenOn; - private final boolean mTelevision; - + private int mDefaultUiModeType; + private boolean mCarModeKeepsScreenOn; + private boolean mDeskModeKeepsScreenOn; + private boolean mTelevision; + private boolean mWatch; private boolean mComputedNightMode; - private int mCurUiMode = 0; - private int mSetUiMode = 0; + int mCurUiMode = 0; + private int mSetUiMode = 0; private boolean mHoldingConfiguration = false; + private Configuration mConfiguration = new Configuration(); + boolean mSystemReady; - private boolean mSystemReady; + private final Handler mHandler = new Handler(); + private TwilightManager mTwilightManager; private NotificationManager mNotificationManager; - private StatusBarManager mStatusBarManager; - private final PowerManager mPowerManager; - private final PowerManager.WakeLock mWakeLock; + private PowerManager.WakeLock mWakeLock; + + public UiModeManagerService(Context context) { + super(context); + } - static Intent buildHomeIntent(String category) { + private static Intent buildHomeIntent(String category) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(category); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK @@ -142,28 +145,26 @@ final class UiModeManagerService extends IUiModeManager.Stub { } }; - private final TwilightService.TwilightListener mTwilightListener = - new TwilightService.TwilightListener() { + private final TwilightListener mTwilightListener = new TwilightListener() { @Override public void onTwilightStateChanged() { updateTwilight(); } }; - public UiModeManagerService(Context context, TwilightService twilight) { - mContext = context; - mTwilightService = twilight; - - ServiceManager.addService(Context.UI_MODE_SERVICE, this); - - mContext.registerReceiver(mDockModeReceiver, + @Override + public void onStart() { + final Context context = getContext(); + mTwilightManager = getLocalService(TwilightManager.class); + final PowerManager powerManager = + (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); + + context.registerReceiver(mDockModeReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); - mContext.registerReceiver(mBatteryReceiver, + context.registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); - mConfiguration.setToDefaults(); mDefaultUiModeType = context.getResources().getInteger( @@ -173,103 +174,144 @@ final class UiModeManagerService extends IUiModeManager.Stub { mDeskModeKeepsScreenOn = (context.getResources().getInteger( com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1); mTelevision = context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_TELEVISION); + PackageManager.FEATURE_TELEVISION) || + context.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_LEANBACK); + mWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); - mNightMode = Settings.Secure.getInt(mContext.getContentResolver(), + mNightMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO); - mTwilightService.registerListener(mTwilightListener, mHandler); + mTwilightManager.registerListener(mTwilightListener, mHandler); + + publishBinderService(Context.UI_MODE_SERVICE, mService); } - @Override // Binder call - public void disableCarMode(int flags) { - final long ident = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - setCarModeLocked(false); - if (mSystemReady) { - updateLocked(0, flags); + private final IBinder mService = new IUiModeManager.Stub() { + @Override + public void enableCarMode(int flags) { + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + setCarModeLocked(true); + if (mSystemReady) { + updateLocked(flags, 0); + } } + } finally { + Binder.restoreCallingIdentity(ident); } - } finally { - Binder.restoreCallingIdentity(ident); } - } - @Override // Binder call - public void enableCarMode(int flags) { - final long ident = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - setCarModeLocked(true); - if (mSystemReady) { - updateLocked(flags, 0); + @Override + public void disableCarMode(int flags) { + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + setCarModeLocked(false); + if (mSystemReady) { + updateLocked(0, flags); + } } + } finally { + Binder.restoreCallingIdentity(ident); } - } finally { - Binder.restoreCallingIdentity(ident); } - } - @Override // Binder call - public int getCurrentModeType() { - final long ident = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - return mCurUiMode & Configuration.UI_MODE_TYPE_MASK; + @Override + public int getCurrentModeType() { + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + return mCurUiMode & Configuration.UI_MODE_TYPE_MASK; + } + } finally { + Binder.restoreCallingIdentity(ident); } - } finally { - Binder.restoreCallingIdentity(ident); } - } - @Override // Binder call - public void setNightMode(int mode) { - switch (mode) { - case UiModeManager.MODE_NIGHT_NO: - case UiModeManager.MODE_NIGHT_YES: - case UiModeManager.MODE_NIGHT_AUTO: - break; - default: - throw new IllegalArgumentException("Unknown mode: " + mode); + @Override + public void setNightMode(int mode) { + switch (mode) { + case UiModeManager.MODE_NIGHT_NO: + case UiModeManager.MODE_NIGHT_YES: + case UiModeManager.MODE_NIGHT_AUTO: + break; + default: + throw new IllegalArgumentException("Unknown mode: " + mode); + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + if (isDoingNightModeLocked() && mNightMode != mode) { + Settings.Secure.putInt(getContext().getContentResolver(), + Settings.Secure.UI_NIGHT_MODE, mode); + mNightMode = mode; + updateLocked(0, 0); + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } } - final long ident = Binder.clearCallingIdentity(); - try { + @Override + public int getNightMode() { synchronized (mLock) { - if (isDoingNightModeLocked() && mNightMode != mode) { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.UI_NIGHT_MODE, mode); - mNightMode = mode; - updateLocked(0, 0); - } + return mNightMode; } - } finally { - Binder.restoreCallingIdentity(ident); } - } - @Override // Binder call - public int getNightMode() { + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + + pw.println("Permission Denial: can't dump uimode service from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + dumpImpl(pw); + } + }; + + void dumpImpl(PrintWriter pw) { synchronized (mLock) { - return mNightMode; + pw.println("Current UI Mode Service state:"); + pw.print(" mDockState="); pw.print(mDockState); + pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); + pw.print(" mNightMode="); pw.print(mNightMode); + pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); + pw.print(" mComputedNightMode="); pw.println(mComputedNightMode); + pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); + pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); + pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration); + pw.print(" mSystemReady="); pw.println(mSystemReady); + pw.print(" mTwilightService.getCurrentState()="); + pw.println(mTwilightManager.getCurrentState()); } } - void systemReady() { - synchronized (mLock) { - mSystemReady = true; - mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; - updateComputedNightModeLocked(); - updateLocked(0, 0); + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { + synchronized (mLock) { + mSystemReady = true; + mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; + updateComputedNightModeLocked(); + updateLocked(0, 0); + } } } - private boolean isDoingNightModeLocked() { + boolean isDoingNightModeLocked() { return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED; } - private void setCarModeLocked(boolean enabled) { + void setCarModeLocked(boolean enabled) { if (mCarModeEnabled != enabled) { mCarModeEnabled = enabled; } @@ -299,8 +341,12 @@ final class UiModeManagerService extends IUiModeManager.Stub { } private void updateConfigurationLocked() { - int uiMode = mTelevision ? Configuration.UI_MODE_TYPE_TELEVISION : mDefaultUiModeType; - if (mCarModeEnabled) { + int uiMode = mDefaultUiModeType; + if (mTelevision) { + uiMode = Configuration.UI_MODE_TYPE_TELEVISION; + } else if (mWatch) { + uiMode = Configuration.UI_MODE_TYPE_WATCH; + } else if (mCarModeEnabled) { uiMode = Configuration.UI_MODE_TYPE_CAR; } else if (isDeskDockState(mDockState)) { uiMode = Configuration.UI_MODE_TYPE_DESK; @@ -344,7 +390,7 @@ final class UiModeManagerService extends IUiModeManager.Stub { } } - private void updateLocked(int enableFlags, int disableFlags) { + void updateLocked(int enableFlags, int disableFlags) { String action = null; String oldAction = null; if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) { @@ -359,7 +405,7 @@ final class UiModeManagerService extends IUiModeManager.Stub { adjustStatusBarCarModeLocked(); if (oldAction != null) { - mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL); + getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL); } mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR; action = UiModeManager.ACTION_ENTER_CAR_MODE; @@ -367,7 +413,7 @@ final class UiModeManagerService extends IUiModeManager.Stub { } else if (isDeskDockState(mDockState)) { if (!isDeskDockState(mLastBroadcastState)) { if (oldAction != null) { - mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL); + getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL); } mLastBroadcastState = mDockState; action = UiModeManager.ACTION_ENTER_DESK_MODE; @@ -393,7 +439,7 @@ final class UiModeManagerService extends IUiModeManager.Stub { Intent intent = new Intent(action); intent.putExtra("enableFlags", enableFlags); intent.putExtra("disableFlags", disableFlags); - mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, + getContext().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, mResultReceiver, null, Activity.RESULT_OK, null, null); // Attempting to make this transition a little more clean, we are going @@ -491,7 +537,7 @@ final class UiModeManagerService extends IUiModeManager.Stub { // activity manager take care of both the start and config // change. Intent homeIntent = buildHomeIntent(category); - if (Sandman.shouldStartDockApp(mContext, homeIntent)) { + if (Sandman.shouldStartDockApp(getContext(), homeIntent)) { try { int result = ActivityManagerNative.getDefault().startActivityWithConfig( null, null, homeIntent, null, null, null, 0, 0, @@ -513,14 +559,15 @@ final class UiModeManagerService extends IUiModeManager.Stub { // If we did not start a dock app, then start dreaming if supported. if (category != null && !dockAppStarted) { - Sandman.startDreamWhenDockedIfAppropriate(mContext); + Sandman.startDreamWhenDockedIfAppropriate(getContext()); } } private void adjustStatusBarCarModeLocked() { + final Context context = getContext(); if (mStatusBarManager == null) { mStatusBarManager = (StatusBarManager) - mContext.getSystemService(Context.STATUS_BAR_SERVICE); + context.getSystemService(Context.STATUS_BAR_SERVICE); } // Fear not: StatusBarManagerService manages a list of requests to disable @@ -536,12 +583,12 @@ final class UiModeManagerService extends IUiModeManager.Stub { if (mNotificationManager == null) { mNotificationManager = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); + context.getSystemService(Context.NOTIFICATION_SERVICE); } if (mNotificationManager != null) { if (mCarModeEnabled) { - Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class); + Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class); Notification n = new Notification(); n.icon = R.drawable.stat_notify_car_mode; @@ -549,10 +596,10 @@ final class UiModeManagerService extends IUiModeManager.Stub { n.flags = Notification.FLAG_ONGOING_EVENT; n.when = 0; n.setLatestEventInfo( - mContext, - mContext.getString(R.string.car_mode_disable_notification_title), - mContext.getString(R.string.car_mode_disable_notification_message), - PendingIntent.getActivityAsUser(mContext, 0, carModeOffIntent, 0, + context, + context.getString(R.string.car_mode_disable_notification_title), + context.getString(R.string.car_mode_disable_notification_message), + PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0, null, UserHandle.CURRENT)); mNotificationManager.notifyAsUser(null, R.string.car_mode_disable_notification_title, n, UserHandle.ALL); @@ -563,7 +610,7 @@ final class UiModeManagerService extends IUiModeManager.Stub { } } - private void updateTwilight() { + void updateTwilight() { synchronized (mLock) { if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { updateComputedNightModeLocked(); @@ -573,36 +620,11 @@ final class UiModeManagerService extends IUiModeManager.Stub { } private void updateComputedNightModeLocked() { - TwilightState state = mTwilightService.getCurrentState(); + TwilightState state = mTwilightManager.getCurrentState(); if (state != null) { mComputedNightMode = state.isNight(); } } - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump uimode service from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - synchronized (mLock) { - pw.println("Current UI Mode Service state:"); - pw.print(" mDockState="); pw.print(mDockState); - pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); - pw.print(" mNightMode="); pw.print(mNightMode); - pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); - pw.print(" mComputedNightMode="); pw.println(mComputedNightMode); - pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); - pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); - pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration); - pw.print(" mSystemReady="); pw.println(mSystemReady); - pw.print(" mTwilightService.getCurrentState()="); - pw.println(mTwilightService.getCurrentState()); - } - } } diff --git a/services/java/com/android/server/UiThread.java b/services/core/java/com/android/server/UiThread.java index 60d73aa..0beb77f 100644 --- a/services/java/com/android/server/UiThread.java +++ b/services/core/java/com/android/server/UiThread.java @@ -17,21 +17,18 @@ package com.android.server; import android.os.Handler; -import android.os.HandlerThread; -import android.os.StrictMode; -import android.util.Slog; /** * Shared singleton thread for showing UI. This is a foreground thread, and in * additional should not have operations that can take more than a few ms scheduled * on it to avoid UI jank. */ -public final class UiThread extends HandlerThread { +public final class UiThread extends ServiceThread { private static UiThread sInstance; private static Handler sHandler; private UiThread() { - super("android.ui", android.os.Process.THREAD_PRIORITY_FOREGROUND); + super("android.ui", android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); } private static void ensureThreadLocked() { @@ -39,19 +36,6 @@ public final class UiThread extends HandlerThread { sInstance = new UiThread(); sInstance.start(); sHandler = new Handler(sInstance.getLooper()); - sHandler.post(new Runnable() { - @Override - public void run() { - //Looper.myLooper().setMessageLogging(new LogPrinter( - // Log.VERBOSE, "WindowManagerPolicy", Log.LOG_ID_SYSTEM)); - android.os.Process.setCanSelfBackground(false); - - // For debug builds, log event loop stalls to dropbox for analysis. - if (StrictMode.conditionallyEnableDebugLogging()) { - Slog.i("UiThread", "Enabled StrictMode logging for UI thread"); - } - } - }); } } diff --git a/services/java/com/android/server/UpdateLockService.java b/services/core/java/com/android/server/UpdateLockService.java index 0f778cd..0f778cd 100644 --- a/services/java/com/android/server/UpdateLockService.java +++ b/services/core/java/com/android/server/UpdateLockService.java diff --git a/services/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 28eb948..28eb948 100644 --- a/services/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java diff --git a/services/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index e17f42d..1ce073a 100644 --- a/services/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -20,18 +20,15 @@ import android.app.IActivityController; import android.os.Binder; import android.os.RemoteException; import com.android.server.am.ActivityManagerService; -import com.android.server.power.PowerManagerService; -import android.app.AlarmManager; -import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.os.BatteryManager; import android.os.Debug; import android.os.Handler; +import android.os.IPowerManager; import android.os.Looper; import android.os.Process; import android.os.ServiceManager; @@ -45,7 +42,6 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; -import java.util.Calendar; /** This class calls its monitor every minute. Killing this process if they don't return **/ public class Watchdog extends Thread { @@ -80,9 +76,6 @@ public class Watchdog extends Thread { final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<HandlerChecker>(); final HandlerChecker mMonitorChecker; ContentResolver mResolver; - BatteryService mBattery; - PowerManagerService mPower; - AlarmManagerService mAlarm; ActivityManagerService mActivity; int mPhonePid; @@ -232,15 +225,13 @@ public class Watchdog extends Thread { // And also check IO thread. mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread", DEFAULT_TIMEOUT)); + // And the display thread. + mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(), + "display thread", DEFAULT_TIMEOUT)); } - public void init(Context context, BatteryService battery, - PowerManagerService power, AlarmManagerService alarm, - ActivityManagerService activity) { + public void init(Context context, ActivityManagerService activity) { mResolver = context.getContentResolver(); - mBattery = battery; - mPower = power; - mAlarm = alarm; mActivity = activity; context.registerReceiver(new RebootRequestReceiver(), @@ -277,15 +268,16 @@ public class Watchdog extends Thread { } } - public void addThread(Handler thread, String name) { - addThread(thread, name, DEFAULT_TIMEOUT); + public void addThread(Handler thread) { + addThread(thread, DEFAULT_TIMEOUT); } - public void addThread(Handler thread, String name, long timeoutMillis) { + public void addThread(Handler thread, long timeoutMillis) { synchronized (this) { if (isAlive()) { throw new RuntimeException("Threads can't be added once the Watchdog is running"); } + final String name = thread.getLooper().getThread().getName(); mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis)); } } @@ -295,8 +287,11 @@ public class Watchdog extends Thread { */ void rebootSystem(String reason) { Slog.i(TAG, "Rebooting system because: " + reason); - PowerManagerService pms = (PowerManagerService) ServiceManager.getService("power"); - pms.reboot(false, reason, false); + IPowerManager pms = (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE); + try { + pms.reboot(false, reason, false); + } catch (RemoteException ex) { + } } private int evaluateCheckerCompletionLocked() { diff --git a/services/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java index 415fcc1..415fcc1 100644 --- a/services/java/com/android/server/WiredAccessoryManager.java +++ b/services/core/java/com/android/server/WiredAccessoryManager.java diff --git a/services/java/com/android/server/accounts/AccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java index 7552368..7552368 100644 --- a/services/java/com/android/server/accounts/AccountAuthenticatorCache.java +++ b/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index aa9849e..aa9849e 100644 --- a/services/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java diff --git a/services/java/com/android/server/accounts/IAccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java index bb09687..bb09687 100644 --- a/services/java/com/android/server/accounts/IAccountAuthenticatorCache.java +++ b/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 17bb3e0..17bb3e0 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e2050fc..d09ee96 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -24,15 +24,19 @@ import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; - import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; import android.app.AppOpsManager; +import android.app.IActivityContainer; +import android.app.IActivityContainerCallback; import android.appwidget.AppWidgetManager; +import android.graphics.Rect; import android.util.ArrayMap; + import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; +import com.android.internal.app.ProcessMap; import com.android.internal.app.ProcessStats; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatteryStatsImpl; @@ -45,20 +49,19 @@ import com.android.internal.util.Preconditions; import com.android.server.AppOpsService; import com.android.server.AttributeCache; import com.android.server.IntentResolver; -import com.android.internal.app.ProcessMap; -import com.android.server.SystemServer; +import com.android.server.LocalServices; +import com.android.server.ServiceThread; +import com.android.server.SystemService; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; import com.android.server.firewall.IntentFirewall; import com.android.server.pm.UserManagerService; import com.android.server.wm.AppTransition; -import com.android.server.wm.StackBox; import com.android.server.wm.WindowManagerService; import com.google.android.collect.Lists; import com.google.android.collect.Maps; import dalvik.system.Zygote; - import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; @@ -68,8 +71,8 @@ import org.xmlpull.v1.XmlSerializer; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; -import android.app.ActivityManager.StackBoxInfo; import android.app.ActivityManager.StackInfo; +import android.app.ActivityManagerInternal; import android.app.ActivityManagerNative; import android.app.ActivityOptions; import android.app.ActivityThread; @@ -134,6 +137,7 @@ import android.os.Bundle; import android.os.Debug; import android.os.DropBoxManager; import android.os.Environment; +import android.os.FactoryTest; import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; @@ -331,8 +335,6 @@ public final class ActivityManagerService extends ActivityManagerNative public IntentFirewall mIntentFirewall; - private final boolean mHeadless; - // Whether we should show our dialogs (ANR, crash, etc) or just perform their // default actuion automatically. Important for devices without direct input // devices. @@ -747,7 +749,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>(); + private static final ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>(); /** * All information we have collected about the runtime performance of @@ -797,9 +799,8 @@ public final class ActivityManagerService extends ActivityManagerNative /** * Used to control how we initialize the service. */ - boolean mStartRunning = false; ComponentName mTopComponent; - String mTopAction; + String mTopAction = Intent.ACTION_MAIN; String mTopData; boolean mProcessesReady = false; boolean mSystemReady = false; @@ -996,8 +997,7 @@ public final class ActivityManagerService extends ActivityManagerNative WindowManagerService mWindowManager; - static ActivityManagerService mSelf; - static ActivityThread mSystemThread; + final ActivityThread mSystemThread; int mCurrentUserId = 0; private UserManagerService mUserManager; @@ -1074,10 +1074,13 @@ public final class ActivityManagerService extends ActivityManagerNative */ private boolean mUserIsMonkey; - final Handler mHandler = new Handler() { - //public Handler() { - // if (localLOGV) Slog.v(TAG, "Handler started!"); - //} + final ServiceThread mHandlerThread; + final MainHandler mHandler; + + final class MainHandler extends Handler { + public MainHandler(Looper looper) { + super(looper, null, true); + } @Override public void handleMessage(Message msg) { @@ -1328,7 +1331,7 @@ public final class ActivityManagerService extends ActivityManagerNative String pkg = bundle.getString("pkg"); String reason = bundle.getString("reason"); forceStopPackageLocked(pkg, appid, restart, false, true, false, - false, UserHandle.USER_ALL, reason); + UserHandle.USER_ALL, reason); } } break; case FINALIZE_PENDING_INTENT_MSG: { @@ -1730,38 +1733,34 @@ public final class ActivityManagerService extends ActivityManagerNative } }; - public static void setSystemProcess() { + public void setSystemProcess() { try { - ActivityManagerService m = mSelf; - - ServiceManager.addService(Context.ACTIVITY_SERVICE, m, true); - ServiceManager.addService(ProcessStats.SERVICE_NAME, m.mProcessStats); - ServiceManager.addService("meminfo", new MemBinder(m)); - ServiceManager.addService("gfxinfo", new GraphicsBinder(m)); - ServiceManager.addService("dbinfo", new DbBinder(m)); + ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true); + ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats); + ServiceManager.addService("meminfo", new MemBinder(this)); + ServiceManager.addService("gfxinfo", new GraphicsBinder(this)); + ServiceManager.addService("dbinfo", new DbBinder(this)); if (MONITOR_CPU_USAGE) { - ServiceManager.addService("cpuinfo", new CpuBinder(m)); + ServiceManager.addService("cpuinfo", new CpuBinder(this)); } - ServiceManager.addService("permission", new PermissionController(m)); + ServiceManager.addService("permission", new PermissionController(this)); - ApplicationInfo info = - mSelf.mContext.getPackageManager().getApplicationInfo( - "android", STOCK_PM_FLAGS); + ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( + "android", STOCK_PM_FLAGS); mSystemThread.installSystemApplicationInfo(info); - synchronized (mSelf) { - ProcessRecord app = mSelf.newProcessRecordLocked(info, - info.processName, false); + synchronized (this) { + ProcessRecord app = newProcessRecordLocked(info, info.processName, false); app.persistent = true; app.pid = MY_PID; app.maxAdj = ProcessList.SYSTEM_ADJ; - app.makeActive(mSystemThread.getApplicationThread(), mSelf.mProcessStats); - mSelf.mProcessNames.put(app.processName, app.uid, app); - synchronized (mSelf.mPidsSelfLocked) { - mSelf.mPidsSelfLocked.put(app.pid, app); + app.makeActive(mSystemThread.getApplicationThread(), mProcessStats); + mProcessNames.put(app.processName, app.uid, app); + synchronized (mPidsSelfLocked) { + mPidsSelfLocked.put(app.pid, app); } - mSelf.updateLruProcessLocked(app, false, null); - mSelf.updateOomAdjLocked(); + updateLruProcessLocked(app, false, null); + updateOomAdjLocked(); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( @@ -1772,105 +1771,17 @@ public final class ActivityManagerService extends ActivityManagerNative public void setWindowManager(WindowManagerService wm) { mWindowManager = wm; mStackSupervisor.setWindowManager(wm); - wm.createStack(HOME_STACK_ID, -1, StackBox.TASK_STACK_GOES_OVER, 1.0f); } public void startObservingNativeCrashes() { - final NativeCrashListener ncl = new NativeCrashListener(); + final NativeCrashListener ncl = new NativeCrashListener(this); ncl.start(); } - public static final Context main(int factoryTest) { - AThread thr = new AThread(); - thr.start(); - - synchronized (thr) { - while (thr.mService == null) { - try { - thr.wait(); - } catch (InterruptedException e) { - } - } - } - - ActivityManagerService m = thr.mService; - mSelf = m; - ActivityThread at = ActivityThread.systemMain(); - mSystemThread = at; - Context context = at.getSystemContext(); - context.setTheme(android.R.style.Theme_Holo); - m.mContext = context; - m.mFactoryTest = factoryTest; - m.mIntentFirewall = new IntentFirewall(m.new IntentFirewallInterface()); - - m.mStackSupervisor = new ActivityStackSupervisor(m, context, thr.mLooper); - - m.mBatteryStatsService.publish(context); - m.mUsageStatsService.publish(context); - m.mAppOpsService.publish(context); - - synchronized (thr) { - thr.mReady = true; - thr.notifyAll(); - } - - m.startRunning(null, null, null, null); - - return context; - } - - public static ActivityManagerService self() { - return mSelf; - } - public IAppOpsService getAppOpsService() { return mAppOpsService; } - static class AThread extends Thread { - ActivityManagerService mService; - Looper mLooper; - boolean mReady = false; - - public AThread() { - super("ActivityManager"); - } - - @Override - public void run() { - Looper.prepare(); - - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_FOREGROUND); - android.os.Process.setCanSelfBackground(false); - - ActivityManagerService m = new ActivityManagerService(); - - synchronized (this) { - mService = m; - mLooper = Looper.myLooper(); - Watchdog.getInstance().addThread(new Handler(mLooper), getName()); - notifyAll(); - } - - synchronized (this) { - while (!mReady) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } - - // For debug builds, log event loop stalls to dropbox for analysis. - if (StrictMode.conditionallyEnableDebugLogging()) { - Slog.i(TAG, "Enabled StrictMode logging for AThread's Looper"); - } - - Looper.loop(); - } - } - static class MemBinder extends Binder { ActivityManagerService mActivityManagerService; MemBinder(ActivityManagerService activityManagerService) { @@ -1955,22 +1866,54 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private ActivityManagerService() { + public static final class Lifecycle extends SystemService { + private final ActivityManagerService mService; + + public Lifecycle(Context context) { + super(context); + mService = new ActivityManagerService(context); + } + + @Override + public void onStart() { + mService.start(); + } + + public ActivityManagerService getService() { + return mService; + } + } + + // Note: This method is invoked on the main thread but may need to attach various + // handlers to other threads. So take care to be explicit about the looper. + public ActivityManagerService(Context systemContext) { + mContext = systemContext; + mFactoryTest = FactoryTest.getMode(); + mSystemThread = ActivityThread.currentActivityThread(); + Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); - mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT, false); - mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT, true); + mHandlerThread = new ServiceThread(TAG, + android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); + mHandlerThread.start(); + mHandler = new MainHandler(mHandlerThread.getLooper()); + + mFgBroadcastQueue = new BroadcastQueue(this, mHandler, + "foreground", BROADCAST_FG_TIMEOUT, false); + mBgBroadcastQueue = new BroadcastQueue(this, mHandler, + "background", BROADCAST_BG_TIMEOUT, true); mBroadcastQueues[0] = mFgBroadcastQueue; mBroadcastQueues[1] = mBgBroadcastQueue; mServices = new ActiveServices(this); mProviderMap = new ProviderMap(this); + // TODO: Move creation of battery stats service outside of activity manager service. File dataDir = Environment.getDataDirectory(); File systemDir = new File(dataDir, "system"); systemDir.mkdirs(); mBatteryStatsService = new BatteryStatsService(new File( - systemDir, "batterystats.bin").toString()); + systemDir, "batterystats.bin").toString(), mHandler); mBatteryStatsService.getActiveStatistics().readLocked(); mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); mOnBattery = DEBUG_POWER ? true @@ -1980,12 +1923,10 @@ public final class ActivityManagerService extends ActivityManagerNative mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats")); mUsageStatsService = new UsageStatsService(new File(systemDir, "usagestats").toString()); - mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml")); + mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler); mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml")); - mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0")); - // User 0 is the first and only user that runs at boot. mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true)); mUserLru.add(Integer.valueOf(0)); @@ -2000,10 +1941,9 @@ public final class ActivityManagerService extends ActivityManagerNative mConfigurationSeq = mConfiguration.seq = 1; mProcessCpuTracker.init(); - mCompatModePackages = new CompatModePackages(this, systemDir); - - // Add ourself to the Watchdog monitors. - Watchdog.getInstance().addMonitor(this); + mCompatModePackages = new CompatModePackages(this, systemDir, mHandler); + mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler); + mStackSupervisor = new ActivityStackSupervisor(this); mProcessCpuThread = new Thread("CpuTracker") { @Override @@ -2034,7 +1974,19 @@ public final class ActivityManagerService extends ActivityManagerNative } } }; + + Watchdog.getInstance().addMonitor(this); + Watchdog.getInstance().addThread(mHandler); + } + + private void start() { mProcessCpuThread.start(); + + mBatteryStatsService.publish(mContext); + mUsageStatsService.publish(mContext); + mAppOpsService.publish(mContext); + + LocalServices.addService(ActivityManagerInternal.class, new LocalService()); } @Override @@ -2730,13 +2682,13 @@ public final class ActivityManagerService extends ActivityManagerNative } gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid)); } - if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) { - if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL + if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) { + if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL && mTopComponent != null && app.processName.equals(mTopComponent.getPackageName())) { uid = 0; } - if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL + if (mFactoryTest == FactoryTest.FACTORY_TEST_HIGH_LEVEL && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) { uid = 0; } @@ -2846,21 +2798,14 @@ public final class ActivityManagerService extends ActivityManagerNative Intent getHomeIntent() { Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); - if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { + if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) { intent.addCategory(Intent.CATEGORY_HOME); } return intent; } boolean startHomeActivityLocked(int userId) { - if (mHeadless) { - // Added because none of the other calls to ensureBootCompleted seem to fire - // when running headless. - ensureBootCompleted(); - return false; - } - - if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL + if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL && mTopAction == null) { // We are running in factory test mode, but unable to find // the factory test app, so just sit around displaying the @@ -2924,14 +2869,14 @@ public final class ActivityManagerService extends ActivityManagerNative // version than the last one shown, and we are not running in // low-level factory test mode. final ContentResolver resolver = mContext.getContentResolver(); - if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL && + if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL && Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0) { mCheckedForSetup = true; // See if we should be showing the platform update setup UI. Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP); - List<ResolveInfo> ris = mSelf.mContext.getPackageManager() + List<ResolveInfo> ris = mContext.getPackageManager() .queryIntentActivities(intent, PackageManager.GET_META_DATA); // We don't allow third party apps to replace this. @@ -2959,7 +2904,7 @@ public final class ActivityManagerService extends ActivityManagerNative intent.setComponent(new ComponentName( ri.activityInfo.packageName, ri.activityInfo.name)); mStackSupervisor.startActivityLocked(null, intent, null, ri.activityInfo, - null, null, 0, 0, 0, null, 0, null, false, null); + null, null, 0, 0, 0, null, 0, null, false, null, null); } } } @@ -3117,7 +3062,7 @@ public final class ActivityManagerService extends ActivityManagerNative // TODO: Switch to user app stacks here. return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd, - null, null, options, userId); + null, null, options, userId, null); } @Override @@ -3132,7 +3077,7 @@ public final class ActivityManagerService extends ActivityManagerNative // TODO: Switch to user app stacks here. mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd, - res, null, options, UserHandle.getCallingUserId()); + res, null, options, UserHandle.getCallingUserId(), null); return res; } @@ -3147,7 +3092,7 @@ public final class ActivityManagerService extends ActivityManagerNative // TODO: Switch to user app stacks here. int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, - null, null, null, config, options, userId); + null, null, null, config, options, userId, null); return ret; } @@ -3179,7 +3124,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } int ret = pir.sendInner(0, fillInIntent, resolvedType, null, null, - resultTo, resultWho, requestCode, flagsMask, flagsValues, options); + resultTo, resultWho, requestCode, flagsMask, flagsValues, options, null); return ret; } @@ -3278,7 +3223,7 @@ public final class ActivityManagerService extends ActivityManagerNative int res = mStackSupervisor.startActivityLocked(r.app.thread, intent, r.resolvedType, aInfo, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1, r.launchedFromUid, r.launchedFromPackage, 0, - options, false, null); + options, false, null, null); Binder.restoreCallingIdentity(origId); r.finishing = wasFinishing; @@ -3291,7 +3236,8 @@ public final class ActivityManagerService extends ActivityManagerNative final int startActivityInPackage(int uid, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, - String resultWho, int requestCode, int startFlags, Bundle options, int userId) { + String resultWho, int requestCode, int startFlags, Bundle options, int userId, + IActivityContainer container) { userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, true, "startActivityInPackage", null); @@ -3299,7 +3245,7 @@ public final class ActivityManagerService extends ActivityManagerNative // TODO: Switch to user app stacks here. int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, - null, null, null, null, options, userId); + null, null, null, null, options, userId, container); return ret; } @@ -3603,9 +3549,13 @@ public final class ActivityManagerService extends ActivityManagerNative */ private final void handleAppDiedLocked(ProcessRecord app, boolean restarting, boolean allowRestart) { + int pid = app.pid; cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1); if (!restarting) { removeLruProcessLocked(app); + if (pid > 0) { + ProcessList.remove(pid); + } } if (mProfileProc == app) { @@ -4175,9 +4125,9 @@ public final class ActivityManagerService extends ActivityManagerNative == PackageManager.PERMISSION_GRANTED) { forceStopPackageLocked(packageName, pkgUid, "clear data"); } else { - throw new SecurityException(pid+" does not have permission:"+ - android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" + - "for process:"+packageName); + throw new SecurityException("PID " + pid + " does not have permission " + + android.Manifest.permission.CLEAR_APP_USER_DATA + " to clear data" + + " of package " + packageName); } } @@ -4494,7 +4444,7 @@ public final class ActivityManagerService extends ActivityManagerNative private void forceStopPackageLocked(final String packageName, int uid, String reason) { forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false, - false, true, false, false, UserHandle.getUserId(uid), reason); + false, true, false, UserHandle.getUserId(uid), reason); Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, Uri.fromParts("package", packageName, null)); if (!mProcessesReady) { @@ -4510,7 +4460,7 @@ public final class ActivityManagerService extends ActivityManagerNative } private void forceStopUserLocked(int userId, String reason) { - forceStopPackageLocked(null, -1, false, false, true, false, false, userId, reason); + forceStopPackageLocked(null, -1, false, false, true, false, userId, reason); Intent intent = new Intent(Intent.ACTION_USER_STOPPED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); @@ -4595,7 +4545,7 @@ public final class ActivityManagerService extends ActivityManagerNative private final boolean forceStopPackageLocked(String name, int appId, boolean callerWillRestart, boolean purgeCache, boolean doit, - boolean evenPersistent, boolean uninstalling, int userId, String reason) { + boolean evenPersistent, int userId, String reason) { int i; int N; @@ -4687,7 +4637,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Remove transient permissions granted from/to this package/user removeUriPermissionsForPackageLocked(name, userId, false); - if (name == null || uninstalling) { + if (name == null) { // Remove pending intents. For now we only do this when force // stopping users, because we have some problems when doing this // for packages -- app widgets are not currently cleaned up for @@ -5000,7 +4950,7 @@ public final class ActivityManagerService extends ActivityManagerNative // See if the top visible activity is waiting to run in this process... if (normalMode) { try { - if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) { + if (mStackSupervisor.attachApplicationLocked(app)) { didSomething = true; } } catch (Exception e) { @@ -5132,7 +5082,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (pkgs != null) { for (String pkg : pkgs) { synchronized (ActivityManagerService.this) { - if (forceStopPackageLocked(pkg, -1, false, false, false, false, false, 0, + if (forceStopPackageLocked(pkg, -1, false, false, false, false, 0, "finished booting")) { setResultCode(Activity.RESULT_OK); return; @@ -5157,7 +5107,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { + if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) { // Start looking for apps that are abusing wake locks. Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY); @@ -7107,23 +7057,52 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public int createStack(int taskId, int relativeStackBoxId, int position, float weight) { + public IBinder getHomeActivityToken() throws RemoteException { enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, - "createStack()"); - if (DEBUG_STACK) Slog.d(TAG, "createStack: taskId=" + taskId + " relStackBoxId=" + - relativeStackBoxId + " position=" + position + " weight=" + weight); + "getHomeActivityToken()"); synchronized (this) { - long ident = Binder.clearCallingIdentity(); - try { - int stackId = mStackSupervisor.createStack(); - mWindowManager.createStack(stackId, relativeStackBoxId, position, weight); - if (taskId > 0) { - moveTaskToStack(taskId, stackId, true); - } - return stackId; - } finally { - Binder.restoreCallingIdentity(ident); + return mStackSupervisor.getHomeActivityToken(); + } + } + + @Override + public IActivityContainer createActivityContainer(IBinder parentActivityToken, + IActivityContainerCallback callback) throws RemoteException { + enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, + "createActivityContainer()"); + synchronized (this) { + if (parentActivityToken == null) { + throw new IllegalArgumentException("parent token must not be null"); + } + ActivityRecord r = ActivityRecord.forToken(parentActivityToken); + if (r == null) { + return null; + } + if (callback == null) { + throw new IllegalArgumentException("callback must not be null"); + } + return mStackSupervisor.createActivityContainer(r, callback); + } + } + + @Override + public void deleteActivityContainer(IActivityContainer container) throws RemoteException { + enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, + "deleteActivityContainer()"); + synchronized (this) { + mStackSupervisor.deleteActivityContainer(container); + } + } + + @Override + public IActivityContainer getEnclosingActivityContainer(IBinder activityToken) + throws RemoteException { + synchronized (this) { + ActivityStack stack = ActivityRecord.getStackLocked(activityToken); + if (stack != null) { + return stack.mActivityContainer; } + return null; } } @@ -7148,99 +7127,40 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void resizeStackBox(int stackBoxId, float weight) { + public void resizeStack(int stackBoxId, Rect bounds) { enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, "resizeStackBox()"); long ident = Binder.clearCallingIdentity(); try { - mWindowManager.resizeStackBox(stackBoxId, weight); + mWindowManager.resizeStack(stackBoxId, bounds); } finally { Binder.restoreCallingIdentity(ident); } } - private ArrayList<StackInfo> getStacks() { - synchronized (this) { - ArrayList<ActivityManager.StackInfo> list = new ArrayList<ActivityManager.StackInfo>(); - ArrayList<ActivityStack> stacks = mStackSupervisor.getStacks(); - for (ActivityStack stack : stacks) { - ActivityManager.StackInfo stackInfo = new ActivityManager.StackInfo(); - int stackId = stack.mStackId; - stackInfo.stackId = stackId; - stackInfo.bounds = mWindowManager.getStackBounds(stackId); - ArrayList<TaskRecord> tasks = stack.getAllTasks(); - final int numTasks = tasks.size(); - int[] taskIds = new int[numTasks]; - String[] taskNames = new String[numTasks]; - for (int i = 0; i < numTasks; ++i) { - final TaskRecord task = tasks.get(i); - taskIds[i] = task.taskId; - taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString() - : task.realActivity != null ? task.realActivity.flattenToString() - : task.getTopActivity() != null ? task.getTopActivity().packageName - : "unknown"; - } - stackInfo.taskIds = taskIds; - stackInfo.taskNames = taskNames; - list.add(stackInfo); - } - return list; - } - } - - private void addStackInfoToStackBoxInfo(StackBoxInfo stackBoxInfo, List<StackInfo> stackInfos) { - final int stackId = stackBoxInfo.stackId; - if (stackId >= 0) { - for (StackInfo stackInfo : stackInfos) { - if (stackId == stackInfo.stackId) { - stackBoxInfo.stack = stackInfo; - stackInfos.remove(stackInfo); - return; - } - } - } else { - addStackInfoToStackBoxInfo(stackBoxInfo.children[0], stackInfos); - addStackInfoToStackBoxInfo(stackBoxInfo.children[1], stackInfos); - } - } - @Override - public List<StackBoxInfo> getStackBoxes() { + public List<StackInfo> getAllStackInfos() { enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, - "getStackBoxes()"); + "getAllStackInfos()"); long ident = Binder.clearCallingIdentity(); try { - List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos(); synchronized (this) { - List<StackInfo> stackInfos = getStacks(); - for (StackBoxInfo stackBoxInfo : stackBoxInfos) { - addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos); - } + return mStackSupervisor.getAllStackInfosLocked(); } - return stackBoxInfos; } finally { Binder.restoreCallingIdentity(ident); } } @Override - public StackBoxInfo getStackBoxInfo(int stackBoxId) { + public StackInfo getStackInfo(int stackId) { enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, - "getStackBoxInfo()"); + "getStackInfo()"); long ident = Binder.clearCallingIdentity(); try { - List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos(); - StackBoxInfo info = null; synchronized (this) { - List<StackInfo> stackInfos = getStacks(); - for (StackBoxInfo stackBoxInfo : stackBoxInfos) { - addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos); - if (stackBoxInfo.stackBoxId == stackBoxId) { - info = stackBoxInfo; - } - } + return mStackSupervisor.getStackInfoLocked(stackId); } - return info; } finally { Binder.restoreCallingIdentity(ident); } @@ -8061,11 +7981,11 @@ public final class ActivityManagerService extends ActivityManagerNative } } - public static final void installSystemProviders() { + public final void installSystemProviders() { List<ProviderInfo> providers; - synchronized (mSelf) { - ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID); - providers = mSelf.generateApplicationProvidersLocked(app); + synchronized (this) { + ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID); + providers = generateApplicationProvidersLocked(app); if (providers != null) { for (int i=providers.size()-1; i>=0; i--) { ProviderInfo pi = (ProviderInfo)providers.get(i); @@ -8081,9 +8001,9 @@ public final class ActivityManagerService extends ActivityManagerNative mSystemThread.installSystemProviders(providers); } - mSelf.mCoreSettingsObserver = new CoreSettingsObserver(mSelf); + mCoreSettingsObserver = new CoreSettingsObserver(this); - mSelf.mUsageStatsService.monitorPackages(); + mUsageStatsService.monitorPackages(); } /** @@ -8248,13 +8168,7 @@ public final class ActivityManagerService extends ActivityManagerNative return mSleeping || mShuttingDown; } - public void goingToSleep() { - if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires permission " - + android.Manifest.permission.DEVICE_POWER); - } - + void goingToSleep() { synchronized(this) { mWentToSleep = true; updateEventDispatchingLocked(); @@ -8329,13 +8243,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - public void wakingUp() { - if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires permission " - + android.Manifest.permission.DEVICE_POWER); - } - + void wakingUp() { synchronized(this) { mWentToSleep = false; updateEventDispatchingLocked(); @@ -8445,7 +8353,7 @@ public final class ActivityManagerService extends ActivityManagerNative mDebugTransient = !persistent; if (packageName != null) { forceStopPackageLocked(packageName, -1, false, false, true, true, - false, UserHandle.USER_ALL, "set debug app"); + UserHandle.USER_ALL, "set debug app"); } } } finally { @@ -9055,25 +8963,6 @@ public final class ActivityManagerService extends ActivityManagerNative } } - public final void startRunning(String pkg, String cls, String action, - String data) { - synchronized(this) { - if (mStartRunning) { - return; - } - mStartRunning = true; - mTopComponent = pkg != null && cls != null - ? new ComponentName(pkg, cls) : null; - mTopAction = action != null ? action : Intent.ACTION_MAIN; - mTopData = data; - if (!mSystemReady) { - return; - } - } - - systemReady(null); - } - private void retrieveSettings() { final ContentResolver resolver = mContext.getContentResolver(); String debugApp = Settings.Global.getString( @@ -9286,9 +9175,6 @@ public final class ActivityManagerService extends ActivityManagerNative mAppOpsService.systemReady(); mSystemReady = true; - if (!mStartRunning) { - return; - } } ArrayList<ProcessRecord> procsToKill = null; @@ -9326,7 +9212,7 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized(this) { // Make sure we have no pre-ready processes sitting around. - if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) { + if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) { ResolveInfo ri = mContext.getPackageManager() .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST), STOCK_PM_FLAGS); @@ -9368,7 +9254,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (goingCallback != null) goingCallback.run(); synchronized (this) { - if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { + if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) { try { List apps = AppGlobals.getPackageManager(). getPersistentApplications(STOCK_PM_FLAGS); @@ -9501,10 +9387,6 @@ public final class ActivityManagerService extends ActivityManagerNative private boolean handleAppCrashLocked(ProcessRecord app, String shortMsg, String longMsg, String stackTrace) { - if (mHeadless) { - Log.e(TAG, "handleAppCrashLocked: " + app.processName); - return false; - } long now = SystemClock.uptimeMillis(); Long crashTime; @@ -10972,8 +10854,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (dumpAll) { pw.println(" Total persistent processes: " + numPers); - pw.println(" mStartRunning=" + mStartRunning - + " mProcessesReady=" + mProcessesReady + pw.println(" mProcessesReady=" + mProcessesReady + " mSystemReady=" + mSystemReady); pw.println(" mBooting=" + mBooting + " mBooted=" + mBooted @@ -12393,6 +12274,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean restarting, boolean allowRestart, int index) { if (index >= 0) { removeLruProcessLocked(app); + ProcessList.remove(app.pid); } mProcessesToGc.remove(app); @@ -13378,7 +13260,7 @@ public final class ActivityManagerService extends ActivityManagerNative String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); if (list != null && (list.length > 0)) { for (String pkg : list) { - forceStopPackageLocked(pkg, -1, false, true, true, false, false, userId, + forceStopPackageLocked(pkg, -1, false, true, true, false, userId, "storage unmount"); } sendPackageBroadcastLocked( @@ -13390,13 +13272,10 @@ public final class ActivityManagerService extends ActivityManagerNative if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals( intent.getAction()); - boolean fullUninstall = removed && - !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) { forceStopPackageLocked(ssp, UserHandle.getAppId( intent.getIntExtra(Intent.EXTRA_UID, -1)), false, true, true, - false, fullUninstall, userId, - removed ? "pkg removed" : "pkg changed"); + false, userId, removed ? "pkg removed" : "pkg changed"); } if (removed) { sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED, @@ -13874,7 +13753,7 @@ public final class ActivityManagerService extends ActivityManagerNative final long origId = Binder.clearCallingIdentity(); // Instrumentation can kill and relaunch even persistent processes - forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId, + forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, userId, "start instr"); ProcessRecord app = addAppLocked(ai, false); app.instrumentationClass = className; @@ -13942,7 +13821,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.instrumentationProfileFile = null; app.instrumentationArguments = null; - forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId, + forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, app.userId, "finished inst"); } @@ -14050,9 +13929,6 @@ public final class ActivityManagerService extends ActivityManagerNative */ boolean updateConfigurationLocked(Configuration values, ActivityRecord starting, boolean persistent, boolean initLocale) { - // do nothing if we are headless - if (mHeadless) return true; - int changes = 0; if (values != null) { @@ -14135,18 +14011,21 @@ public final class ActivityManagerService extends ActivityManagerNative boolean kept = true; final ActivityStack mainStack = mStackSupervisor.getFocusedStack(); - if (changes != 0 && starting == null) { - // If the configuration changed, and the caller is not already - // in the process of starting an activity, then find the top - // activity to check if its configuration needs to change. - starting = mainStack.topRunningActivityLocked(null); - } + // mainStack is null during startup. + if (mainStack != null) { + if (changes != 0 && starting == null) { + // If the configuration changed, and the caller is not already + // in the process of starting an activity, then find the top + // activity to check if its configuration needs to change. + starting = mainStack.topRunningActivityLocked(null); + } - if (starting != null) { - kept = mainStack.ensureActivityConfigurationLocked(starting, changes); - // And we need to make sure at this point that all other activities - // are made visible with the correct configuration. - mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes); + if (starting != null) { + kept = mainStack.ensureActivityConfigurationLocked(starting, changes); + // And we need to make sure at this point that all other activities + // are made visible with the correct configuration. + mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes); + } } if (values != null && mWindowManager != null) { @@ -15258,16 +15137,13 @@ public final class ActivityManagerService extends ActivityManagerNative } if (app.curAdj != app.setAdj) { - if (Process.setOomAdj(app.pid, app.curAdj)) { - if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v( - TAG, "Set " + app.pid + " " + app.processName + - " adj " + app.curAdj + ": " + app.adjType); - app.setAdj = app.curAdj; - } else { - success = false; - Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj); - } + ProcessList.setOomAdj(app.pid, app.curAdj); + if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v( + TAG, "Set " + app.pid + " " + app.processName + + " adj " + app.curAdj + ": " + app.adjType); + app.setAdj = app.curAdj; } + if (app.setSchedGroup != app.curSchedGroup) { app.setSchedGroup = app.curSchedGroup; if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG, @@ -16622,4 +16498,16 @@ public final class ActivityManagerService extends ActivityManagerNative info.applicationInfo = getAppInfoForUser(info.applicationInfo, userId); return info; } + + private final class LocalService extends ActivityManagerInternal { + @Override + public void goingToSleep() { + ActivityManagerService.this.goingToSleep(); + } + + @Override + public void wakingUp() { + ActivityManagerService.this.wakingUp(); + } + } } diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 49f29fe..5a9e690 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -21,6 +21,7 @@ import com.android.internal.R.styleable; import com.android.internal.app.ResolverActivity; import com.android.server.AttributeCache; import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.am.ActivityStackSupervisor.ActivityContainer; import android.app.ActivityOptions; import android.app.ResultInfo; @@ -138,11 +139,13 @@ final class ActivityRecord { boolean forceNewConfig; // force re-create with new config next time int launchCount; // count of launches since last state long lastLaunchTime; // time of last lauch of this activity + ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>(); String stringName; // for caching of toString(). private boolean inHistory; // are we in the history stack? final ActivityStackSupervisor mStackSupervisor; + ActivityContainer mInitialActivityContainer; void dump(PrintWriter pw, String prefix) { final long now = SystemClock.uptimeMillis(); @@ -347,7 +350,8 @@ final class ActivityRecord { int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo, String _resultWho, int _reqCode, - boolean _componentSpecified, ActivityStackSupervisor supervisor) { + boolean _componentSpecified, ActivityStackSupervisor supervisor, + ActivityContainer container) { service = _service; appToken = new Token(this); info = aInfo; @@ -378,6 +382,7 @@ final class ActivityRecord { idle = false; hasBeenLaunched = false; mStackSupervisor = supervisor; + mInitialActivityContainer = container; // This starts out true, since the initial state of an activity // is that we have everything, and we shouldn't never consider it @@ -481,7 +486,7 @@ final class ActivityRecord { void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) { if (task != null && task.removeActivity(this)) { if (task != newTask) { - mStackSupervisor.removeTask(task); + task.stack.removeTask(task); } else { Slog.d(TAG, "!!! REMOVE THIS LOG !!! setTask: nearly removed stack=" + (newTask == null ? null : newTask.stack)); diff --git a/services/java/com/android/server/am/ActivityResult.java b/services/core/java/com/android/server/am/ActivityResult.java index 6d5bdeb..6d5bdeb 100644 --- a/services/java/com/android/server/am/ActivityResult.java +++ b/services/core/java/com/android/server/am/ActivityResult.java diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 596c84d..e4b196e 100644..100755 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -36,10 +36,12 @@ import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE; import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES; import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; +import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE; + import com.android.internal.os.BatteryStatsImpl; -import com.android.internal.util.Objects; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService.ItemMatcher; +import com.android.server.am.ActivityStackSupervisor.ActivityContainer; import com.android.server.wm.AppTransition; import com.android.server.wm.TaskGroup; import com.android.server.wm.WindowManagerService; @@ -53,7 +55,6 @@ import android.app.IThumbnailReceiver; import android.app.ResultInfo; import android.app.ActivityManager.RunningTaskInfo; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; @@ -82,6 +83,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Objects; /** * State and management of a single stack of activities. @@ -139,8 +141,6 @@ final class ActivityStack { final ActivityManagerService mService; final WindowManagerService mWindowManager; - final Context mContext; - /** * The back history of all previous (and possibly still * running) activities. It contains #TaskRecord objects. @@ -229,6 +229,11 @@ final class ActivityStack { int mCurrentUser; final int mStackId; + final ActivityContainer mActivityContainer; + /** The other stacks, in order, on the attached display. Updated at attach/detach time. */ + ArrayList<ActivityStack> mStacks; + /** The attached Display's unique identifier, or -1 if detached */ + int mDisplayId; /** Run all ActivityStacks through this */ final ActivityStackSupervisor mStackSupervisor; @@ -319,7 +324,7 @@ final class ActivityStack { } } - private int numActivities() { + int numActivities() { int count = 0; for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { count += mTaskHistory.get(taskNdx).mActivities.size(); @@ -327,14 +332,14 @@ final class ActivityStack { return count; } - ActivityStack(ActivityManagerService service, Context context, Looper looper, int stackId) { - mHandler = new ActivityStackHandler(looper); - mService = service; - mWindowManager = service.mWindowManager; - mStackSupervisor = service.mStackSupervisor; - mContext = context; - mStackId = stackId; - mCurrentUser = service.mCurrentUserId; + ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer) { + mActivityContainer = activityContainer; + mStackSupervisor = activityContainer.getOuter(); + mService = mStackSupervisor.mService; + mHandler = new ActivityStackHandler(mService.mHandler.getLooper()); + mWindowManager = mService.mWindowManager; + mStackId = activityContainer.mStackId; + mCurrentUser = mService.mCurrentUserId; } boolean okToShow(ActivityRecord r) { @@ -436,25 +441,6 @@ final class ActivityStack { return null; } - boolean containsApp(ProcessRecord app) { - if (app == null) { - return false; - } - for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; - for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { - final ActivityRecord r = activities.get(activityNdx); - if (r.finishing) { - continue; - } - if (r.app == app) { - return true; - } - } - } - return false; - } - final boolean updateLRUListLocked(ActivityRecord r) { final boolean hadit = mLRUActivities.remove(r); mLRUActivities.add(r); @@ -465,6 +451,25 @@ final class ActivityStack { return mStackId == HOME_STACK_ID; } + final boolean isOnHomeDisplay() { + return isAttached() && + mActivityContainer.mActivityDisplay.mDisplayId == Display.DEFAULT_DISPLAY; + } + + final void moveToFront() { + if (isAttached()) { + if (isOnHomeDisplay()) { + mStackSupervisor.moveHomeStack(isHomeStack()); + } + mStacks.remove(this); + mStacks.add(this); + } + } + + final boolean isAttached() { + return mStacks != null; + } + /** * Returns the top activity in any existing task matching the given * Intent. Returns null if no such task is found. @@ -733,6 +738,12 @@ final class ActivityStack { mStackSupervisor.resumeTopActivitiesLocked(); return; } + + if (mActivityContainer.mParentActivity == null) { + // Top level stack, not a child. Look for child stacks. + mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping); + } + if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev); else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev); mResumedActivity = null; @@ -1016,6 +1027,16 @@ final class ActivityStack { return mStackSupervisor.isFrontStack(this); } + private void setVisibile(ActivityRecord r, boolean visible) { + r.visible = visible; + mWindowManager.setAppVisibility(r.appToken, visible); + final ArrayList<ActivityContainer> containers = r.mChildContainers; + for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) { + ActivityContainer container = containers.get(containerNdx); + container.setVisible(visible); + } + } + /** * Version of ensureActivitiesVisible that can easily be called anywhere. */ @@ -1094,8 +1115,7 @@ final class ActivityStack { if (!r.visible) { if (DEBUG_VISBILITY) Slog.v( TAG, "Starting and making visible: " + r); - r.visible = true; - mWindowManager.setAppVisibility(r.appToken, true); + setVisibile(r, true); } if (r != starting) { mStackSupervisor.startSpecificActivityLocked(r, false, false); @@ -1121,7 +1141,7 @@ final class ActivityStack { if (mTranslucentActivityWaiting != null) { mUndrawnActivitiesBelowTopTranslucent.add(r); } - mWindowManager.setAppVisibility(r.appToken, true); + setVisibile(r, true); r.sleeping = false; r.app.pendingUiClean = true; r.app.thread.scheduleWindowVisibility(r.appToken, true); @@ -1145,7 +1165,7 @@ final class ActivityStack { } else if (isActivityOverHome(r)) { if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r); showHomeBehindStack = true; - behindFullscreen = !isHomeStack(); + behindFullscreen = !isHomeStack() && r.frontOfTask && task.mOnTopOfHome; } } else { if (DEBUG_VISBILITY) Slog.v( @@ -1156,9 +1176,8 @@ final class ActivityStack { // sure they no longer are keeping the screen frozen. if (r.visible) { if (DEBUG_VISBILITY) Slog.v(TAG, "Making invisible: " + r); - r.visible = false; try { - mWindowManager.setAppVisibility(r.appToken, false); + setVisibile(r, false); switch (r.state) { case STOPPING: case STOPPED: @@ -1214,6 +1233,7 @@ final class ActivityStack { * occurred and the activity will be notified immediately. */ void notifyActivityDrawnLocked(ActivityRecord r) { + mActivityContainer.setDrawn(); if ((r == null) || (mUndrawnActivitiesBelowTopTranslucent.remove(r) && mUndrawnActivitiesBelowTopTranslucent.isEmpty())) { @@ -1224,12 +1244,14 @@ final class ActivityStack { mUndrawnActivitiesBelowTopTranslucent.clear(); mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); - if (waitingActivity != null && waitingActivity.app != null && - waitingActivity.app.thread != null) { - try { - waitingActivity.app.thread.scheduleTranslucentConversionComplete( - waitingActivity.appToken, r != null); - } catch (RemoteException e) { + if (waitingActivity != null) { + mWindowManager.setWindowOpaque(waitingActivity.appToken, false); + if (waitingActivity.app != null && waitingActivity.app.thread != null) { + try { + waitingActivity.app.thread.scheduleTranslucentConversionComplete( + waitingActivity.appToken, r != null); + } catch (RemoteException e) { + } } } } @@ -1251,6 +1273,14 @@ final class ActivityStack { final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen(""); + ActivityRecord parent = mActivityContainer.mParentActivity; + if ((parent != null && parent.state != ActivityState.RESUMED) || + !mActivityContainer.isAttached()) { + // Do not resume this stack if its parent is not resumed. + // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st. + return false; + } + // Find the first activity that is not finishing. ActivityRecord next = topRunningActivityLocked(null); @@ -1265,7 +1295,8 @@ final class ActivityStack { ActivityOptions.abort(options); if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home"); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); - return mStackSupervisor.resumeHomeActivity(prev); + // Only resume home if on home display + return isOnHomeDisplay() && mStackSupervisor.resumeHomeActivity(prev); } next.delayedResume = false; @@ -1295,8 +1326,10 @@ final class ActivityStack { final int taskNdx = mTaskHistory.indexOf(prevTask) + 1; mTaskHistory.get(taskNdx).mOnTopOfHome = true; } else { - if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Launching home next"); - return mStackSupervisor.resumeHomeActivity(prev); + if (DEBUG_STATES && isOnHomeDisplay()) Slog.d(TAG, + "resumeTopActivityLocked: Launching home next"); + // Only resume home if on home display + return isOnHomeDisplay() && mStackSupervisor.resumeHomeActivity(prev); } } @@ -1658,10 +1691,14 @@ final class ActivityStack { private void insertTaskAtTop(TaskRecord task) { // If this is being moved to the top by another activity or being launched from the home // activity, set mOnTopOfHome accordingly. - ActivityStack lastStack = mStackSupervisor.getLastStack(); - final boolean fromHome = lastStack == null ? true : lastStack.isHomeStack(); - if (!isHomeStack() && (fromHome || topTask() != task)) { - task.mOnTopOfHome = fromHome; + if (isOnHomeDisplay()) { + ActivityStack lastStack = mStackSupervisor.getLastStack(); + final boolean fromHome = lastStack.isHomeStack(); + if (!isHomeStack() && (fromHome || topTask() != task)) { + task.mOnTopOfHome = fromHome; + } + } else { + task.mOnTopOfHome = false; } mTaskHistory.remove(task); @@ -2350,7 +2387,7 @@ final class ActivityStack { ArrayList<ActivityRecord> activities = r.task.mActivities; for (int index = activities.indexOf(r); index >= 0; --index) { ActivityRecord cur = activities.get(index); - if (!Objects.equal(cur.taskAffinity, r.taskAffinity)) { + if (!Objects.equals(cur.taskAffinity, r.taskAffinity)) { break; } finishActivityLocked(cur, Activity.RESULT_CANCELED, null, "request-affinity", true); @@ -2514,10 +2551,25 @@ final class ActivityStack { // activity into the stopped state and then finish it. if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r); mStackSupervisor.mFinishingActivities.add(r); + r.resumeKeyDispatchingLocked(); mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null); return r; } + void finishAllActivitiesLocked() { + for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { + final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + if (r.finishing) { + continue; + } + Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r); + finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false); + } + } + } + final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode, Intent resultData) { final ActivityRecord srec = ActivityRecord.forToken(token); @@ -2586,7 +2638,7 @@ final class ActivityStack { int res = mStackSupervisor.startActivityLocked(srec.app.thread, destIntent, null, aInfo, parent.appToken, null, 0, -1, parent.launchedFromUid, parent.launchedFromPackage, - 0, null, true, null); + 0, null, true, null, null); foundParentInTask = res == ActivityManager.START_SUCCESS; } catch (RemoteException e) { foundParentInTask = false; @@ -2664,7 +2716,8 @@ final class ActivityStack { r.finishLaunchTickingLocked(); } - final void removeActivityFromHistoryLocked(ActivityRecord r) { + private void removeActivityFromHistoryLocked(ActivityRecord r) { + mStackSupervisor.removeChildActivityContainers(r); finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null); r.makeFinishing(); if (DEBUG_ADD_REMOVE) { @@ -2672,15 +2725,6 @@ final class ActivityStack { here.fillInStackTrace(); Slog.i(TAG, "Removing activity " + r + " from stack"); } - final TaskRecord task = r.task; - if (task != null && task.removeActivity(r)) { - if (DEBUG_STACK) Slog.i(TAG, - "removeActivityFromHistoryLocked: last activity removed from " + this); - if (mStackSupervisor.isFrontStack(this) && task == topTask() && task.mOnTopOfHome) { - mStackSupervisor.moveHomeToTop(); - } - mStackSupervisor.removeTask(task); - } r.takeFromHistory(); removeTimeoutsForActivityLocked(r); if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (removed from history)"); @@ -2691,6 +2735,15 @@ final class ActivityStack { if (VALIDATE_TOKENS) { validateAppTokensLocked(); } + final TaskRecord task = r.task; + if (task != null && task.removeActivity(r)) { + if (DEBUG_STACK) Slog.i(TAG, + "removeActivityFromHistoryLocked: last activity removed from " + this); + if (mStackSupervisor.isFrontStack(this) && task == topTask() && task.mOnTopOfHome) { + mStackSupervisor.moveHomeToTop(); + } + removeTask(task); + } cleanUpActivityServicesLocked(r); r.removeUriPermissionsLocked(); } @@ -2752,7 +2805,6 @@ final class ActivityStack { } if (activityRemoved) { mStackSupervisor.resumeTopActivitiesLocked(); - } } @@ -3038,7 +3090,7 @@ final class ActivityStack { return; } - mStackSupervisor.moveHomeStack(isHomeStack()); + moveToFront(); // Shift all activities with this task up to the top // of the stack, keeping them in the same internal order. @@ -3147,10 +3199,8 @@ final class ActivityStack { } final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null; - if (task == tr && task.mOnTopOfHome || numTasks <= 1) { - if (task != null) { - task.mOnTopOfHome = false; - } + if (task == tr && tr.mOnTopOfHome || numTasks <= 1 && isOnHomeDisplay()) { + tr.mOnTopOfHome = false; return mStackSupervisor.resumeHomeActivity(null); } @@ -3310,6 +3360,8 @@ final class ActivityStack { r.startFreezingScreenLocked(r.app, 0); + mStackSupervisor.removeChildActivityContainers(r); + try { if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, (andResume ? "Relaunching to RESUMED " : "Relaunching to PAUSED ") @@ -3342,14 +3394,20 @@ final class ActivityStack { for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { final ActivityRecord r = activities.get(activityNdx); if (r.appToken == token) { - return true; + return true; } if (r.fullscreen && !r.finishing) { return false; } } } - return true; + final ActivityRecord r = ActivityRecord.forToken(token); + if (r == null) { + return false; + } + if (r.finishing) Slog.e(TAG, "willActivityBeVisibleLocked: Returning false," + + " would have returned true for r=" + r); + return !r.finishing; } void closeSystemDialogsLocked() { @@ -3588,14 +3646,30 @@ final class ActivityStack { return starting; } - boolean removeTask(TaskRecord task) { + void removeTask(TaskRecord task) { + mWindowManager.removeTask(task.taskId); + final ActivityRecord r = mResumedActivity; + if (r != null && r.task == task) { + mResumedActivity = null; + } + final int taskNdx = mTaskHistory.indexOf(task); final int topTaskNdx = mTaskHistory.size() - 1; if (task.mOnTopOfHome && taskNdx < topTaskNdx) { mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true; } mTaskHistory.remove(task); - return mTaskHistory.isEmpty(); + + if (mTaskHistory.isEmpty()) { + if (DEBUG_STACK) Slog.i(TAG, "removeTask: moving to back stack=" + this); + if (isOnHomeDisplay()) { + mStackSupervisor.moveHomeStack(!isHomeStack()); + } + if (mStacks != null) { + mStacks.remove(this); + mStacks.add(0, this); + } + } } TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, boolean toTop) { diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index d616f1b..e942afb 100644 --- a/services/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -34,8 +34,11 @@ import static com.android.server.am.ActivityManagerService.TAG; import android.app.Activity; import android.app.ActivityManager; +import android.app.ActivityManager.StackInfo; import android.app.ActivityOptions; import android.app.AppGlobals; +import android.app.IActivityContainer; +import android.app.IActivityContainerCallback; import android.app.IActivityManager; import android.app.IApplicationThread; import android.app.IThumbnailReceiver; @@ -53,6 +56,13 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; +import android.graphics.Point; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; +import android.hardware.display.DisplayManagerGlobal; +import android.hardware.display.VirtualDisplay; +import android.hardware.input.InputManager; +import android.hardware.input.InputManagerInternal; import android.os.Binder; import android.os.Bundle; import android.os.Debug; @@ -68,13 +78,18 @@ import android.os.SystemClock; import android.os.UserHandle; import android.util.EventLog; import android.util.Slog; -import android.util.SparseIntArray; +import android.util.SparseArray; +import android.util.SparseIntArray; +import android.view.Display; +import android.view.DisplayInfo; +import android.view.InputEvent; +import android.view.Surface; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.os.TransferPipe; +import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService.PendingActivityLaunch; import com.android.server.am.ActivityStack.ActivityState; -import com.android.server.wm.StackBox; import com.android.server.wm.WindowManagerService; import java.io.FileDescriptor; @@ -83,7 +98,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -public final class ActivityStackSupervisor { +public final class ActivityStackSupervisor implements DisplayListener { static final boolean DEBUG = ActivityManagerService.DEBUG || false; static final boolean DEBUG_ADD_REMOVE = DEBUG || false; static final boolean DEBUG_APP = DEBUG || false; @@ -107,19 +122,24 @@ public final class ActivityStackSupervisor { static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2; static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3; static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4; + static final int HANDLE_DISPLAY_ADDED = FIRST_SUPERVISOR_STACK_MSG + 5; + static final int HANDLE_DISPLAY_CHANGED = FIRST_SUPERVISOR_STACK_MSG + 6; + static final int HANDLE_DISPLAY_REMOVED = FIRST_SUPERVISOR_STACK_MSG + 7; + static final int CONTAINER_CALLBACK_VISIBILITY = FIRST_SUPERVISOR_STACK_MSG + 8; + + private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay"; // For debugging to make sure the caller when acquiring/releasing our // wake lock is the system process. static final boolean VALIDATE_WAKE_LOCK_CALLER = false; final ActivityManagerService mService; - final Context mContext; - final Looper mLooper; final ActivityStackSupervisorHandler mHandler; /** Short cut */ WindowManagerService mWindowManager; + DisplayManager mDisplayManager; /** Dismiss the keyguard after the next activity is displayed? */ boolean mDismissKeyguardOnNextActivity = false; @@ -134,22 +154,17 @@ public final class ActivityStackSupervisor { /** The current user */ private int mCurrentUser; - /** The stack containing the launcher app */ + /** The stack containing the launcher app. Assumed to always be attached to + * Display.DEFAULT_DISPLAY. */ private ActivityStack mHomeStack; - /** The non-home stack currently receiving input or launching the next activity. If home is - * in front then mHomeStack overrides mFocusedStack. - * DO NOT ACCESS DIRECTLY - It may be null, use getFocusedStack() */ + /** The stack currently receiving input or launching the next activity. */ private ActivityStack mFocusedStack; - /** All the non-launcher stacks */ - private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>(); - - private static final int STACK_STATE_HOME_IN_FRONT = 0; - private static final int STACK_STATE_HOME_TO_BACK = 1; - private static final int STACK_STATE_HOME_IN_BACK = 2; - private static final int STACK_STATE_HOME_TO_FRONT = 3; - private int mStackState = STACK_STATE_HOME_IN_FRONT; + /** If this is the same as mFocusedStack then the activity on the top of the focused stack has + * been resumed. If stacks are changing position this will hold the old stack until the new + * stack becomes resumed after which it will be set to mFocusedStack. */ + private ActivityStack mLastFocusedStack; /** List of activities that are waiting for a new activity to become visible before completing * whatever operation they are supposed to do. */ @@ -206,14 +221,21 @@ public final class ActivityStackSupervisor { /** Stack id of the front stack when user switched, indexed by userId. */ SparseIntArray mUserStackInFront = new SparseIntArray(2); - public ActivityStackSupervisor(ActivityManagerService service, Context context, - Looper looper) { + // TODO: Add listener for removal of references. + /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */ + SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>(); + + /** Mapping from displayId to display current state */ + private final SparseArray<ActivityDisplay> mActivityDisplays = + new SparseArray<ActivityDisplay>(); + + InputManagerInternal mInputManagerInternal; + + public ActivityStackSupervisor(ActivityManagerService service) { mService = service; - mContext = context; - mLooper = looper; - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep"); - mHandler = new ActivityStackSupervisorHandler(looper); + mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper()); if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) { throw new IllegalStateException("Calling must be system uid"); } @@ -223,9 +245,25 @@ public final class ActivityStackSupervisor { } void setWindowManager(WindowManagerService wm) { - mWindowManager = wm; - mHomeStack = new ActivityStack(mService, mContext, mLooper, HOME_STACK_ID); - mStacks.add(mHomeStack); + synchronized (mService) { + mWindowManager = wm; + + mDisplayManager = + (DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE); + mDisplayManager.registerDisplayListener(this, null); + + Display[] displays = mDisplayManager.getDisplays(); + for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) { + final int displayId = displays[displayNdx].getDisplayId(); + ActivityDisplay activityDisplay = new ActivityDisplay(displayId); + mActivityDisplays.put(displayId, activityDisplay); + } + + createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY); + mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID); + + mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); + } } void dismissKeyguard() { @@ -237,43 +275,42 @@ public final class ActivityStackSupervisor { } ActivityStack getFocusedStack() { - if (mFocusedStack == null) { - return mHomeStack; - } - switch (mStackState) { - case STACK_STATE_HOME_IN_FRONT: - case STACK_STATE_HOME_TO_FRONT: - return mHomeStack; - case STACK_STATE_HOME_IN_BACK: - case STACK_STATE_HOME_TO_BACK: - default: - return mFocusedStack; - } + return mFocusedStack; } ActivityStack getLastStack() { - switch (mStackState) { - case STACK_STATE_HOME_IN_FRONT: - case STACK_STATE_HOME_TO_BACK: - return mHomeStack; - case STACK_STATE_HOME_TO_FRONT: - case STACK_STATE_HOME_IN_BACK: - default: - return mFocusedStack; - } + return mLastFocusedStack; } + // TODO: Split into two methods isFrontStack for any visible stack and isFrontmostStack for the + // top of all visible stacks. boolean isFrontStack(ActivityStack stack) { - return !(stack.isHomeStack() ^ getFocusedStack().isHomeStack()); + final ActivityRecord parent = stack.mActivityContainer.mParentActivity; + if (parent != null) { + stack = parent.task.stack; + } + ArrayList<ActivityStack> stacks = stack.mStacks; + if (stacks != null && !stacks.isEmpty()) { + return stack == stacks.get(stacks.size() - 1); + } + return false; } void moveHomeStack(boolean toFront) { - final boolean homeInFront = isFrontStack(mHomeStack); - if (homeInFront ^ toFront) { - if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: mStackState old=" + - stackStateToString(mStackState) + " new=" + stackStateToString(homeInFront ? - STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT)); - mStackState = homeInFront ? STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT; + ArrayList<ActivityStack> stacks = mHomeStack.mStacks; + int topNdx = stacks.size() - 1; + if (topNdx <= 0) { + return; + } + ActivityStack topStack = stacks.get(topNdx); + final boolean homeInFront = topStack == mHomeStack; + if (homeInFront != toFront) { + mLastFocusedStack = topStack; + stacks.remove(mHomeStack); + stacks.add(toFront ? topNdx : 0, mHomeStack); + mFocusedStack = stacks.get(topNdx); + if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old=" + topStack + " new=" + + mFocusedStack); } } @@ -301,21 +338,29 @@ public final class ActivityStackSupervisor { } TaskRecord anyTaskForIdLocked(int id) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - ActivityStack stack = mStacks.get(stackNdx); - TaskRecord task = stack.taskForIdLocked(id); - if (task != null) { - return task; + int numDisplays = mActivityDisplays.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + ActivityStack stack = stacks.get(stackNdx); + TaskRecord task = stack.taskForIdLocked(id); + if (task != null) { + return task; + } } } return null; } ActivityRecord isInAnyStackLocked(IBinder token) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityRecord r = mStacks.get(stackNdx).isInStackLocked(token); - if (r != null) { - return r; + int numDisplays = mActivityDisplays.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityRecord r = stacks.get(stackNdx).isInStackLocked(token); + if (r != null) { + return r; + } } } return null; @@ -331,26 +376,6 @@ public final class ActivityStackSupervisor { return mCurTaskId; } - void removeTask(TaskRecord task) { - mWindowManager.removeTask(task.taskId); - final ActivityStack stack = task.stack; - final ActivityRecord r = stack.mResumedActivity; - if (r != null && r.task == task) { - stack.mResumedActivity = null; - } - if (stack.removeTask(task) && !stack.isHomeStack()) { - if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack " + stack); - mStacks.remove(stack); - final int stackId = stack.mStackId; - final int nextStackId = mWindowManager.removeStack(stackId); - // TODO: Perhaps we need to let the ActivityManager determine the next focus... - if (mFocusedStack == null || mFocusedStack.mStackId == stackId) { - // If this is the last app stack, set mFocusedStack to null. - mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId); - } - } - } - ActivityRecord resumedAppLocked() { ActivityStack stack = getFocusedStack(); if (stack == null) { @@ -366,29 +391,29 @@ public final class ActivityStackSupervisor { return resumedActivity; } - boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception { - boolean didSomething = false; + boolean attachApplicationLocked(ProcessRecord app) throws Exception { final String processName = app.processName; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack)) { - continue; - } - ActivityRecord hr = stack.topRunningActivityLocked(null); - if (hr != null) { - if (hr.app == null && app.uid == hr.info.applicationInfo.uid - && processName.equals(hr.processName)) { - try { - if (headless) { - Slog.e(TAG, "Starting activities not supported on headless device: " - + hr); - } else if (realStartActivityLocked(hr, app, true, true)) { - didSomething = true; + boolean didSomething = false; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!isFrontStack(stack)) { + continue; + } + ActivityRecord hr = stack.topRunningActivityLocked(null); + if (hr != null) { + if (hr.app == null && app.uid == hr.info.applicationInfo.uid + && processName.equals(hr.processName)) { + try { + if (realStartActivityLocked(hr, app, true, true)) { + didSomething = true; + } + } catch (Exception e) { + Slog.w(TAG, "Exception in new application when starting activity " + + hr.intent.getComponent().flattenToShortString(), e); + throw e; } - } catch (Exception e) { - Slog.w(TAG, "Exception in new application when starting activity " - + hr.intent.getComponent().flattenToShortString(), e); - throw e; } } } @@ -400,53 +425,54 @@ public final class ActivityStackSupervisor { } boolean allResumedActivitiesIdle() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack)) { - continue; - } - final ActivityRecord resumedActivity = stack.mResumedActivity; - if (resumedActivity == null || !resumedActivity.idle) { - return false; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!isFrontStack(stack) || stack.numActivities() == 0) { + continue; + } + final ActivityRecord resumedActivity = stack.mResumedActivity; + if (resumedActivity == null || !resumedActivity.idle) { + if (DEBUG_STATES) Slog.d(TAG, "allResumedActivitiesIdle: stack=" + + stack.mStackId + " " + resumedActivity + " not idle"); + return false; + } } } return true; } boolean allResumedActivitiesComplete() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - final ActivityRecord r = stack.mResumedActivity; - if (r != null && r.state != ActivityState.RESUMED) { - return false; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (isFrontStack(stack)) { + final ActivityRecord r = stack.mResumedActivity; + if (r != null && r.state != ActivityState.RESUMED) { + return false; + } } } } // TODO: Not sure if this should check if all Paused are complete too. - switch (mStackState) { - case STACK_STATE_HOME_TO_BACK: - if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" + - stackStateToString(STACK_STATE_HOME_TO_BACK) + " new=" + - stackStateToString(STACK_STATE_HOME_IN_BACK)); - mStackState = STACK_STATE_HOME_IN_BACK; - break; - case STACK_STATE_HOME_TO_FRONT: - if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" + - stackStateToString(STACK_STATE_HOME_TO_FRONT) + " new=" + - stackStateToString(STACK_STATE_HOME_IN_FRONT)); - mStackState = STACK_STATE_HOME_IN_FRONT; - break; - } + if (DEBUG_STACK) Slog.d(TAG, + "allResumedActivitiesComplete: mLastFocusedStack changing from=" + + mLastFocusedStack + " to=" + mFocusedStack); + mLastFocusedStack = mFocusedStack; return true; } boolean allResumedActivitiesVisible() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - final ActivityRecord r = stack.mResumedActivity; - if (r != null && (!r.nowVisible || r.waitingVisible)) { - return false; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + final ActivityRecord r = stack.mResumedActivity; + if (r != null && (!r.nowVisible || r.waitingVisible)) { + return false; + } } } return true; @@ -459,13 +485,16 @@ public final class ActivityStackSupervisor { */ boolean pauseBackStacks(boolean userLeaving) { boolean someActivityPaused = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack) && stack.mResumedActivity != null) { - if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack + - " mResumedActivity=" + stack.mResumedActivity); - stack.startPausingLocked(userLeaving, false); - someActivityPaused = true; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!isFrontStack(stack) && stack.mResumedActivity != null) { + if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack + + " mResumedActivity=" + stack.mResumedActivity); + stack.startPausingLocked(userLeaving, false); + someActivityPaused = true; + } } } return someActivityPaused; @@ -473,23 +502,40 @@ public final class ActivityStackSupervisor { boolean allPausedActivitiesComplete() { boolean pausing = true; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - final ActivityRecord r = stack.mPausingActivity; - if (r != null && r.state != ActivityState.PAUSED - && r.state != ActivityState.STOPPED - && r.state != ActivityState.STOPPING) { - if (DEBUG_STATES) { - Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state); - pausing = false; - } else { - return false; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + final ActivityRecord r = stack.mPausingActivity; + if (r != null && r.state != ActivityState.PAUSED + && r.state != ActivityState.STOPPED + && r.state != ActivityState.STOPPING) { + if (DEBUG_STATES) { + Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state); + pausing = false; + } else { + return false; + } } } } return pausing; } + void pauseChildStacks(ActivityRecord parent, boolean userLeaving, boolean uiSleeping) { + // TODO: Put all stacks in supervisor and iterate through them instead. + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (stack.mResumedActivity != null && + stack.mActivityContainer.mParentActivity == parent) { + stack.startPausingLocked(userLeaving, uiSleeping); + } + } + } + } + void reportActivityVisibleLocked(ActivityRecord r) { for (int i = mWaitingActivityVisible.size()-1; i >= 0; i--) { WaitResult w = mWaitingActivityVisible.get(i); @@ -525,8 +571,10 @@ public final class ActivityStackSupervisor { return r; } - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); + // Return to the home stack. + final ArrayList<ActivityStack> stacks = mHomeStack.mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (stack != focusedStack && isFrontStack(stack)) { r = stack.topRunningActivityLocked(null); if (r != null) { @@ -542,15 +590,19 @@ public final class ActivityStackSupervisor { ActivityRecord r = null; // Gather all of the running tasks for each stack into runningTaskLists. - final int numStacks = mStacks.size(); - ArrayList<RunningTaskInfo>[] runningTaskLists = new ArrayList[numStacks]; - for (int stackNdx = numStacks - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>(); - runningTaskLists[stackNdx] = stackTaskList; - final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList); - if (isFrontStack(stack)) { - r = ar; + ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists = + new ArrayList<ArrayList<RunningTaskInfo>>(); + final int numDisplays = mActivityDisplays.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>(); + runningTaskLists.add(stackTaskList); + final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList); + if (r == null && isFrontStack(stack)) { + r = ar; + } } } @@ -559,8 +611,9 @@ public final class ActivityStackSupervisor { while (maxNum > 0) { long mostRecentActiveTime = Long.MIN_VALUE; ArrayList<RunningTaskInfo> selectedStackList = null; - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists[stackNdx]; + final int numTaskLists = runningTaskLists.size(); + for (int stackNdx = 0; stackNdx < numTaskLists; ++stackNdx) { + ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists.get(stackNdx); if (!stackTaskList.isEmpty()) { final long lastActiveTime = stackTaskList.get(0).lastActiveTime; if (lastActiveTime > mostRecentActiveTime) { @@ -630,14 +683,14 @@ public final class ActivityStackSupervisor { void startHomeActivity(Intent intent, ActivityInfo aInfo) { moveHomeToTop(); startActivityLocked(null, intent, null, aInfo, null, null, 0, 0, 0, null, 0, - null, false, null); + null, false, null, null); } final int startActivityMayWait(IApplicationThread caller, int callingUid, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile, ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config, - Bundle options, int userId) { + Bundle options, int userId, IActivityContainer iContainer) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -651,6 +704,7 @@ public final class ActivityStackSupervisor { ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, profileFile, profileFd, userId); + ActivityContainer container = (ActivityContainer)iContainer; synchronized (mService) { int callingPid; if (callingUid >= 0) { @@ -662,7 +716,12 @@ public final class ActivityStackSupervisor { callingPid = callingUid = -1; } - final ActivityStack stack = getFocusedStack(); + final ActivityStack stack; + if (container == null || container.mStack.isOnHomeDisplay()) { + stack = getFocusedStack(); + } else { + stack = container.mStack; + } stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0; if (DEBUG_CONFIGURATION) Slog.v(TAG, @@ -738,9 +797,9 @@ public final class ActivityStackSupervisor { } } - int res = startActivityLocked(caller, intent, resolvedType, - aInfo, resultTo, resultWho, requestCode, callingPid, callingUid, - callingPackage, startFlags, options, componentSpecified, null); + int res = startActivityLocked(caller, intent, resolvedType, aInfo, resultTo, resultWho, + requestCode, callingPid, callingUid, callingPackage, startFlags, options, + componentSpecified, null, container); if (stack.mConfigWillChange) { // If the caller also wants to switch to a new configuration, @@ -855,7 +914,7 @@ public final class ActivityStackSupervisor { } int res = startActivityLocked(caller, intent, resolvedTypes[i], aInfo, resultTo, null, -1, callingPid, callingUid, callingPackage, - 0, theseOptions, componentSpecified, outActivity); + 0, theseOptions, componentSpecified, outActivity, null); if (res < 0) { return res; } @@ -1079,7 +1138,7 @@ public final class ActivityStackSupervisor { Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options, - boolean componentSpecified, ActivityRecord[] outActivity) { + boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container) { int err = ActivityManager.START_SUCCESS; ProcessRecord callerApp = null; @@ -1099,7 +1158,11 @@ public final class ActivityStackSupervisor { if (err == ActivityManager.START_SUCCESS) { final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0; Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) - + "} from pid " + (callerApp != null ? callerApp.pid : callingPid)); + + "} from pid " + (callerApp != null ? callerApp.pid : callingPid) + + " on display " + (container == null ? (mFocusedStack == null ? + Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) : + (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY : + container.mActivityDisplay.mDisplayId))); } ActivityRecord sourceRecord = null; @@ -1227,8 +1290,8 @@ public final class ActivityStackSupervisor { } ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage, - intent, resolvedType, aInfo, mService.mConfiguration, - resultRecord, resultWho, requestCode, componentSpecified, this); + intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, + requestCode, componentSpecified, this, container); if (outActivity != null) { outActivity[0] = r; } @@ -1276,25 +1339,35 @@ public final class ActivityStackSupervisor { if (r.isApplicationActivity() || (task != null && task.isApplicationTask())) { if (task != null) { final ActivityStack taskStack = task.stack; - if (mFocusedStack != taskStack) { - if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, - "adjustStackFocus: Setting focused stack to r=" + r + " task=" + task); - mFocusedStack = taskStack.isHomeStack() ? null : taskStack; - } else { - if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, - "adjustStackFocus: Focused stack already=" + mFocusedStack); + if (taskStack.isOnHomeDisplay()) { + if (mFocusedStack != taskStack) { + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting " + + "focused stack to r=" + r + " task=" + task); + mFocusedStack = taskStack; + } else { + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, + "adjustStackFocus: Focused stack already=" + mFocusedStack); + } } return taskStack; } - if (mFocusedStack != null) { + final ActivityContainer container = r.mInitialActivityContainer; + if (container != null) { + // The first time put it on the desired stack, after this put on task stack. + r.mInitialActivityContainer = null; + return container.mStack; + } + + if (mFocusedStack != mHomeStack) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Have a focused stack=" + mFocusedStack); return mFocusedStack; } - for (int stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) { - ActivityStack stack = mStacks.get(stackNdx); + final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks; + for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = homeDisplayStacks.get(stackNdx); if (!stack.isHomeStack()) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting focused stack=" + stack); @@ -1303,9 +1376,8 @@ public final class ActivityStackSupervisor { } } - // Time to create the first app stack for this user. - int stackId = - mService.createStack(-1, HOME_STACK_ID, StackBox.TASK_STACK_GOES_OVER, 1.0f); + // Need to create an app stack for this user. + int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY); if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r + " stackId=" + stackId); mFocusedStack = getStack(stackId); @@ -1315,30 +1387,17 @@ public final class ActivityStackSupervisor { } void setFocusedStack(ActivityRecord r) { - if (r == null) { - return; - } - if (!r.isApplicationActivity() || (r.task != null && !r.task.isApplicationTask())) { - if (mStackState != STACK_STATE_HOME_IN_FRONT) { - if (DEBUG_STACK || DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: mStackState old=" + - stackStateToString(mStackState) + " new=" + - stackStateToString(STACK_STATE_HOME_TO_FRONT) + - " Callers=" + Debug.getCallers(3)); - mStackState = STACK_STATE_HOME_TO_FRONT; + if (r != null) { + final TaskRecord task = r.task; + boolean isHomeActivity = !r.isApplicationActivity(); + if (!isHomeActivity && task != null) { + isHomeActivity = !task.isApplicationTask(); } - } else { - if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, - "setFocusedStack: Setting focused stack to r=" + r + " task=" + r.task + - " Callers=" + Debug.getCallers(3)); - final ActivityStack taskStack = r.task.stack; - mFocusedStack = taskStack.isHomeStack() ? null : taskStack; - if (mStackState != STACK_STATE_HOME_IN_BACK) { - if (DEBUG_STACK) Slog.d(TAG, "setFocusedStack: mStackState old=" + - stackStateToString(mStackState) + " new=" + - stackStateToString(STACK_STATE_HOME_TO_BACK) + - " Callers=" + Debug.getCallers(3)); - mStackState = STACK_STATE_HOME_TO_BACK; + if (!isHomeActivity && task != null) { + final ActivityRecord parent = task.stack.mActivityContainer.mParentActivity; + isHomeActivity = parent != null && parent.isHomeActivity(); } + moveHomeStack(isHomeActivity); } } @@ -1465,7 +1524,7 @@ public final class ActivityStackSupervisor { targetStack.mLastPausedActivity = null; if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack + " from " + intentActivity); - moveHomeStack(targetStack.isHomeStack()); + targetStack.moveToFront(); if (intentActivity.task.intent == null) { // This task was started because of movement of // the activity based on affinity... now that we @@ -1515,9 +1574,6 @@ public final class ActivityStackSupervisor { } else { ActivityOptions.abort(options); } - if (r.task == null) Slog.v(TAG, - "startActivityUncheckedLocked: task left null", - new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_RETURN_INTENT_TO_CALLER; } if ((launchFlags & @@ -1610,9 +1666,6 @@ public final class ActivityStackSupervisor { } else { ActivityOptions.abort(options); } - if (r.task == null) Slog.v(TAG, - "startActivityUncheckedLocked: task left null", - new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_TASK_TO_FRONT; } } @@ -1650,15 +1703,9 @@ public final class ActivityStackSupervisor { // We don't need to start a new activity, and // the client said not to do anything if that // is the case, so this is it! - if (r.task == null) Slog.v(TAG, - "startActivityUncheckedLocked: task left null", - new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_RETURN_INTENT_TO_CALLER; } top.deliverNewIntentLocked(callingUid, r.intent); - if (r.task == null) Slog.v(TAG, - "startActivityUncheckedLocked: task left null", - new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_DELIVERED_TO_TOP; } } @@ -1671,9 +1718,6 @@ public final class ActivityStackSupervisor { r.requestCode, Activity.RESULT_CANCELED, null); } ActivityOptions.abort(options); - if (r.task == null) Slog.v(TAG, - "startActivityUncheckedLocked: task left null", - new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_CLASS_NOT_FOUND; } @@ -1684,7 +1728,7 @@ public final class ActivityStackSupervisor { if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { targetStack = adjustStackFocus(r); - moveHomeStack(targetStack.isHomeStack()); + targetStack.moveToFront(); if (reuseTask == null) { r.setTask(targetStack.createTaskRecord(getNextTaskId(), newTaskInfo != null ? newTaskInfo : r.info, @@ -1702,13 +1746,13 @@ public final class ActivityStackSupervisor { == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) { // Caller wants to appear on home activity, so before starting // their own activity we will bring home to the front. - r.task.mOnTopOfHome = true; + r.task.mOnTopOfHome = r.task.stack.isOnHomeDisplay(); } } } else if (sourceRecord != null) { TaskRecord sourceTask = sourceRecord.task; targetStack = sourceTask.stack; - moveHomeStack(targetStack.isHomeStack()); + targetStack.moveToFront(); mWindowManager.moveTaskToTop(sourceTask.taskId); if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { @@ -1727,9 +1771,6 @@ public final class ActivityStackSupervisor { targetStack.resumeTopActivityLocked(null); } ActivityOptions.abort(options); - if (r.task == null) Slog.w(TAG, - "startActivityUncheckedLocked: task left null", - new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_DELIVERED_TO_TOP; } } else if (!addingToTask && @@ -1763,7 +1804,7 @@ public final class ActivityStackSupervisor { // of a new task... just put it in the top task, though these days // this case should never happen. targetStack = adjustStackFocus(r); - moveHomeStack(targetStack.isHomeStack()); + targetStack.moveToFront(); ActivityRecord prev = targetStack.topActivity(); r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true), @@ -1956,17 +1997,21 @@ public final class ActivityStackSupervisor { boolean handleAppDiedLocked(ProcessRecord app) { boolean hasVisibleActivities = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - hasVisibleActivities |= mStacks.get(stackNdx).handleAppDiedLocked(app); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + hasVisibleActivities |= stacks.get(stackNdx).handleAppDiedLocked(app); + } } return hasVisibleActivities; } void closeSystemDialogsLocked() { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.closeSystemDialogsLocked(); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).closeSystemDialogsLocked(); + } } } @@ -1979,11 +2024,14 @@ public final class ActivityStackSupervisor { */ boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) { boolean didSomething = false; - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) { - didSomething = true; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) { + didSomething = true; + } } } return didSomething; @@ -1998,15 +2046,18 @@ public final class ActivityStackSupervisor { // we don't blow away the previous app if this activity is being // hosted by the process that is actually still the foreground. ProcessRecord fgApp = null; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - if (stack.mResumedActivity != null) { - fgApp = stack.mResumedActivity.app; - } else if (stack.mPausingActivity != null) { - fgApp = stack.mPausingActivity.app; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (isFrontStack(stack)) { + if (stack.mResumedActivity != null) { + fgApp = stack.mResumedActivity.app; + } else if (stack.mPausingActivity != null) { + fgApp = stack.mPausingActivity.app; + } + break; } - break; } } @@ -2029,13 +2080,20 @@ public final class ActivityStackSupervisor { if (targetStack == null) { targetStack = getFocusedStack(); } + // Do targetStack first. boolean result = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { + if (isFrontStack(targetStack)) { + result = targetStack.resumeTopActivityLocked(target, targetOptions); + } + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (stack == targetStack) { - result = stack.resumeTopActivityLocked(target, targetOptions); - } else { + // Already started above. + continue; + } + if (isFrontStack(stack)) { stack.resumeTopActivityLocked(null); } } @@ -2044,38 +2102,105 @@ public final class ActivityStackSupervisor { } void finishTopRunningActivityLocked(ProcessRecord app) { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.finishTopRunningActivityLocked(app); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.finishTopRunningActivityLocked(app); + } } } void findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - if (mStacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) { - if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" + - mStacks.get(stackNdx)); - return; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + if (stacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) { + if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" + + stacks.get(stackNdx)); + return; + } } } } ActivityStack getStack(int stackId) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (stack.getStackId() == stackId) { - return stack; - } + ActivityContainer activityContainer = mActivityContainers.get(stackId); + if (activityContainer != null) { + return activityContainer.mStack; } return null; } ArrayList<ActivityStack> getStacks() { - return new ArrayList<ActivityStack>(mStacks); + ArrayList<ActivityStack> allStacks = new ArrayList<ActivityStack>(); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + allStacks.addAll(mActivityDisplays.valueAt(displayNdx).mStacks); + } + return allStacks; + } + + IBinder getHomeActivityToken() { + final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + final TaskRecord task = tasks.get(taskNdx); + if (task.isHomeTask()) { + final ArrayList<ActivityRecord> activities = task.mActivities; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + if (r.isHomeActivity()) { + return r.appToken; + } + } + } + } + return null; } - int createStack() { + ActivityContainer createActivityContainer(ActivityRecord parentActivity, + IActivityContainerCallback callback) { + ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback); + mActivityContainers.put(activityContainer.mStackId, activityContainer); + parentActivity.mChildContainers.add(activityContainer); + return activityContainer; + } + + void removeChildActivityContainers(ActivityRecord parentActivity) { + final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers; + for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) { + ActivityContainer container = childStacks.remove(containerNdx); + container.release(); + } + } + + void deleteActivityContainer(IActivityContainer container) { + ActivityContainer activityContainer = (ActivityContainer)container; + if (activityContainer != null) { + activityContainer.mStack.finishAllActivitiesLocked(); + final ActivityRecord parent = activityContainer.mParentActivity; + if (parent != null) { + parent.mChildContainers.remove(activityContainer); + } + final int stackId = activityContainer.mStackId; + mActivityContainers.remove(stackId); + mWindowManager.removeStack(stackId); + } + } + + private int createStackOnDisplay(int stackId, int displayId) { + ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + if (activityDisplay == null) { + return -1; + } + + ActivityContainer activityContainer = new ActivityContainer(stackId); + mActivityContainers.put(stackId, activityContainer); + activityContainer.attachToDisplayLocked(activityDisplay); + return stackId; + } + + int getNextStackId() { while (true) { if (++mLastStackId <= HOME_STACK_ID) { mLastStackId = HOME_STACK_ID + 1; @@ -2084,7 +2209,6 @@ public final class ActivityStackSupervisor { break; } } - mStacks.add(new ActivityStack(mService, mContext, mLooper, mLastStackId)); return mLastStackId; } @@ -2098,7 +2222,7 @@ public final class ActivityStackSupervisor { Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId); return; } - removeTask(task); + task.stack.removeTask(task); stack.addTask(task, toTop); mWindowManager.addTask(taskId, stackId, toTop); resumeTopActivitiesLocked(); @@ -2106,15 +2230,18 @@ public final class ActivityStackSupervisor { ActivityRecord findTaskLocked(ActivityRecord r) { if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r); - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!r.isApplicationActivity() && !stack.isHomeStack()) { - if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack); - continue; - } - final ActivityRecord ar = stack.findTaskLocked(r); - if (ar != null) { - return ar; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!r.isApplicationActivity() && !stack.isHomeStack()) { + if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack); + continue; + } + final ActivityRecord ar = stack.findTaskLocked(r); + if (ar != null) { + return ar; + } } } if (DEBUG_TASKS) Slog.d(TAG, "No task found"); @@ -2122,10 +2249,13 @@ public final class ActivityStackSupervisor { } ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityRecord ar = mStacks.get(stackNdx).findActivityLocked(intent, info); - if (ar != null) { - return ar; + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityRecord ar = stacks.get(stackNdx).findActivityLocked(intent, info); + if (ar != null) { + return ar; + } } } return null; @@ -2147,14 +2277,17 @@ public final class ActivityStackSupervisor { } boolean shutdownLocked(int timeout) { - boolean timedout = false; goingToSleepLocked(); + boolean timedout = false; final long endTime = System.currentTimeMillis() + timeout; while (true) { boolean cantShutdown = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - cantShutdown |= mStacks.get(stackNdx).checkReadyForSleepLocked(); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + cantShutdown |= stacks.get(stackNdx).checkReadyForSleepLocked(); + } } if (cantShutdown) { long timeRemaining = endTime - System.currentTimeMillis(); @@ -2185,11 +2318,14 @@ public final class ActivityStackSupervisor { if (mGoingToSleep.isHeld()) { mGoingToSleep.release(); } - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.awakeFromSleepingLocked(); - if (isFrontStack(stack)) { - resumeTopActivitiesLocked(); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.awakeFromSleepingLocked(); + if (isFrontStack(stack)) { + resumeTopActivitiesLocked(); + } } } mGoingToSleepActivities.clear(); @@ -2208,8 +2344,11 @@ public final class ActivityStackSupervisor { if (!mSleepTimeout) { boolean dontSleep = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - dontSleep |= mStacks.get(stackNdx).checkReadyForSleepLocked(); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + dontSleep |= stacks.get(stackNdx).checkReadyForSleepLocked(); + } } if (mStoppingActivities.size() > 0) { @@ -2232,8 +2371,11 @@ public final class ActivityStackSupervisor { } } - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - mStacks.get(stackNdx).goToSleep(); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).goToSleep(); + } } removeSleepTimeouts(); @@ -2260,37 +2402,45 @@ public final class ActivityStackSupervisor { } void handleAppCrashLocked(ProcessRecord app) { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.handleAppCrashLocked(app); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.handleAppCrashLocked(app); + } } } void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) { // First the front stacks. In case any are not fullscreen and are in front of home. boolean showHomeBehindStack = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - showHomeBehindStack = - stack.ensureActivitiesVisibleLocked(starting, configChanges); - } - } - // Now do back stacks. - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack)) { - stack.ensureActivitiesVisibleLocked(starting, configChanges, showHomeBehindStack); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int topStackNdx = stacks.size() - 1; + for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (stackNdx == topStackNdx) { + // Top stack. + showHomeBehindStack = + stack.ensureActivitiesVisibleLocked(starting, configChanges); + } else { + // Back stack. + stack.ensureActivitiesVisibleLocked(starting, configChanges, + showHomeBehindStack); + } } } } void scheduleDestroyAllActivities(ProcessRecord app, String reason) { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.scheduleDestroyActivities(app, false, reason); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.scheduleDestroyActivities(app, false, reason); + } } } @@ -2300,8 +2450,13 @@ public final class ActivityStackSupervisor { mCurrentUser = userId; mStartingUsers.add(uss); - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - mStacks.get(stackNdx).switchUserLocked(userId); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.switchUserLocked(userId); + mWindowManager.moveTaskToTop(stack.topTask().taskId); + } } ActivityStack stack = getStack(restoreStackId); @@ -2309,8 +2464,13 @@ public final class ActivityStackSupervisor { stack = mHomeStack; } final boolean homeInFront = stack.isHomeStack(); - moveHomeStack(homeInFront); - mWindowManager.moveTaskToTop(stack.topTask().taskId); + if (stack.isOnHomeDisplay()) { + moveHomeStack(homeInFront); + mWindowManager.moveTaskToTop(stack.topTask().taskId); + } else { + // Stack was moved to another display while user was swapped out. + resumeHomeActivity(null); + } return homeInFront; } @@ -2355,8 +2515,9 @@ public final class ActivityStackSupervisor { } void validateTopActivitiesLocked() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); + // FIXME +/* for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); final ActivityRecord r = stack.topRunningActivityLocked(null); final ActivityState state = r == null ? ActivityState.DESTROYED : r.state; if (isFrontStack(stack)) { @@ -2386,26 +2547,18 @@ public final class ActivityStackSupervisor { } } } - } - - private static String stackStateToString(int stackState) { - switch (stackState) { - case STACK_STATE_HOME_IN_FRONT: return "STACK_STATE_HOME_IN_FRONT"; - case STACK_STATE_HOME_TO_BACK: return "STACK_STATE_HOME_TO_BACK"; - case STACK_STATE_HOME_IN_BACK: return "STACK_STATE_HOME_IN_BACK"; - case STACK_STATE_HOME_TO_FRONT: return "STACK_STATE_HOME_TO_FRONT"; - default: return "Unknown stackState=" + stackState; - } +*/ } public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mDismissKeyguardOnNextActivity="); pw.println(mDismissKeyguardOnNextActivity); pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack); - pw.print(" mStackState="); pw.println(stackStateToString(mStackState)); + pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack); pw.print(prefix); pw.println("mSleepTimeout=" + mSleepTimeout); pw.print(prefix); pw.println("mCurTaskId=" + mCurTaskId); pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront); + pw.print(prefix); pw.println("mActivityContainers=" + mActivityContainers); } ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) { @@ -2431,42 +2584,48 @@ public final class ActivityStackSupervisor { boolean dumpClient, String dumpPackage) { boolean printed = false; boolean needSep = false; - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - StringBuilder stackHeader = new StringBuilder(128); - stackHeader.append(" Stack #"); - stackHeader.append(mStacks.indexOf(stack)); - stackHeader.append(":"); - printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, needSep, - stackHeader.toString()); - printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, !dumpAll, - false, dumpPackage, true, " Running activities (most recent first):", null); - - needSep = printed; - boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep, - " mPausingActivity: "); - if (pr) { - printed = true; - needSep = false; - } - pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep, - " mResumedActivity: "); - if (pr) { - printed = true; - needSep = false; - } - if (dumpAll) { - pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep, - " mLastPausedActivity: "); + for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { + ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx); + pw.print("Display #"); pw.println(activityDisplay.mDisplayId); + ArrayList<ActivityStack> stacks = activityDisplay.mStacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + StringBuilder stackHeader = new StringBuilder(128); + stackHeader.append(" Stack #"); + stackHeader.append(stack.mStackId); + stackHeader.append(":"); + printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, + needSep, stackHeader.toString()); + printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, + !dumpAll, false, dumpPackage, true, + " Running activities (most recent first):", null); + + needSep = printed; + boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep, + " mPausingActivity: "); + if (pr) { + printed = true; + needSep = false; + } + pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep, + " mResumedActivity: "); if (pr) { printed = true; - needSep = true; + needSep = false; } - printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage, - needSep, " mLastNoHistoryActivity: "); + if (dumpAll) { + pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep, + " mLastPausedActivity: "); + if (pr) { + printed = true; + needSep = true; + } + printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage, + needSep, " mLastNoHistoryActivity: "); + } + needSep = printed; } - needSep = printed; } printed |= dumpHistoryList(fd, pw, mFinishingActivities, " ", "Fin", false, !dumpAll, @@ -2583,7 +2742,9 @@ public final class ActivityStackSupervisor { } final void scheduleResumeTopActivities() { - mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG); + if (!mHandler.hasMessages(RESUME_TOP_ACTIVITY_MSG)) { + mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG); + } } void removeSleepTimeouts() { @@ -2596,6 +2757,101 @@ public final class ActivityStackSupervisor { mHandler.sendEmptyMessageDelayed(SLEEP_TIMEOUT_MSG, SLEEP_TIMEOUT); } + @Override + public void onDisplayAdded(int displayId) { + mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_ADDED, displayId, 0)); + } + + @Override + public void onDisplayRemoved(int displayId) { + mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_REMOVED, displayId, 0)); + } + + @Override + public void onDisplayChanged(int displayId) { + mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0)); + } + + public void handleDisplayAddedLocked(int displayId) { + boolean newDisplay; + synchronized (mService) { + newDisplay = mActivityDisplays.get(displayId) == null; + if (newDisplay) { + ActivityDisplay activityDisplay = new ActivityDisplay(displayId); + mActivityDisplays.put(displayId, activityDisplay); + } + } + if (newDisplay) { + mWindowManager.onDisplayAdded(displayId); + } + } + + public void handleDisplayRemovedLocked(int displayId) { + synchronized (mService) { + ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + if (activityDisplay != null) { + ArrayList<ActivityStack> stacks = activityDisplay.mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).mActivityContainer.detachLocked(); + } + mActivityDisplays.remove(displayId); + } + } + mWindowManager.onDisplayRemoved(displayId); + } + + public void handleDisplayChangedLocked(int displayId) { + synchronized (mService) { + ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + if (activityDisplay != null) { + // TODO: Update the bounds. + } + } + mWindowManager.onDisplayChanged(displayId); + } + + StackInfo getStackInfo(ActivityStack stack) { + StackInfo info = new StackInfo(); + mWindowManager.getStackBounds(stack.mStackId, info.bounds); + info.displayId = Display.DEFAULT_DISPLAY; + info.stackId = stack.mStackId; + + ArrayList<TaskRecord> tasks = stack.getAllTasks(); + final int numTasks = tasks.size(); + int[] taskIds = new int[numTasks]; + String[] taskNames = new String[numTasks]; + for (int i = 0; i < numTasks; ++i) { + final TaskRecord task = tasks.get(i); + taskIds[i] = task.taskId; + taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString() + : task.realActivity != null ? task.realActivity.flattenToString() + : task.getTopActivity() != null ? task.getTopActivity().packageName + : "unknown"; + } + info.taskIds = taskIds; + info.taskNames = taskNames; + return info; + } + + StackInfo getStackInfoLocked(int stackId) { + ActivityStack stack = getStack(stackId); + if (stack != null) { + return getStackInfo(stack); + } + return null; + } + + ArrayList<StackInfo> getAllStackInfosLocked() { + ArrayList<StackInfo> list = new ArrayList<StackInfo>(); + for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) { + list.add(getStackInfo(stacks.get(ndx))); + } + } + return list; + } + private final class ActivityStackSupervisorHandler extends Handler { public ActivityStackSupervisorHandler(Looper looper) { @@ -2659,7 +2915,393 @@ public final class ActivityStackSupervisor { } } } break; + case HANDLE_DISPLAY_ADDED: { + handleDisplayAddedLocked(msg.arg1); + } break; + case HANDLE_DISPLAY_CHANGED: { + handleDisplayChangedLocked(msg.arg1); + } break; + case HANDLE_DISPLAY_REMOVED: { + handleDisplayRemovedLocked(msg.arg1); + } break; + case CONTAINER_CALLBACK_VISIBILITY: { + final ActivityContainer container = (ActivityContainer) msg.obj; + try { + // We only send this message if mCallback is non-null. + container.mCallback.setVisible(container.asBinder(), msg.arg1 == 1); + } catch (RemoteException e) { + } + } + } + } + } + + class ActivityContainer extends android.app.IActivityContainer.Stub { + final static int FORCE_NEW_TASK_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_MULTIPLE_TASK; + final int mStackId; + IActivityContainerCallback mCallback = null; + final ActivityStack mStack; + ActivityRecord mParentActivity = null; + String mIdString; + + boolean mVisible = true; + + /** Display this ActivityStack is currently on. Null if not attached to a Display. */ + ActivityDisplay mActivityDisplay; + + final static int CONTAINER_STATE_HAS_SURFACE = 0; + final static int CONTAINER_STATE_NO_SURFACE = 1; + final static int CONTAINER_STATE_FINISHING = 2; + int mContainerState = CONTAINER_STATE_HAS_SURFACE; + + ActivityContainer(int stackId) { + synchronized (mService) { + mStackId = stackId; + mStack = new ActivityStack(this); + mIdString = "ActivtyContainer{" + mStackId + "}"; + if (DEBUG_STACK) Slog.d(TAG, "Creating " + this); + } + } + + void attachToDisplayLocked(ActivityDisplay activityDisplay) { + if (DEBUG_STACK) Slog.d(TAG, "attachToDisplayLocked: " + this + + " to display=" + activityDisplay); + mActivityDisplay = activityDisplay; + mStack.mDisplayId = activityDisplay.mDisplayId; + mStack.mStacks = activityDisplay.mStacks; + + activityDisplay.attachActivities(mStack); + mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId); + } + + @Override + public void attachToDisplay(int displayId) { + synchronized (mService) { + ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + if (activityDisplay == null) { + return; + } + attachToDisplayLocked(activityDisplay); + } + } + + @Override + public int getDisplayId() { + if (mActivityDisplay != null) { + return mActivityDisplay.mDisplayId; + } + return -1; + } + + @Override + public boolean injectEvent(InputEvent event) { + final long origId = Binder.clearCallingIdentity(); + try { + if (mActivityDisplay != null) { + return mInputManagerInternal.injectInputEvent(event, + mActivityDisplay.mDisplayId, + InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); + } + return false; + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + @Override + public void release() { + mContainerState = CONTAINER_STATE_FINISHING; + mStack.finishAllActivitiesLocked(); + detachLocked(); + mWindowManager.removeStack(mStackId); + } + + private void detachLocked() { + if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display=" + + mActivityDisplay + " Callers=" + Debug.getCallers(2)); + if (mActivityDisplay != null) { + mActivityDisplay.detachActivitiesLocked(mStack); + mActivityDisplay = null; + mStack.mDisplayId = -1; + mStack.mStacks = null; + mWindowManager.detachStack(mStackId); + } + } + + @Override + public final int startActivity(Intent intent) { + mService.enforceNotIsolatedCaller("ActivityContainer.startActivity"); + int userId = mService.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null); + // TODO: Switch to user app stacks here. + intent.addFlags(FORCE_NEW_TASK_FLAGS); + String mimeType = intent.getType(); + if (mimeType == null && intent.getData() != null + && "content".equals(intent.getData().getScheme())) { + mimeType = mService.getProviderMimeType(intent.getData(), userId); + } + return startActivityMayWait(null, -1, null, intent, mimeType, null, null, 0, 0, null, + null, null, null, null, userId, this); + } + + @Override + public final int startActivityIntentSender(IIntentSender intentSender) { + mService.enforceNotIsolatedCaller("ActivityContainer.startActivityIntentSender"); + + if (!(intentSender instanceof PendingIntentRecord)) { + throw new IllegalArgumentException("Bad PendingIntent object"); + } + + return ((PendingIntentRecord)intentSender).sendInner(0, null, null, null, null, null, + null, 0, FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this); + } + + private void checkEmbeddedAllowedInner(Intent intent, String resolvedType) { + int userId = mService.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null); + if (resolvedType == null) { + resolvedType = intent.getType(); + if (resolvedType == null && intent.getData() != null + && "content".equals(intent.getData().getScheme())) { + resolvedType = mService.getProviderMimeType(intent.getData(), userId); + } + } + ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, null, userId); + if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) { + throw new SecurityException( + "Attempt to embed activity that has not set allowEmbedded=\"true\""); + } + } + + /** Throw a SecurityException if allowEmbedded is not true */ + @Override + public final void checkEmbeddedAllowed(Intent intent) { + checkEmbeddedAllowedInner(intent, null); + } + + /** Throw a SecurityException if allowEmbedded is not true */ + @Override + public final void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) { + if (!(intentSender instanceof PendingIntentRecord)) { + throw new IllegalArgumentException("Bad PendingIntent object"); } + PendingIntentRecord pendingIntent = (PendingIntentRecord) intentSender; + checkEmbeddedAllowedInner(pendingIntent.key.requestIntent, + pendingIntent.key.requestResolvedType); + } + + @Override + public IBinder asBinder() { + return this; + } + + @Override + public void setSurface(Surface surface, int width, int height, int density) { + mService.enforceNotIsolatedCaller("ActivityContainer.attachToSurface"); + } + + ActivityStackSupervisor getOuter() { + return ActivityStackSupervisor.this; + } + + boolean isAttached() { + return mActivityDisplay != null; + } + + void getBounds(Point outBounds) { + if (mActivityDisplay != null) { + mActivityDisplay.getBounds(outBounds); + } else { + outBounds.set(0, 0); + } + } + + // TODO: Make sure every change to ActivityRecord.visible results in a call to this. + void setVisible(boolean visible) { + if (mVisible != visible) { + mVisible = visible; + if (mCallback != null) { + mHandler.obtainMessage(CONTAINER_CALLBACK_VISIBILITY, visible ? 1 : 0, + 0 /* unused */, this).sendToTarget(); + } + } + } + + void setDrawn() { + } + + @Override + public String toString() { + return mIdString + (mActivityDisplay == null ? "N" : "A"); + } + } + + private class VirtualActivityContainer extends ActivityContainer { + Surface mSurface; + boolean mDrawn = false; + + VirtualActivityContainer(ActivityRecord parent, IActivityContainerCallback callback) { + super(getNextStackId()); + mParentActivity = parent; + mCallback = callback; + mContainerState = CONTAINER_STATE_NO_SURFACE; + mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}"; + } + + @Override + public void setSurface(Surface surface, int width, int height, int density) { + super.setSurface(surface, width, height, density); + + synchronized (mService) { + final long origId = Binder.clearCallingIdentity(); + try { + setSurfaceLocked(surface, width, height, density); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + + private void setSurfaceLocked(Surface surface, int width, int height, int density) { + if (mContainerState == CONTAINER_STATE_FINISHING) { + return; + } + VirtualActivityDisplay virtualActivityDisplay = + (VirtualActivityDisplay) mActivityDisplay; + if (virtualActivityDisplay == null) { + virtualActivityDisplay = + new VirtualActivityDisplay(width, height, density); + mActivityDisplay = virtualActivityDisplay; + mActivityDisplays.put(virtualActivityDisplay.mDisplayId, virtualActivityDisplay); + attachToDisplayLocked(virtualActivityDisplay); + } + + if (mSurface != null) { + mSurface.release(); + } + + mSurface = surface; + if (surface != null) { + mStack.resumeTopActivityLocked(null); + } else { + mContainerState = CONTAINER_STATE_NO_SURFACE; + ((VirtualActivityDisplay) mActivityDisplay).setSurface(null); + if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) { + mStack.startPausingLocked(false, true); + } + } + + setSurfaceIfReady(); + + if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display=" + + virtualActivityDisplay); + } + + @Override + boolean isAttached() { + return mSurface != null && super.isAttached(); + } + + @Override + void setDrawn() { + synchronized (mService) { + mDrawn = true; + setSurfaceIfReady(); + } + } + + private void setSurfaceIfReady() { + if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn + + " mContainerState=" + mContainerState + " mSurface=" + mSurface); + if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) { + ((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface); + mContainerState = CONTAINER_STATE_HAS_SURFACE; + } + } + } + + /** Exactly one of these classes per Display in the system. Capable of holding zero or more + * attached {@link ActivityStack}s */ + class ActivityDisplay { + /** Actual Display this object tracks. */ + int mDisplayId; + Display mDisplay; + DisplayInfo mDisplayInfo = new DisplayInfo(); + + /** All of the stacks on this display. Order matters, topmost stack is in front of all other + * stacks, bottommost behind. Accessed directly by ActivityManager package classes */ + final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>(); + + ActivityDisplay() { + } + + ActivityDisplay(int displayId) { + init(mDisplayManager.getDisplay(displayId)); + } + + void init(Display display) { + mDisplay = display; + mDisplayId = display.getDisplayId(); + mDisplay.getDisplayInfo(mDisplayInfo); + } + + void attachActivities(ActivityStack stack) { + if (DEBUG_STACK) Slog.v(TAG, "attachActivities: attaching " + stack + " to displayId=" + + mDisplayId); + mStacks.add(stack); + } + + void detachActivitiesLocked(ActivityStack stack) { + if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack + + " from displayId=" + mDisplayId); + mStacks.remove(stack); + } + + void getBounds(Point bounds) { + mDisplay.getDisplayInfo(mDisplayInfo); + bounds.x = mDisplayInfo.appWidth; + bounds.y = mDisplayInfo.appHeight; + } + + @Override + public String toString() { + return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}"; + } + } + + class VirtualActivityDisplay extends ActivityDisplay { + VirtualDisplay mVirtualDisplay; + + VirtualActivityDisplay(int width, int height, int density) { + DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); + mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, VIRTUAL_DISPLAY_BASE_NAME, + width, height, density, null, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | + DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); + + init(mVirtualDisplay.getDisplay()); + + mWindowManager.handleDisplayAdded(mDisplayId); + } + + void setSurface(Surface surface) { + if (mVirtualDisplay != null) { + mVirtualDisplay.setSurface(surface); + } + } + + @Override + void detachActivitiesLocked(ActivityStack stack) { + super.detachActivitiesLocked(stack); + if (mVirtualDisplay != null) { + mVirtualDisplay.release(); + mVirtualDisplay = null; + } + } + + @Override + public String toString() { + return "VirtualActivityDisplay={" + mDisplayId + "}"; } } } diff --git a/services/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java index 06265fd..06265fd 100644 --- a/services/java/com/android/server/am/AppBindRecord.java +++ b/services/core/java/com/android/server/am/AppBindRecord.java diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java index 0ba62c5..0ba62c5 100644 --- a/services/java/com/android/server/am/AppErrorDialog.java +++ b/services/core/java/com/android/server/am/AppErrorDialog.java diff --git a/services/java/com/android/server/am/AppErrorResult.java b/services/core/java/com/android/server/am/AppErrorResult.java index c6a5720..c6a5720 100644 --- a/services/java/com/android/server/am/AppErrorResult.java +++ b/services/core/java/com/android/server/am/AppErrorResult.java diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java index f4c1664..f4c1664 100644 --- a/services/java/com/android/server/am/AppNotRespondingDialog.java +++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java index 27865a8..27865a8 100644 --- a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java +++ b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java diff --git a/services/java/com/android/server/am/BackupRecord.java b/services/core/java/com/android/server/am/BackupRecord.java index 5fa7e6a..5fa7e6a 100644 --- a/services/java/com/android/server/am/BackupRecord.java +++ b/services/core/java/com/android/server/am/BackupRecord.java diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java index 6ede8f8..6ede8f8 100644 --- a/services/java/com/android/server/am/BaseErrorDialog.java +++ b/services/core/java/com/android/server/am/BaseErrorDialog.java diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 2d59678..89e96fd 100644 --- a/services/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -24,6 +24,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.BatteryStats; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; import android.os.Parcel; import android.os.Process; @@ -54,8 +55,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub { private boolean mBluetoothPendingStats; private BluetoothHeadset mBluetoothHeadset; - BatteryStatsService(String filename) { - mStats = new BatteryStatsImpl(filename); + BatteryStatsService(String filename, Handler handler) { + mStats = new BatteryStatsImpl(filename, handler); } public void publish(Context context) { @@ -174,10 +175,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub { } } - public void noteScreenOn() { + public void noteScreenState(int state) { enforceCallingPermission(); synchronized (mStats) { - mStats.noteScreenOnLocked(); + mStats.noteScreenStateLocked(state); } } @@ -188,22 +189,17 @@ public final class BatteryStatsService extends IBatteryStats.Stub { } } - public void noteScreenOff() { + public void noteUserActivity(int uid, int event) { enforceCallingPermission(); synchronized (mStats) { - mStats.noteScreenOffLocked(); + mStats.noteUserActivityLocked(uid, event); } } - - public void noteInputEvent() { - enforceCallingPermission(); - mStats.noteInputEventAtomic(); - } - public void noteUserActivity(int uid, int event) { + public void noteInteractive(boolean interactive) { enforceCallingPermission(); synchronized (mStats) { - mStats.noteUserActivityLocked(uid, event); + mStats.noteInteractiveLocked(interactive); } } diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java index 986b8ea..986b8ea 100644 --- a/services/java/com/android/server/am/BroadcastFilter.java +++ b/services/core/java/com/android/server/am/BroadcastFilter.java diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index bfb667f..aef9e5c 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -33,6 +33,7 @@ import android.content.pm.ResolveInfo; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.RemoteException; @@ -132,7 +133,14 @@ public final class BroadcastQueue { static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG; static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1; - final Handler mHandler = new Handler() { + final BroadcastHandler mHandler; + + private final class BroadcastHandler extends Handler { + public BroadcastHandler(Looper looper) { + super(looper, null, true); + } + + @Override public void handleMessage(Message msg) { switch (msg.what) { case BROADCAST_INTENT_MSG: { @@ -164,9 +172,10 @@ public final class BroadcastQueue { } } - BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod, - boolean allowDelayBehindServices) { + BroadcastQueue(ActivityManagerService service, Handler handler, + String name, long timeoutPeriod, boolean allowDelayBehindServices) { mService = service; + mHandler = new BroadcastHandler(handler.getLooper()); mQueueName = name; mTimeoutPeriod = timeoutPeriod; mDelayBehindServices = allowDelayBehindServices; diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index b2cfd7a..b2cfd7a 100644 --- a/services/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java diff --git a/services/java/com/android/server/am/CompatModeDialog.java b/services/core/java/com/android/server/am/CompatModeDialog.java index 202cc7c..202cc7c 100644 --- a/services/java/com/android/server/am/CompatModeDialog.java +++ b/services/core/java/com/android/server/am/CompatModeDialog.java diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java index 59e6787..ec500c2 100644 --- a/services/java/com/android/server/am/CompatModePackages.java +++ b/services/core/java/com/android/server/am/CompatModePackages.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.server.am; import java.io.File; @@ -19,6 +35,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.CompatibilityInfo; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.AtomicFile; @@ -41,22 +58,27 @@ public final class CompatModePackages { private static final int MSG_WRITE = ActivityManagerService.FIRST_COMPAT_MODE_MSG; - private final Handler mHandler = new Handler() { - @Override public void handleMessage(Message msg) { + private final CompatHandler mHandler; + + private final class CompatHandler extends Handler { + public CompatHandler(Looper looper) { + super(looper, null, true); + } + + @Override + public void handleMessage(Message msg) { switch (msg.what) { case MSG_WRITE: saveCompatModes(); break; - default: - super.handleMessage(msg); - break; } } }; - public CompatModePackages(ActivityManagerService service, File systemDir) { + public CompatModePackages(ActivityManagerService service, File systemDir, Handler handler) { mService = service; mFile = new AtomicFile(new File(systemDir, "packages-compat.xml")); + mHandler = new CompatHandler(handler.getLooper()); FileInputStream fis = null; try { @@ -64,9 +86,14 @@ public final class CompatModePackages { XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, null); int eventType = parser.getEventType(); - while (eventType != XmlPullParser.START_TAG) { + while (eventType != XmlPullParser.START_TAG && + eventType != XmlPullParser.END_DOCUMENT) { eventType = parser.next(); } + if (eventType == XmlPullParser.END_DOCUMENT) { + return; + } + String tagName = parser.getName(); if ("compat-packages".equals(tagName)) { eventType = parser.next(); diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java index 423e540..423e540 100644 --- a/services/java/com/android/server/am/ConnectionRecord.java +++ b/services/core/java/com/android/server/am/ConnectionRecord.java diff --git a/services/java/com/android/server/am/ContentProviderConnection.java b/services/core/java/com/android/server/am/ContentProviderConnection.java index f2c9e2f..f2c9e2f 100644 --- a/services/java/com/android/server/am/ContentProviderConnection.java +++ b/services/core/java/com/android/server/am/ContentProviderConnection.java diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java index 646b7d2..646b7d2 100644 --- a/services/java/com/android/server/am/ContentProviderRecord.java +++ b/services/core/java/com/android/server/am/ContentProviderRecord.java diff --git a/services/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java index 10ea67c..10ea67c 100644 --- a/services/java/com/android/server/am/CoreSettingsObserver.java +++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index d3cc56b..d3cc56b 100644 --- a/services/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/core/java/com/android/server/am/FactoryErrorDialog.java index f4632c1..f4632c1 100644 --- a/services/java/com/android/server/am/FactoryErrorDialog.java +++ b/services/core/java/com/android/server/am/FactoryErrorDialog.java diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java index 21cf266..21cf266 100644 --- a/services/java/com/android/server/am/IntentBindRecord.java +++ b/services/core/java/com/android/server/am/IntentBindRecord.java diff --git a/services/java/com/android/server/am/LaunchWarningWindow.java b/services/core/java/com/android/server/am/LaunchWarningWindow.java index 30c3066..30c3066 100644 --- a/services/java/com/android/server/am/LaunchWarningWindow.java +++ b/services/core/java/com/android/server/am/LaunchWarningWindow.java diff --git a/services/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java index 2c7f1f1..b12843b 100644 --- a/services/java/com/android/server/am/NativeCrashListener.java +++ b/services/core/java/com/android/server/am/NativeCrashListener.java @@ -95,8 +95,8 @@ final class NativeCrashListener extends Thread { * Daemon thread that accept()s incoming domain socket connections from debuggerd * and processes the crash dump that is passed through. */ - NativeCrashListener() { - mAm = ActivityManagerService.self(); + NativeCrashListener(ActivityManagerService am) { + mAm = am; } @Override diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index 17f24a9..00fa216 100644 --- a/services/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -17,6 +17,7 @@ package com.android.server.am; import android.app.ActivityManager; +import android.app.IActivityContainer; import android.content.IIntentSender; import android.content.IIntentReceiver; import android.app.PendingIntent; @@ -190,13 +191,13 @@ final class PendingIntentRecord extends IIntentSender.Stub { public int send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission) { return sendInner(code, intent, resolvedType, finishedReceiver, - requiredPermission, null, null, 0, 0, 0, null); + requiredPermission, null, null, 0, 0, 0, null, null); } int sendInner(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, String resultWho, int requestCode, - int flagsMask, int flagsValues, Bundle options) { + int flagsMask, int flagsValues, Bundle options, IActivityContainer container) { synchronized(owner) { if (!canceled) { sent = true; @@ -251,7 +252,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { } else { owner.startActivityInPackage(uid, key.packageName, finalIntent, resolvedType, resultTo, resultWho, requestCode, 0, - options, userId); + options, userId, container); } } catch (RuntimeException e) { Slog.w(ActivityManagerService.TAG, @@ -302,7 +303,8 @@ final class PendingIntentRecord extends IIntentSender.Stub { } return ActivityManager.START_CANCELED; } - + + @Override protected void finalize() throws Throwable { try { if (!canceled) { diff --git a/services/java/com/android/server/am/PendingThumbnailsRecord.java b/services/core/java/com/android/server/am/PendingThumbnailsRecord.java index e4eb4d0..e4eb4d0 100644 --- a/services/java/com/android/server/am/PendingThumbnailsRecord.java +++ b/services/core/java/com/android/server/am/PendingThumbnailsRecord.java diff --git a/services/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index d3777c7..f5920c8 100644 --- a/services/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -18,6 +18,8 @@ package com.android.server.am; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; import android.app.ActivityManager; import com.android.internal.util.MemInfoReader; @@ -26,6 +28,8 @@ import com.android.server.wm.WindowManagerService; import android.content.res.Resources; import android.graphics.Point; import android.os.SystemProperties; +import android.net.LocalSocketAddress; +import android.net.LocalSocket; import android.util.Slog; import android.view.Display; @@ -141,6 +145,16 @@ final class ProcessList { // Threshold of number of cached+empty where we consider memory critical. static final int TRIM_LOW_THRESHOLD = 5; + // Low Memory Killer Daemon command codes. + // These must be kept in sync with the definitions in lmkd.c + // + // LMK_TARGET <minfree> <minkillprio> ... (up to 6 pairs) + // LMK_PROCPRIO <pid> <prio> + // LMK_PROCREMOVE <pid> + static final byte LMK_TARGET = 0; + static final byte LMK_PROCPRIO = 1; + static final byte LMK_PROCREMOVE = 2; + // These are the various interesting memory levels that we will give to // the OOM killer. Note that the OOM killer only supports 6 slots, so we // can't give it a different value for every possible kind of process. @@ -150,18 +164,18 @@ final class ProcessList { }; // These are the low-end OOM level limits. This is appropriate for an // HVGA or smaller phone with less than 512MB. Values are in KB. - private final long[] mOomMinFreeLow = new long[] { + private final int[] mOomMinFreeLow = new int[] { 8192, 12288, 16384, 24576, 28672, 32768 }; // These are the high-end OOM level limits. This is appropriate for a // 1280x800 or larger screen with around 1GB RAM. Values are in KB. - private final long[] mOomMinFreeHigh = new long[] { + private final int[] mOomMinFreeHigh = new int[] { 49152, 61440, 73728, 86016, 98304, 122880 }; // The actual OOM killer memory levels we are using. - private final long[] mOomMinFree = new long[mOomAdj.length]; + private final int[] mOomMinFree = new int[mOomAdj.length]; private final long mTotalMemMb; @@ -169,6 +183,9 @@ final class ProcessList { private boolean mHaveDisplaySize; + private static LocalSocket sLmkdSocket; + private static OutputStream sLmkdOutputStream; + ProcessList() { MemInfoReader minfo = new MemInfoReader(); minfo.readMemInfo(); @@ -202,9 +219,6 @@ final class ProcessList { + " dh=" + displayHeight); } - StringBuilder adjString = new StringBuilder(); - StringBuilder memString = new StringBuilder(); - float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp; if (scale < 0) scale = 0; else if (scale > 1) scale = 1; @@ -217,20 +231,20 @@ final class ProcessList { } for (int i=0; i<mOomAdj.length; i++) { - long low = mOomMinFreeLow[i]; - long high = mOomMinFreeHigh[i]; - mOomMinFree[i] = (long)(low + ((high-low)*scale)); + int low = mOomMinFreeLow[i]; + int high = mOomMinFreeHigh[i]; + mOomMinFree[i] = (int)(low + ((high-low)*scale)); } if (minfree_abs >= 0) { for (int i=0; i<mOomAdj.length; i++) { - mOomMinFree[i] = (long)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]); + mOomMinFree[i] = (int)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]); } } if (minfree_adj != 0) { for (int i=0; i<mOomAdj.length; i++) { - mOomMinFree[i] += (long)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]); + mOomMinFree[i] += (int)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]); if (mOomMinFree[i] < 0) { mOomMinFree[i] = 0; } @@ -242,15 +256,6 @@ final class ProcessList { // before killing background processes. mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024) / 3; - for (int i=0; i<mOomAdj.length; i++) { - if (i > 0) { - adjString.append(','); - memString.append(','); - } - adjString.append(mOomAdj[i]); - memString.append((mOomMinFree[i]*1024)/PAGE_SIZE); - } - // Ask the kernel to try to keep enough memory free to allocate 3 full // screen 32bpp buffers without entering direct reclaim. int reserve = displayWidth * displayHeight * 4 * 3 / 1024; @@ -268,10 +273,15 @@ final class ProcessList { } } - //Slog.i("XXXXXXX", "******************************* MINFREE: " + memString); if (write) { - writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString()); - writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString()); + ByteBuffer buf = ByteBuffer.allocate(4 * (2*mOomAdj.length + 1)); + buf.putInt(LMK_TARGET); + for (int i=0; i<mOomAdj.length; i++) { + buf.putInt((mOomMinFree[i]*1024)/PAGE_SIZE); + buf.putInt(mOomAdj[i]); + } + + writeLmkd(buf); SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve)); } // GB: 2048,3072,4096,6144,7168,8192 @@ -506,19 +516,78 @@ final class ProcessList { return mCachedRestoreLevel; } - private void writeFile(String path, String data) { - FileOutputStream fos = null; + /** + * Set the out-of-memory badness adjustment for a process. + * + * @param pid The process identifier to set. + * @param amt Adjustment value -- lmkd allows -16 to +15. + * + * {@hide} + */ + public static final void setOomAdj(int pid, int amt) { + if (amt == UNKNOWN_ADJ) + return; + + ByteBuffer buf = ByteBuffer.allocate(4 * 3); + buf.putInt(LMK_PROCPRIO); + buf.putInt(pid); + buf.putInt(amt); + writeLmkd(buf); + } + + /* + * {@hide} + */ + public static final void remove(int pid) { + ByteBuffer buf = ByteBuffer.allocate(4 * 2); + buf.putInt(LMK_PROCREMOVE); + buf.putInt(pid); + writeLmkd(buf); + } + + private static boolean openLmkdSocket() { try { - fos = new FileOutputStream(path); - fos.write(data.getBytes()); - } catch (IOException e) { - Slog.w(ActivityManagerService.TAG, "Unable to write " + path); - } finally { - if (fos != null) { + sLmkdSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET); + sLmkdSocket.connect( + new LocalSocketAddress("lmkd", + LocalSocketAddress.Namespace.RESERVED)); + sLmkdOutputStream = sLmkdSocket.getOutputStream(); + } catch (IOException ex) { + Slog.w(ActivityManagerService.TAG, + "lowmemorykiller daemon socket open failed"); + sLmkdSocket = null; + return false; + } + + return true; + } + + private static void writeLmkd(ByteBuffer buf) { + + for (int i = 0; i < 3; i++) { + if (sLmkdSocket == null) { + if (openLmkdSocket() == false) { + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + } + continue; + } + } + + try { + sLmkdOutputStream.write(buf.array(), 0, buf.position()); + return; + } catch (IOException ex) { + Slog.w(ActivityManagerService.TAG, + "Error writing to lowmemorykiller socket"); + try { - fos.close(); - } catch (IOException e) { + sLmkdSocket.close(); + } catch (IOException ex2) { } + + sLmkdSocket = null; } } } diff --git a/services/java/com/android/server/am/ProcessMemInfo.java b/services/core/java/com/android/server/am/ProcessMemInfo.java index c94694e..c94694e 100644 --- a/services/java/com/android/server/am/ProcessMemInfo.java +++ b/services/core/java/com/android/server/am/ProcessMemInfo.java diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 217a8d6..217a8d6 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java index e05fcda..e05fcda 100644 --- a/services/java/com/android/server/am/ProcessStatsService.java +++ b/services/core/java/com/android/server/am/ProcessStatsService.java diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java index 7da8c48..7da8c48 100644 --- a/services/java/com/android/server/am/ProviderMap.java +++ b/services/core/java/com/android/server/am/ProviderMap.java diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/core/java/com/android/server/am/ReceiverList.java index fa8c1df..fa8c1df 100644 --- a/services/java/com/android/server/am/ReceiverList.java +++ b/services/core/java/com/android/server/am/ReceiverList.java diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 80e6e94..cb04835 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -18,7 +18,8 @@ package com.android.server.am; import com.android.internal.app.ProcessStats; import com.android.internal.os.BatteryStatsImpl; -import com.android.server.NotificationManagerService; +import com.android.server.LocalServices; +import com.android.server.notification.NotificationManagerInternal; import android.app.INotificationManager; import android.app.Notification; @@ -427,8 +428,8 @@ final class ServiceRecord extends Binder { final Notification localForegroundNoti = foregroundNoti; ams.mHandler.post(new Runnable() { public void run() { - NotificationManagerService nm = - (NotificationManagerService) NotificationManager.getService(); + NotificationManagerInternal nm = LocalServices.getService( + NotificationManagerInternal.class); if (nm == null) { return; } @@ -479,7 +480,7 @@ final class ServiceRecord extends Binder { throw new RuntimeException("icon must be non-zero"); } int[] outId = new int[1]; - nm.enqueueNotificationInternal(localPackageName, localPackageName, + nm.enqueueNotification(localPackageName, localPackageName, appUid, appPid, null, localForegroundId, localForegroundNoti, outId, userId); } catch (RuntimeException e) { diff --git a/services/java/com/android/server/am/StrictModeViolationDialog.java b/services/core/java/com/android/server/am/StrictModeViolationDialog.java index fda1ec1..fda1ec1 100644 --- a/services/java/com/android/server/am/StrictModeViolationDialog.java +++ b/services/core/java/com/android/server/am/StrictModeViolationDialog.java diff --git a/services/java/com/android/server/am/TaskAccessInfo.java b/services/core/java/com/android/server/am/TaskAccessInfo.java index 50aeec1..50aeec1 100644 --- a/services/java/com/android/server/am/TaskAccessInfo.java +++ b/services/core/java/com/android/server/am/TaskAccessInfo.java diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 9105103..9740812 100644 --- a/services/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -60,7 +60,8 @@ final class TaskRecord extends ThumbnailHolder { /** Takes on same set of values as ActivityRecord.mActivityType */ private int mTaskType; - /** Launch the home activity when leaving this task. */ + /** Launch the home activity when leaving this task. Will be false for tasks that are not on + * Display.DEFAULT_DISPLAY. */ boolean mOnTopOfHome = false; TaskRecord(int _taskId, ActivityInfo info, Intent _intent) { diff --git a/services/java/com/android/server/am/ThumbnailHolder.java b/services/core/java/com/android/server/am/ThumbnailHolder.java index a6974f5..a6974f5 100644 --- a/services/java/com/android/server/am/ThumbnailHolder.java +++ b/services/core/java/com/android/server/am/ThumbnailHolder.java diff --git a/services/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java index 1f12b74..1f12b74 100644 --- a/services/java/com/android/server/am/UriPermission.java +++ b/services/core/java/com/android/server/am/UriPermission.java diff --git a/services/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java index 7bbd3bc..7bbd3bc 100644 --- a/services/java/com/android/server/am/UriPermissionOwner.java +++ b/services/core/java/com/android/server/am/UriPermissionOwner.java diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/core/java/com/android/server/am/UsageStatsService.java index e96d8b1..09cb344 100644 --- a/services/java/com/android/server/am/UsageStatsService.java +++ b/services/core/java/com/android/server/am/UsageStatsService.java @@ -396,9 +396,14 @@ public final class UsageStatsService extends IUsageStats.Stub { XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, null); int eventType = parser.getEventType(); - while (eventType != XmlPullParser.START_TAG) { + while (eventType != XmlPullParser.START_TAG && + eventType != XmlPullParser.END_DOCUMENT) { eventType = parser.next(); } + if (eventType == XmlPullParser.END_DOCUMENT) { + return; + } + String tagName = parser.getName(); if ("usage-history".equals(tagName)) { String pkg = null; diff --git a/services/java/com/android/server/am/UserStartedState.java b/services/core/java/com/android/server/am/UserStartedState.java index d3e73d5..d3e73d5 100644 --- a/services/java/com/android/server/am/UserStartedState.java +++ b/services/core/java/com/android/server/am/UserStartedState.java diff --git a/services/java/com/android/server/am/package.html b/services/core/java/com/android/server/am/package.html index c9f96a6..c9f96a6 100644 --- a/services/java/com/android/server/am/package.html +++ b/services/core/java/com/android/server/am/package.html diff --git a/services/java/com/android/server/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 069ae23..6aa596d 100644 --- a/services/java/com/android/server/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.clipboard; import android.app.ActivityManagerNative; import android.app.AppGlobals; diff --git a/services/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java index 227ab23..227ab23 100644 --- a/services/java/com/android/server/connectivity/DataConnectionStats.java +++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index a15d678..a15d678 100644 --- a/services/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java diff --git a/services/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java index 7786fe6..7786fe6 100644 --- a/services/java/com/android/server/connectivity/PacManager.java +++ b/services/core/java/com/android/server/connectivity/PacManager.java diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 231a40a..adf1dfc 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -51,6 +51,7 @@ import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.IoThread; +import com.android.server.net.BaseNetworkObserver; import com.google.android.collect.Lists; import java.io.FileDescriptor; @@ -70,7 +71,7 @@ import java.util.Set; * * TODO - look for parent classes and code sharing */ -public class Tethering extends INetworkManagementEventObserver.Stub { +public class Tethering extends BaseNetworkObserver { private Context mContext; private final static String TAG = "Tethering"; @@ -315,14 +316,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } } - public void addressUpdated(String address, String iface, int flags, int scope) {} - - public void addressRemoved(String address, String iface, int flags, int scope) {} - - public void limitReached(String limitName, String iface) {} - - public void interfaceClassDataActivityChanged(String label, boolean active) {} - public int tether(String iface) { if (DBG) Log.d(TAG, "Tethering " + iface); TetherInterfaceSM sm = null; diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 8f25860..376414b 100644 --- a/services/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -633,10 +633,10 @@ public class Vpn extends BaseNetworkStateTracker { int appId = UserHandle.getAppId(Binder.getCallingUid()); final long token = Binder.clearCallingIdentity(); try { - // System dialogs are also allowed to control VPN. + // System VPN dialogs are also allowed to control VPN. PackageManager pm = mContext.getPackageManager(); ApplicationInfo app = pm.getApplicationInfo(VpnConfig.DIALOGS_PACKAGE, 0); - if (appId == app.uid) { + if (((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) && (appId == app.uid)) { return; } } catch (Exception e) { diff --git a/services/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 023bf2b..023bf2b 100644 --- a/services/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java diff --git a/services/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 9e3dad6..9e3dad6 100644 --- a/services/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java diff --git a/services/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java index 67e3b09..67e3b09 100644 --- a/services/java/com/android/server/content/SyncOperation.java +++ b/services/core/java/com/android/server/content/SyncOperation.java diff --git a/services/java/com/android/server/content/SyncQueue.java b/services/core/java/com/android/server/content/SyncQueue.java index 22fa2de..22fa2de 100644 --- a/services/java/com/android/server/content/SyncQueue.java +++ b/services/core/java/com/android/server/content/SyncQueue.java diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index 781280e..178c372 100644 --- a/services/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -1697,9 +1697,15 @@ public class SyncStorageEngine extends Handler { XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, null); int eventType = parser.getEventType(); - while (eventType != XmlPullParser.START_TAG) { + while (eventType != XmlPullParser.START_TAG && + eventType != XmlPullParser.END_DOCUMENT) { eventType = parser.next(); } + if (eventType == XmlPullParser.END_DOCUMENT) { + Log.i(TAG, "No initial accounts"); + return; + } + String tagName = parser.getName(); if ("accounts".equals(tagName)) { String listen = parser.getAttributeValue(null, XML_ATTR_LISTEN_FOR_TICKLES); diff --git a/services/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java index b411a0d..b411a0d 100644 --- a/services/java/com/android/server/display/DisplayAdapter.java +++ b/services/core/java/com/android/server/display/DisplayAdapter.java diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/services/core/java/com/android/server/display/DisplayBlanker.java index 6072053..eb0ae6a 100644 --- a/services/java/com/android/server/power/DisplayBlanker.java +++ b/services/core/java/com/android/server/display/DisplayBlanker.java @@ -14,12 +14,11 @@ * limitations under the License. */ -package com.android.server.power; +package com.android.server.display; /** - * Blanks or unblanks all displays. + * Interface used to update the actual display state. */ -interface DisplayBlanker { - public void blankAllDisplays(); - public void unblankAllDisplays(); +public interface DisplayBlanker { + void requestDisplayState(int state); } diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index 4161147..a5f9822 100644 --- a/services/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -17,6 +17,7 @@ package com.android.server.display; import android.graphics.Rect; +import android.hardware.display.DisplayViewport; import android.os.IBinder; import android.view.Surface; import android.view.SurfaceControl; @@ -106,15 +107,9 @@ abstract class DisplayDevice { } /** - * Blanks the display, if supported. + * Sets the display state, if supported. */ - public void blankLocked() { - } - - /** - * Unblanks the display, if supported. - */ - public void unblankLocked() { + public void requestDisplayStateLocked(int state) { } /** diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index 11c5d87..a77443d 100644 --- a/services/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -16,6 +16,7 @@ package com.android.server.display; +import android.hardware.display.DisplayViewport; import android.util.DisplayMetrics; import android.view.Display; import android.view.Surface; @@ -63,6 +64,7 @@ final class DisplayDeviceInfo { /** * Flag: Indicates that the display device is owned by a particular application * and that no other application should be able to interact with it. + * Should typically be used together with {@link #FLAG_OWN_CONTENT_ONLY}. */ public static final int FLAG_PRIVATE = 1 << 4; @@ -78,6 +80,12 @@ final class DisplayDeviceInfo { public static final int FLAG_PRESENTATION = 1 << 6; /** + * Flag: Only show this display's own content; do not mirror + * the content of another display. + */ + public static final int FLAG_OWN_CONTENT_ONLY = 1 << 7; + + /** * Touch attachment: Display does not receive touch. */ public static final int TOUCH_NONE = 0; @@ -168,6 +176,11 @@ final class DisplayDeviceInfo { public String address; /** + * Display state. + */ + public int state = Display.STATE_ON; + + /** * The UID of the application that owns this display, or zero if it is owned by the system. * <p> * If the display is private, then only the owner can use it. @@ -211,6 +224,7 @@ final class DisplayDeviceInfo { && rotation == other.rotation && type == other.type && Objects.equal(address, other.address) + && state == other.state && ownerUid == other.ownerUid && Objects.equal(ownerPackageName, other.ownerPackageName); } @@ -233,6 +247,7 @@ final class DisplayDeviceInfo { rotation = other.rotation; type = other.type; address = other.address; + state = other.state; ownerUid = other.ownerUid; ownerPackageName = other.ownerPackageName; } @@ -252,6 +267,7 @@ final class DisplayDeviceInfo { if (address != null) { sb.append(", address ").append(address); } + sb.append(", state ").append(Display.stateToString(state)); if (ownerUid != 0 || ownerPackageName != null) { sb.append(", owner ").append(ownerPackageName); sb.append(" (uid ").append(ownerUid).append(")"); @@ -297,6 +313,9 @@ final class DisplayDeviceInfo { if ((flags & FLAG_PRESENTATION) != 0) { msg.append(", FLAG_PRESENTATION"); } + if ((flags & FLAG_OWN_CONTENT_ONLY) != 0) { + msg.append(", FLAG_OWN_CONTENT_ONLY"); + } return msg.toString(); } } diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index bcb677f..6697b60 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -21,16 +21,23 @@ import com.android.internal.util.IndentingPrintWriter; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; +import android.hardware.SensorManager; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; +import android.hardware.display.DisplayManagerInternal; +import android.hardware.display.DisplayViewport; +import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener; import android.hardware.display.IDisplayManager; import android.hardware.display.IDisplayManagerCallback; import android.hardware.display.WifiDisplayStatus; +import android.hardware.input.InputManagerInternal; import android.os.Binder; import android.os.Handler; import android.os.IBinder; +import android.os.IBinder.DeathRecipient; import android.os.Looper; import android.os.Message; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; @@ -41,7 +48,11 @@ import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; +import android.view.WindowManagerInternal; +import com.android.server.DisplayThread; +import com.android.server.LocalServices; +import com.android.server.SystemService; import com.android.server.UiThread; import java.io.FileDescriptor; @@ -93,7 +104,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * avoid this by making all potentially reentrant out-calls asynchronous. * </p> */ -public final class DisplayManagerService extends IDisplayManager.Stub { +public final class DisplayManagerService extends SystemService { private static final String TAG = "DisplayManagerService"; private static final boolean DEBUG = false; @@ -102,7 +113,6 @@ public final class DisplayManagerService extends IDisplayManager.Stub { // Otherwise WFD is enabled according to the value of config_enableWifiDisplay. private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable"; - private static final String SYSTEM_HEADLESS = "ro.config.headless"; private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000; private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1; @@ -111,17 +121,12 @@ public final class DisplayManagerService extends IDisplayManager.Stub { private static final int MSG_REQUEST_TRAVERSAL = 4; private static final int MSG_UPDATE_VIEWPORT = 5; - private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0; - private static final int DISPLAY_BLANK_STATE_BLANKED = 1; - private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2; - private final Context mContext; - private final boolean mHeadless; private final DisplayManagerHandler mHandler; private final Handler mUiHandler; private final DisplayAdapterListener mDisplayAdapterListener; - private WindowManagerFuncs mWindowManagerFuncs; - private InputManagerFuncs mInputManagerFuncs; + private WindowManagerInternal mWindowManagerInternal; + private InputManagerInternal mInputManagerInternal; // The synchronization root for the display manager. // This lock guards most of the display manager's state. @@ -164,8 +169,12 @@ public final class DisplayManagerService extends IDisplayManager.Stub { private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners = new CopyOnWriteArrayList<DisplayTransactionListener>(); - // Set to true if all displays have been blanked by the power manager. - private int mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNKNOWN; + // Display power controller. + private DisplayPowerController mDisplayPowerController; + + // The overall display state, independent of changes that might influence one + // display or another in particular. + private int mGlobalDisplayState = Display.STATE_UNKNOWN; // Set to true when there are pending display changes that have yet to be applied // to the surface flinger state. @@ -200,59 +209,52 @@ public final class DisplayManagerService extends IDisplayManager.Stub { private final DisplayViewport mTempDefaultViewport = new DisplayViewport(); private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport(); - public DisplayManagerService(Context context, Handler mainHandler) { + public DisplayManagerService(Context context) { + super(context); mContext = context; - mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1"); - - mHandler = new DisplayManagerHandler(mainHandler.getLooper()); + mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper()); mUiHandler = UiThread.getHandler(); mDisplayAdapterListener = new DisplayAdapterListener(); mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); + } + @Override + public void onStart() { mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER); + + publishBinderService(Context.DISPLAY_SERVICE, new BinderService(), + true /*allowIsolated*/); + publishLocalService(DisplayManagerInternal.class, new LocalService()); } - /** - * Pauses the boot process to wait for the first display to be initialized. - */ - public boolean waitForDefaultDisplay() { - synchronized (mSyncRoot) { - long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT; - while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) { - long delay = timeout - SystemClock.uptimeMillis(); - if (delay <= 0) { - return false; - } - if (DEBUG) { - Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay); - } - try { - mSyncRoot.wait(delay); - } catch (InterruptedException ex) { + @Override + public void onBootPhase(int phase) { + if (phase == PHASE_WAIT_FOR_DEFAULT_DISPLAY) { + synchronized (mSyncRoot) { + long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT; + while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) { + long delay = timeout - SystemClock.uptimeMillis(); + if (delay <= 0) { + throw new RuntimeException("Timeout waiting for default display " + + "to be initialized."); + } + if (DEBUG) { + Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay); + } + try { + mSyncRoot.wait(delay); + } catch (InterruptedException ex) { + } } } } - return true; - } - - /** - * Called during initialization to associate the display manager with the - * window manager. - */ - public void setWindowManager(WindowManagerFuncs windowManagerFuncs) { - synchronized (mSyncRoot) { - mWindowManagerFuncs = windowManagerFuncs; - scheduleTraversalLocked(false); - } } - /** - * Called during initialization to associate the display manager with the - * input manager. - */ - public void setInputManager(InputManagerFuncs inputManagerFuncs) { + // TODO: Use dependencies or a boot phase + public void windowManagerAndInputReady() { synchronized (mSyncRoot) { - mInputManagerFuncs = inputManagerFuncs; + mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); + mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); scheduleTraversalLocked(false); } } @@ -269,59 +271,19 @@ public final class DisplayManagerService extends IDisplayManager.Stub { mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS); } - /** - * Returns true if the device is headless. - * - * @return True if the device is headless. - */ - public boolean isHeadless() { - return mHeadless; - } - - /** - * Registers a display transaction listener to provide the client a chance to - * update its surfaces within the same transaction as any display layout updates. - * - * @param listener The listener to register. - */ - public void registerDisplayTransactionListener(DisplayTransactionListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - + private void registerDisplayTransactionListenerInternal( + DisplayTransactionListener listener) { // List is self-synchronized copy-on-write. mDisplayTransactionListeners.add(listener); } - /** - * Unregisters a display transaction listener to provide the client a chance to - * update its surfaces within the same transaction as any display layout updates. - * - * @param listener The listener to unregister. - */ - public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - + private void unregisterDisplayTransactionListenerInternal( + DisplayTransactionListener listener) { // List is self-synchronized copy-on-write. mDisplayTransactionListeners.remove(listener); } - /** - * Overrides the display information of a particular logical display. - * This is used by the window manager to control the size and characteristics - * of the default display. It is expected to apply the requested change - * to the display information synchronously so that applications will immediately - * observe the new state. - * - * NOTE: This method must be the only entry point by which the window manager - * influences the logical configuration of displays. - * - * @param displayId The logical display id. - * @param info The new data to be stored. - */ - public void setDisplayInfoOverrideFromWindowManager( + private void setDisplayInfoOverrideFromWindowManagerInternal( int displayId, DisplayInfo info) { synchronized (mSyncRoot) { LogicalDisplay display = mLogicalDisplays.get(displayId); @@ -334,11 +296,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } } - /** - * Called by the window manager to perform traversals while holding a - * surface flinger transaction. - */ - public void performTraversalInTransactionFromWindowManager() { + private void performTraversalInTransactionFromWindowManagerInternal() { synchronized (mSyncRoot) { if (!mPendingTraversal) { return; @@ -354,96 +312,50 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } } - /** - * Called by the power manager to blank all displays. - */ - public void blankAllDisplaysFromPowerManager() { + private void requestGlobalDisplayStateInternal(int state) { synchronized (mSyncRoot) { - if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) { - mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED; - updateAllDisplayBlankingLocked(); + if (mGlobalDisplayState != state) { + mGlobalDisplayState = state; + updateGlobalDisplayStateLocked(); scheduleTraversalLocked(false); } } } - /** - * Called by the power manager to unblank all displays. - */ - public void unblankAllDisplaysFromPowerManager() { + private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) { synchronized (mSyncRoot) { - if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) { - mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED; - updateAllDisplayBlankingLocked(); - scheduleTraversalLocked(false); - } - } - } - - /** - * Returns information about the specified logical display. - * - * @param displayId The logical display id. - * @return The logical display info, or null if the display does not exist. The - * returned object must be treated as immutable. - */ - @Override // Binder call - public DisplayInfo getDisplayInfo(int displayId) { - final int callingUid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - LogicalDisplay display = mLogicalDisplays.get(displayId); - if (display != null) { - DisplayInfo info = display.getDisplayInfoLocked(); - if (info.hasAccess(callingUid)) { - return info; - } + LogicalDisplay display = mLogicalDisplays.get(displayId); + if (display != null) { + DisplayInfo info = display.getDisplayInfoLocked(); + if (info.hasAccess(callingUid)) { + return info; } - return null; } - } finally { - Binder.restoreCallingIdentity(token); + return null; } } - /** - * Returns the list of all display ids. - */ - @Override // Binder call - public int[] getDisplayIds() { - final int callingUid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - final int count = mLogicalDisplays.size(); - int[] displayIds = new int[count]; - int n = 0; - for (int i = 0; i < count; i++) { - LogicalDisplay display = mLogicalDisplays.valueAt(i); - DisplayInfo info = display.getDisplayInfoLocked(); - if (info.hasAccess(callingUid)) { - displayIds[n++] = mLogicalDisplays.keyAt(i); - } - } - if (n != count) { - displayIds = Arrays.copyOfRange(displayIds, 0, n); + private int[] getDisplayIdsInternal(int callingUid) { + synchronized (mSyncRoot) { + final int count = mLogicalDisplays.size(); + int[] displayIds = new int[count]; + int n = 0; + for (int i = 0; i < count; i++) { + LogicalDisplay display = mLogicalDisplays.valueAt(i); + DisplayInfo info = display.getDisplayInfoLocked(); + if (info.hasAccess(callingUid)) { + displayIds[n++] = mLogicalDisplays.keyAt(i); } - return displayIds; } - } finally { - Binder.restoreCallingIdentity(token); + if (n != count) { + displayIds = Arrays.copyOfRange(displayIds, 0, n); + } + return displayIds; } } - @Override // Binder call - public void registerCallback(IDisplayManagerCallback callback) { - if (callback == null) { - throw new IllegalArgumentException("listener must not be null"); - } - + private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid) { synchronized (mSyncRoot) { - int callingPid = Binder.getCallingPid(); if (mCallbacks.get(callingPid) != null) { throw new SecurityException("The calling process has already " + "registered an IDisplayManagerCallback."); @@ -469,24 +381,14 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } } - @Override // Binder call - public void startWifiDisplayScan() { - mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, - "Permission required to start wifi display scans"); - - final int callingPid = Binder.getCallingPid(); - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - CallbackRecord record = mCallbacks.get(callingPid); - if (record == null) { - throw new IllegalStateException("The calling process has not " - + "registered an IDisplayManagerCallback."); - } - startWifiDisplayScanLocked(record); + private void startWifiDisplayScanInternal(int callingPid) { + synchronized (mSyncRoot) { + CallbackRecord record = mCallbacks.get(callingPid); + if (record == null) { + throw new IllegalStateException("The calling process has not " + + "registered an IDisplayManagerCallback."); } - } finally { - Binder.restoreCallingIdentity(token); + startWifiDisplayScanLocked(record); } } @@ -501,24 +403,14 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } } - @Override // Binder call - public void stopWifiDisplayScan() { - mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, - "Permission required to stop wifi display scans"); - - final int callingPid = Binder.getCallingPid(); - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - CallbackRecord record = mCallbacks.get(callingPid); - if (record == null) { - throw new IllegalStateException("The calling process has not " - + "registered an IDisplayManagerCallback."); - } - stopWifiDisplayScanLocked(record); + private void stopWifiDisplayScanInternal(int callingPid) { + synchronized (mSyncRoot) { + CallbackRecord record = mCallbacks.get(callingPid); + if (record == null) { + throw new IllegalStateException("The calling process has not " + + "registered an IDisplayManagerCallback."); } - } finally { - Binder.restoreCallingIdentity(token); + stopWifiDisplayScanLocked(record); } } @@ -537,255 +429,123 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } } - @Override // Binder call - public void connectWifiDisplay(String address) { - if (address == null) { - throw new IllegalArgumentException("address must not be null"); - } - mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, - "Permission required to connect to a wifi display"); - - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - if (mWifiDisplayAdapter != null) { - mWifiDisplayAdapter.requestConnectLocked(address); - } + private void connectWifiDisplayInternal(String address) { + synchronized (mSyncRoot) { + if (mWifiDisplayAdapter != null) { + mWifiDisplayAdapter.requestConnectLocked(address); } - } finally { - Binder.restoreCallingIdentity(token); } } - @Override - public void pauseWifiDisplay() { - mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, - "Permission required to pause a wifi display session"); - - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - if (mWifiDisplayAdapter != null) { - mWifiDisplayAdapter.requestPauseLocked(); - } + private void pauseWifiDisplayInternal() { + synchronized (mSyncRoot) { + if (mWifiDisplayAdapter != null) { + mWifiDisplayAdapter.requestPauseLocked(); } - } finally { - Binder.restoreCallingIdentity(token); } } - @Override - public void resumeWifiDisplay() { - mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, - "Permission required to resume a wifi display session"); - - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - if (mWifiDisplayAdapter != null) { - mWifiDisplayAdapter.requestResumeLocked(); - } + private void resumeWifiDisplayInternal() { + synchronized (mSyncRoot) { + if (mWifiDisplayAdapter != null) { + mWifiDisplayAdapter.requestResumeLocked(); } - } finally { - Binder.restoreCallingIdentity(token); } } - @Override // Binder call - public void disconnectWifiDisplay() { - // This request does not require special permissions. - // Any app can request disconnection from the currently active wifi display. - // This exception should no longer be needed once wifi display control moves - // to the media router service. - - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - if (mWifiDisplayAdapter != null) { - mWifiDisplayAdapter.requestDisconnectLocked(); - } + private void disconnectWifiDisplayInternal() { + synchronized (mSyncRoot) { + if (mWifiDisplayAdapter != null) { + mWifiDisplayAdapter.requestDisconnectLocked(); } - } finally { - Binder.restoreCallingIdentity(token); } } - @Override // Binder call - public void renameWifiDisplay(String address, String alias) { - if (address == null) { - throw new IllegalArgumentException("address must not be null"); - } - mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, - "Permission required to rename to a wifi display"); - - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - if (mWifiDisplayAdapter != null) { - mWifiDisplayAdapter.requestRenameLocked(address, alias); - } + private void renameWifiDisplayInternal(String address, String alias) { + synchronized (mSyncRoot) { + if (mWifiDisplayAdapter != null) { + mWifiDisplayAdapter.requestRenameLocked(address, alias); } - } finally { - Binder.restoreCallingIdentity(token); } } - @Override // Binder call - public void forgetWifiDisplay(String address) { - if (address == null) { - throw new IllegalArgumentException("address must not be null"); - } - mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, - "Permission required to forget to a wifi display"); - - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - if (mWifiDisplayAdapter != null) { - mWifiDisplayAdapter.requestForgetLocked(address); - } + private void forgetWifiDisplayInternal(String address) { + synchronized (mSyncRoot) { + if (mWifiDisplayAdapter != null) { + mWifiDisplayAdapter.requestForgetLocked(address); } - } finally { - Binder.restoreCallingIdentity(token); } } - @Override // Binder call - public WifiDisplayStatus getWifiDisplayStatus() { - // This request does not require special permissions. - // Any app can get information about available wifi displays. - - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - if (mWifiDisplayAdapter != null) { - return mWifiDisplayAdapter.getWifiDisplayStatusLocked(); - } - return new WifiDisplayStatus(); + private WifiDisplayStatus getWifiDisplayStatusInternal() { + synchronized (mSyncRoot) { + if (mWifiDisplayAdapter != null) { + return mWifiDisplayAdapter.getWifiDisplayStatusLocked(); } - } finally { - Binder.restoreCallingIdentity(token); + return new WifiDisplayStatus(); } } - @Override // Binder call - public int createVirtualDisplay(IBinder appToken, String packageName, + private int createVirtualDisplayInternal(IBinder appToken, int callingUid, String packageName, String name, int width, int height, int densityDpi, Surface surface, int flags) { - final int callingUid = Binder.getCallingUid(); - if (!validatePackageName(callingUid, packageName)) { - throw new SecurityException("packageName must match the calling uid"); - } - if (appToken == null) { - throw new IllegalArgumentException("appToken must not be null"); - } - if (TextUtils.isEmpty(name)) { - throw new IllegalArgumentException("name must be non-null and non-empty"); - } - if (width <= 0 || height <= 0 || densityDpi <= 0) { - throw new IllegalArgumentException("width, height, and densityDpi must be " - + "greater than 0"); - } - if (surface == null) { - throw new IllegalArgumentException("surface must not be null"); - } - if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) { - if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT) - != PackageManager.PERMISSION_GRANTED - && mContext.checkCallingPermission( - android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or " - + "CAPTURE_SECURE_VIDEO_OUTPUT permission to create a " - + "public virtual display."); - } - } - if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { - if (mContext.checkCallingPermission( - android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT " - + "to create a secure virtual display."); + synchronized (mSyncRoot) { + if (mVirtualDisplayAdapter == null) { + Slog.w(TAG, "Rejecting request to create private virtual display " + + "because the virtual display adapter is not available."); + return -1; } - } - - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - if (mVirtualDisplayAdapter == null) { - Slog.w(TAG, "Rejecting request to create private virtual display " - + "because the virtual display adapter is not available."); - return -1; - } - DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked( - appToken, callingUid, packageName, name, width, height, densityDpi, - surface, flags); - if (device == null) { - return -1; - } - - handleDisplayDeviceAddedLocked(device); - LogicalDisplay display = findLogicalDisplayForDeviceLocked(device); - if (display != null) { - return display.getDisplayIdLocked(); - } + DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked( + appToken, callingUid, packageName, name, width, height, densityDpi, + surface, flags); + if (device == null) { + return -1; + } - // Something weird happened and the logical display was not created. - Slog.w(TAG, "Rejecting request to create virtual display " - + "because the logical display was not created."); - mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken); - handleDisplayDeviceRemovedLocked(device); + handleDisplayDeviceAddedLocked(device); + LogicalDisplay display = findLogicalDisplayForDeviceLocked(device); + if (display != null) { + return display.getDisplayIdLocked(); } - } finally { - Binder.restoreCallingIdentity(token); + + // Something weird happened and the logical display was not created. + Slog.w(TAG, "Rejecting request to create virtual display " + + "because the logical display was not created."); + mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken); + handleDisplayDeviceRemovedLocked(device); } return -1; } - @Override // Binder call - public void releaseVirtualDisplay(IBinder appToken) { - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mSyncRoot) { - if (mVirtualDisplayAdapter == null) { - return; - } - - DisplayDevice device = - mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken); - if (device != null) { - handleDisplayDeviceRemovedLocked(device); - } + private void setVirtualDisplaySurfaceInternal(IBinder appToken, Surface surface) { + synchronized (mSyncRoot) { + if (mVirtualDisplayAdapter == null) { + return; } - } finally { - Binder.restoreCallingIdentity(token); + + mVirtualDisplayAdapter.setVirtualDisplaySurfaceLocked(appToken, surface); } } - private boolean validatePackageName(int uid, String packageName) { - if (packageName != null) { - String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); - if (packageNames != null) { - for (String n : packageNames) { - if (n.equals(packageName)) { - return true; - } - } + private void releaseVirtualDisplayInternal(IBinder appToken) { + synchronized (mSyncRoot) { + if (mVirtualDisplayAdapter == null) { + return; + } + + DisplayDevice device = + mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken); + if (device != null) { + handleDisplayDeviceRemovedLocked(device); } } - return false; } private void registerDefaultDisplayAdapter() { // Register default display adapter. synchronized (mSyncRoot) { - if (mHeadless) { - registerDisplayAdapterLocked(new HeadlessDisplayAdapter( - mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); - } else { - registerDisplayAdapterLocked(new LocalDisplayAdapter( - mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); - } + registerDisplayAdapterLocked(new LocalDisplayAdapter( + mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); } } @@ -853,7 +613,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { mDisplayDevices.add(device); addLogicalDisplayLocked(device); - updateDisplayBlankingLocked(device); + updateDisplayStateLocked(device); scheduleTraversalLocked(false); } @@ -892,27 +652,20 @@ public final class DisplayManagerService extends IDisplayManager.Stub { scheduleTraversalLocked(false); } - private void updateAllDisplayBlankingLocked() { + private void updateGlobalDisplayStateLocked() { final int count = mDisplayDevices.size(); for (int i = 0; i < count; i++) { DisplayDevice device = mDisplayDevices.get(i); - updateDisplayBlankingLocked(device); + updateDisplayStateLocked(device); } } - private void updateDisplayBlankingLocked(DisplayDevice device) { + private void updateDisplayStateLocked(DisplayDevice device) { // Blank or unblank the display immediately to match the state requested - // by the power manager (if known). + // by the display power controller (if known). DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { - switch (mAllDisplayBlankStateFromPowerManager) { - case DISPLAY_BLANK_STATE_BLANKED: - device.blankLocked(); - break; - case DISPLAY_BLANK_STATE_UNBLANKED: - device.unblankLocked(); - break; - } + device.requestDisplayStateLocked(mGlobalDisplayState); } } @@ -1002,26 +755,13 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } // Tell the input system about these new viewports. - if (mInputManagerFuncs != null) { + if (mInputManagerInternal != null) { mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT); } } - /** - * Tells the display manager whether there is interesting unique content on the - * specified logical display. This is used to control automatic mirroring. - * <p> - * If the display has unique content, then the display manager arranges for it - * to be presented on a physical display if appropriate. Otherwise, the display manager - * may choose to make the physical display mirror some other logical display. - * </p> - * - * @param displayId The logical display id to update. - * @param hasContent True if the logical display has content. - * @param inTraversal True if called from WindowManagerService during a window traversal prior - * to call to performTraversalInTransactionFromWindowManager. - */ - public void setDisplayHasContent(int displayId, boolean hasContent, boolean inTraversal) { + private void setDisplayHasContentInternal(int displayId, boolean hasContent, + boolean inTraversal) { synchronized (mSyncRoot) { LogicalDisplay display = mLogicalDisplays.get(displayId); if (display != null && display.hasContentLocked() != hasContent) { @@ -1042,13 +782,13 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } private void configureDisplayInTransactionLocked(DisplayDevice device) { - DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); - boolean isPrivate = (info.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0; + final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); + final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0; // Find the logical display that the display device is showing. - // Private displays never mirror other displays. + // Certain displays only ever show their own content. LogicalDisplay display = findLogicalDisplayForDeviceLocked(device); - if (!isPrivate) { + if (!ownContent) { if (display != null && !display.hasContentLocked()) { // If the display does not have any content of its own, then // automatically mirror the default logical display contents. @@ -1066,9 +806,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { + device.getDisplayDeviceInfoLocked()); return; } - boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED) - && (info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0; - display.configureDisplayInTransactionLocked(device, isBlanked); + display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF); // Update the viewports if needed. if (!mDefaultViewport.valid @@ -1107,7 +845,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { // Requests that performTraversalsInTransactionFromWindowManager be called at a // later time to apply changes to surfaces and displays. private void scheduleTraversalLocked(boolean inTraversal) { - if (!mPendingTraversal && mWindowManagerFuncs != null) { + if (!mPendingTraversal && mWindowManagerInternal != null) { mPendingTraversal = true; if (!inTraversal) { mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL); @@ -1140,25 +878,14 @@ public final class DisplayManagerService extends IDisplayManager.Stub { mTempCallbacks.clear(); } - @Override // Binder call - public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { - if (mContext == null - || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump DisplayManager from from pid=" - + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); - return; - } - + private void dumpInternal(PrintWriter pw) { pw.println("DISPLAY MANAGER (dumpsys display)"); synchronized (mSyncRoot) { - pw.println(" mHeadless=" + mHeadless); pw.println(" mOnlyCode=" + mOnlyCore); pw.println(" mSafeMode=" + mSafeMode); pw.println(" mPendingTraversal=" + mPendingTraversal); - pw.println(" mAllDisplayBlankStateFromPowerManager=" - + mAllDisplayBlankStateFromPowerManager); + pw.println(" mGlobalDisplayState=" + Display.stateToString(mGlobalDisplayState)); pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId); pw.println(" mDefaultViewport=" + mDefaultViewport); pw.println(" mExternalTouchViewport=" + mExternalTouchViewport); @@ -1200,6 +927,10 @@ public final class DisplayManagerService extends IDisplayManager.Stub { pw.println(" " + i + ": mPid=" + callback.mPid + ", mWifiDisplayScanRequested=" + callback.mWifiDisplayScanRequested); } + + if (mDisplayPowerController != null) { + mDisplayPowerController.dump(pw); + } } } @@ -1212,30 +943,6 @@ public final class DisplayManagerService extends IDisplayManager.Stub { public static final class SyncRoot { } - /** - * Private interface to the window manager. - */ - public interface WindowManagerFuncs { - /** - * Request that the window manager call - * {@link #performTraversalInTransactionFromWindowManager} within a surface - * transaction at a later time. - */ - void requestTraversal(); - } - - /** - * Private interface to the input manager. - */ - public interface InputManagerFuncs { - /** - * Sets information about the displays as needed by the input system. - * The input system should copy this information if required. - */ - void setDisplayViewports(DisplayViewport defaultViewport, - DisplayViewport externalTouchViewport); - } - private final class DisplayManagerHandler extends Handler { public DisplayManagerHandler(Looper looper) { super(looper, null, true /*async*/); @@ -1257,7 +964,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { break; case MSG_REQUEST_TRAVERSAL: - mWindowManagerFuncs.requestTraversal(); + mWindowManagerInternal.requestTraversalFromDisplayManager(); break; case MSG_UPDATE_VIEWPORT: { @@ -1265,7 +972,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { mTempDefaultViewport.copyFrom(mDefaultViewport); mTempExternalTouchViewport.copyFrom(mExternalTouchViewport); } - mInputManagerFuncs.setDisplayViewports( + mInputManagerInternal.setDisplayViewports( mTempDefaultViewport, mTempExternalTouchViewport); break; } @@ -1328,4 +1035,358 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } } } + + private final class BinderService extends IDisplayManager.Stub { + /** + * Returns information about the specified logical display. + * + * @param displayId The logical display id. + * @return The logical display info, or null if the display does not exist. The + * returned object must be treated as immutable. + */ + @Override // Binder call + public DisplayInfo getDisplayInfo(int displayId) { + final int callingUid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); + try { + return getDisplayInfoInternal(displayId, callingUid); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** + * Returns the list of all display ids. + */ + @Override // Binder call + public int[] getDisplayIds() { + final int callingUid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); + try { + return getDisplayIdsInternal(callingUid); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void registerCallback(IDisplayManagerCallback callback) { + if (callback == null) { + throw new IllegalArgumentException("listener must not be null"); + } + + final int callingPid = Binder.getCallingPid(); + final long token = Binder.clearCallingIdentity(); + try { + registerCallbackInternal(callback, callingPid); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void startWifiDisplayScan() { + mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, + "Permission required to start wifi display scans"); + + final int callingPid = Binder.getCallingPid(); + final long token = Binder.clearCallingIdentity(); + try { + startWifiDisplayScanInternal(callingPid); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void stopWifiDisplayScan() { + mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, + "Permission required to stop wifi display scans"); + + final int callingPid = Binder.getCallingPid(); + final long token = Binder.clearCallingIdentity(); + try { + stopWifiDisplayScanInternal(callingPid); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void connectWifiDisplay(String address) { + if (address == null) { + throw new IllegalArgumentException("address must not be null"); + } + mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, + "Permission required to connect to a wifi display"); + + final long token = Binder.clearCallingIdentity(); + try { + connectWifiDisplayInternal(address); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void disconnectWifiDisplay() { + // This request does not require special permissions. + // Any app can request disconnection from the currently active wifi display. + // This exception should no longer be needed once wifi display control moves + // to the media router service. + + final long token = Binder.clearCallingIdentity(); + try { + disconnectWifiDisplayInternal(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void renameWifiDisplay(String address, String alias) { + if (address == null) { + throw new IllegalArgumentException("address must not be null"); + } + mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, + "Permission required to rename to a wifi display"); + + final long token = Binder.clearCallingIdentity(); + try { + renameWifiDisplayInternal(address, alias); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void forgetWifiDisplay(String address) { + if (address == null) { + throw new IllegalArgumentException("address must not be null"); + } + mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, + "Permission required to forget to a wifi display"); + + final long token = Binder.clearCallingIdentity(); + try { + forgetWifiDisplayInternal(address); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void pauseWifiDisplay() { + mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, + "Permission required to pause a wifi display session"); + + final long token = Binder.clearCallingIdentity(); + try { + pauseWifiDisplayInternal(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void resumeWifiDisplay() { + mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, + "Permission required to resume a wifi display session"); + + final long token = Binder.clearCallingIdentity(); + try { + resumeWifiDisplayInternal(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public WifiDisplayStatus getWifiDisplayStatus() { + // This request does not require special permissions. + // Any app can get information about available wifi displays. + + final long token = Binder.clearCallingIdentity(); + try { + return getWifiDisplayStatusInternal(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public int createVirtualDisplay(IBinder appToken, String packageName, + String name, int width, int height, int densityDpi, Surface surface, int flags) { + final int callingUid = Binder.getCallingUid(); + if (!validatePackageName(callingUid, packageName)) { + throw new SecurityException("packageName must match the calling uid"); + } + if (appToken == null) { + throw new IllegalArgumentException("appToken must not be null"); + } + if (TextUtils.isEmpty(name)) { + throw new IllegalArgumentException("name must be non-null and non-empty"); + } + if (width <= 0 || height <= 0 || densityDpi <= 0) { + throw new IllegalArgumentException("width, height, and densityDpi must be " + + "greater than 0"); + } + if (callingUid != Process.SYSTEM_UID && + (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) { + if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT) + != PackageManager.PERMISSION_GRANTED + && mContext.checkCallingPermission( + android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or " + + "CAPTURE_SECURE_VIDEO_OUTPUT permission to create a " + + "public virtual display."); + } + } + if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { + if (mContext.checkCallingPermission( + android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT " + + "to create a secure virtual display."); + } + } + + final long token = Binder.clearCallingIdentity(); + try { + return createVirtualDisplayInternal(appToken, callingUid, packageName, + name, width, height, densityDpi, surface, flags); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void setVirtualDisplaySurface(IBinder appToken, Surface surface) { + final long token = Binder.clearCallingIdentity(); + try { + setVirtualDisplaySurfaceInternal(appToken, surface); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void releaseVirtualDisplay(IBinder appToken) { + final long token = Binder.clearCallingIdentity(); + try { + releaseVirtualDisplayInternal(appToken); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { + if (mContext == null + || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump DisplayManager from from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); + return; + } + + final long token = Binder.clearCallingIdentity(); + try { + dumpInternal(pw); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private boolean validatePackageName(int uid, String packageName) { + if (packageName != null) { + String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); + if (packageNames != null) { + for (String n : packageNames) { + if (n.equals(packageName)) { + return true; + } + } + } + } + return false; + } + } + + private final class LocalService extends DisplayManagerInternal { + @Override + public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler, + SensorManager sensorManager) { + synchronized (mSyncRoot) { + DisplayBlanker blanker = new DisplayBlanker() { + @Override + public void requestDisplayState(int state) { + // The order of operations is important for legacy reasons. + if (state == Display.STATE_OFF) { + requestGlobalDisplayStateInternal(state); + } + + callbacks.onDisplayStateChange(state); + + if (state != Display.STATE_OFF) { + requestGlobalDisplayStateInternal(state); + } + } + }; + mDisplayPowerController = new DisplayPowerController( + mContext, callbacks, handler, sensorManager, blanker); + } + } + + @Override + public boolean requestPowerState(DisplayPowerRequest request, + boolean waitForNegativeProximity) { + return mDisplayPowerController.requestPowerState(request, + waitForNegativeProximity); + } + + @Override + public boolean isProximitySensorAvailable() { + return mDisplayPowerController.isProximitySensorAvailable(); + } + + @Override + public DisplayInfo getDisplayInfo(int displayId) { + return getDisplayInfoInternal(displayId, Process.myUid()); + } + + @Override + public void registerDisplayTransactionListener(DisplayTransactionListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + + registerDisplayTransactionListenerInternal(listener); + } + + @Override + public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + + unregisterDisplayTransactionListenerInternal(listener); + } + + @Override + public void setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info) { + setDisplayInfoOverrideFromWindowManagerInternal(displayId, info); + } + + @Override + public void performTraversalInTransactionFromWindowManager() { + performTraversalInTransactionFromWindowManagerInternal(); + } + + @Override + public void setDisplayHasContent(int displayId, boolean hasContent, boolean inTraversal) { + setDisplayHasContentInternal(displayId, hasContent, inTraversal); + } + } } diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 30bc922..279a9cc 100644 --- a/services/java/com/android/server/power/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -14,12 +14,15 @@ * limitations under the License. */ -package com.android.server.power; +package com.android.server.display; -import com.android.server.LightsService; -import com.android.server.TwilightService; -import com.android.server.TwilightService.TwilightState; -import com.android.server.display.DisplayManagerService; +import com.android.internal.app.IBatteryStats; +import com.android.server.LocalServices; +import com.android.server.am.BatteryStatsService; +import com.android.server.lights.LightsManager; +import com.android.server.twilight.TwilightListener; +import com.android.server.twilight.TwilightManager; +import com.android.server.twilight.TwilightState; import android.animation.Animator; import android.animation.ObjectAnimator; @@ -29,16 +32,20 @@ import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; +import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks; +import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PowerManager; +import android.os.RemoteException; import android.os.SystemClock; import android.text.format.DateUtils; import android.util.FloatMath; import android.util.Slog; import android.util.Spline; import android.util.TimeUtils; +import android.view.Display; import java.io.PrintWriter; @@ -160,42 +167,37 @@ final class DisplayPowerController { private final Object mLock = new Object(); - // Notifier for sending asynchronous notifications. - private final Notifier mNotifier; - - // The display suspend blocker. - // Held while there are pending state change notifications. - private final SuspendBlocker mDisplaySuspendBlocker; - - // The display blanker. - private final DisplayBlanker mDisplayBlanker; - // Our handler. private final DisplayControllerHandler mHandler; // Asynchronous callbacks into the power manager service. // Only invoked from the handler thread while no locks are held. - private final Callbacks mCallbacks; - private Handler mCallbackHandler; + private final DisplayPowerCallbacks mCallbacks; + + // Battery stats. + private final IBatteryStats mBatteryStats; // The lights service. - private final LightsService mLights; + private final LightsManager mLights; // The twilight service. - private final TwilightService mTwilight; - - // The display manager. - private final DisplayManagerService mDisplayManager; + private final TwilightManager mTwilight; // The sensor manager. private final SensorManager mSensorManager; + // The display blanker. + private final DisplayBlanker mBlanker; + // The proximity sensor, or null if not available or needed. private Sensor mProximitySensor; // The light sensor, or null if not available or needed. private Sensor mLightSensor; + // The doze screen brightness. + private final int mScreenBrightnessDozeConfig; + // The dim screen brightness. private final int mScreenBrightnessDimConfig; @@ -350,25 +352,23 @@ final class DisplayPowerController { /** * Creates the display power controller. */ - public DisplayPowerController(Looper looper, Context context, Notifier notifier, - LightsService lights, TwilightService twilight, SensorManager sensorManager, - DisplayManagerService displayManager, - SuspendBlocker displaySuspendBlocker, DisplayBlanker displayBlanker, - Callbacks callbacks, Handler callbackHandler) { - mHandler = new DisplayControllerHandler(looper); - mNotifier = notifier; - mDisplaySuspendBlocker = displaySuspendBlocker; - mDisplayBlanker = displayBlanker; + public DisplayPowerController(Context context, + DisplayPowerCallbacks callbacks, Handler handler, + SensorManager sensorManager, DisplayBlanker blanker) { + mHandler = new DisplayControllerHandler(handler.getLooper()); mCallbacks = callbacks; - mCallbackHandler = callbackHandler; - mLights = lights; - mTwilight = twilight; + mBatteryStats = BatteryStatsService.getService(); + mLights = LocalServices.getService(LightsManager.class); + mTwilight = LocalServices.getService(TwilightManager.class); mSensorManager = sensorManager; - mDisplayManager = displayManager; + mBlanker = blanker; final Resources resources = context.getResources(); + mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger( + com.android.internal.R.integer.config_screenBrightnessDoze)); + mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger( com.android.internal.R.integer.config_screenBrightnessDim)); @@ -526,9 +526,11 @@ final class DisplayPowerController { } private void initialize() { - mPowerState = new DisplayPowerState( - new ElectronBeam(mDisplayManager), mDisplayBlanker, - mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT)); + // Initialize the power state object for the default display. + // In the future, we might manage multiple displays independently. + mPowerState = new DisplayPowerState(mBlanker, + mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT), + new ElectronBeam(Display.DEFAULT_DISPLAY)); mElectronBeamOnAnimator = ObjectAnimator.ofFloat( mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f); @@ -542,6 +544,14 @@ final class DisplayPowerController { mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>( mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS); + + // Initialize screen state for battery stats. + try { + mBatteryStats.noteScreenState(mPowerState.getScreenState()); + mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness()); + } catch (RemoteException ex) { + // same process + } } private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() { @@ -565,7 +575,7 @@ final class DisplayPowerController { final boolean mustNotify; boolean mustInitialize = false; boolean updateAutoBrightness = mTwilightChanged; - boolean wasDim = false; + boolean wasDimOrDoze = false; mTwilightChanged = false; synchronized (mLock) { @@ -585,7 +595,8 @@ final class DisplayPowerController { != mPendingRequestLocked.screenAutoBrightnessAdjustment) { updateAutoBrightness = true; } - wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM); + wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM + || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE); mPowerRequest.copyFrom(mPendingRequestLocked); mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; mPendingWaitForNegativeProximityLocked = false; @@ -631,12 +642,12 @@ final class DisplayPowerController { // Turn on the light sensor if needed. if (mLightSensor != null) { - setLightSensorEnabled(mPowerRequest.useAutoBrightness - && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness); + setLightSensorEnabled(mPowerRequest.wantLightSensorEnabled(), + updateAutoBrightness); } // Set the screen brightness. - if (wantScreenOn(mPowerRequest.screenState)) { + if (mPowerRequest.wantScreenOnAny()) { int target; boolean slow; if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) { @@ -653,12 +664,16 @@ final class DisplayPowerController { slow = false; mUsingScreenAutoBrightness = false; } - if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) { + if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) { + // Dim quickly to the doze state. + target = mScreenBrightnessDozeConfig; + slow = false; + } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) { // Dim quickly by at least some minimum amount. target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION, mScreenBrightnessDimConfig); slow = false; - } else if (wasDim) { + } else if (wasDimOrDoze) { // Brighten quickly. slow = false; } @@ -672,9 +687,9 @@ final class DisplayPowerController { // Animate the screen on or off unless blocked. if (mScreenOffBecauseOfProximity) { // Screen off due to proximity. - setScreenOn(false); + setScreenState(Display.STATE_OFF); unblockScreenOn(); - } else if (wantScreenOn(mPowerRequest.screenState)) { + } else if (mPowerRequest.wantScreenOnAny()) { // Want screen on. // Wait for previous off animation to complete beforehand. // It is relatively short but if we cancel it and switch to the @@ -683,7 +698,8 @@ final class DisplayPowerController { // Turn the screen on. The contents of the screen may not yet // be visible if the electron beam has not been dismissed because // its last frame of animation is solid black. - setScreenOn(true); + setScreenState(mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE + ? Display.STATE_DOZING : Display.STATE_ON); if (mPowerRequest.blockScreenOn && mPowerState.getElectronBeamLevel() == 0.0f) { @@ -716,12 +732,12 @@ final class DisplayPowerController { if (!mElectronBeamOnAnimator.isStarted()) { if (!mElectronBeamOffAnimator.isStarted()) { if (mPowerState.getElectronBeamLevel() == 0.0f) { - setScreenOn(false); + setScreenState(Display.STATE_OFF); } else if (mPowerState.prepareElectronBeam( mElectronBeamFadesConfig ? ElectronBeam.MODE_FADE : ElectronBeam.MODE_COOL_DOWN) - && mPowerState.isScreenOn()) { + && mPowerState.getScreenState() != Display.STATE_OFF) { mElectronBeamOffAnimator.start(); } else { mElectronBeamOffAnimator.end(); @@ -754,9 +770,9 @@ final class DisplayPowerController { private void blockScreenOn() { if (!mScreenOnWasBlocked) { mScreenOnWasBlocked = true; + mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime(); if (DEBUG) { Slog.d(TAG, "Blocked screen on."); - mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime(); } } } @@ -771,13 +787,13 @@ final class DisplayPowerController { } } - private void setScreenOn(boolean on) { - if (mPowerState.isScreenOn() != on) { - mPowerState.setScreenOn(on); - if (on) { - mNotifier.onScreenOn(); - } else { - mNotifier.onScreenOff(); + private void setScreenState(int state) { + if (mPowerState.getScreenState() != state) { + mPowerState.setScreenState(state); + try { + mBatteryStats.noteScreenState(state); + } catch (RemoteException ex) { + // same process } } } @@ -806,7 +822,11 @@ final class DisplayPowerController { private void animateScreenBrightness(int target, int rate) { if (mScreenBrightnessRampAnimator.animateTo(target, rate)) { - mNotifier.onScreenBrightness(target); + try { + mBatteryStats.noteScreenBrightness(target); + } catch (RemoteException ex) { + // same process + } } } @@ -891,13 +911,13 @@ final class DisplayPowerController { private void clearPendingProximityDebounceTime() { if (mPendingProximityDebounceTime >= 0) { mPendingProximityDebounceTime = -1; - mDisplaySuspendBlocker.release(); // release wake lock + mCallbacks.releaseSuspendBlocker(); // release wake lock } } private void setPendingProximityDebounceTime(long debounceTime) { if (mPendingProximityDebounceTime < 0) { - mDisplaySuspendBlocker.acquire(); // acquire wake lock + mCallbacks.acquireSuspendBlocker(); // acquire wake lock } mPendingProximityDebounceTime = debounceTime; } @@ -1167,48 +1187,48 @@ final class DisplayPowerController { } private void sendOnStateChangedWithWakelock() { - mDisplaySuspendBlocker.acquire(); - mCallbackHandler.post(mOnStateChangedRunnable); + mCallbacks.acquireSuspendBlocker(); + mHandler.post(mOnStateChangedRunnable); } private final Runnable mOnStateChangedRunnable = new Runnable() { @Override public void run() { mCallbacks.onStateChanged(); - mDisplaySuspendBlocker.release(); + mCallbacks.releaseSuspendBlocker(); } }; private void sendOnProximityPositiveWithWakelock() { - mDisplaySuspendBlocker.acquire(); - mCallbackHandler.post(mOnProximityPositiveRunnable); + mCallbacks.acquireSuspendBlocker(); + mHandler.post(mOnProximityPositiveRunnable); } private final Runnable mOnProximityPositiveRunnable = new Runnable() { @Override public void run() { mCallbacks.onProximityPositive(); - mDisplaySuspendBlocker.release(); + mCallbacks.releaseSuspendBlocker(); } }; private void sendOnProximityNegativeWithWakelock() { - mDisplaySuspendBlocker.acquire(); - mCallbackHandler.post(mOnProximityNegativeRunnable); + mCallbacks.acquireSuspendBlocker(); + mHandler.post(mOnProximityNegativeRunnable); } private final Runnable mOnProximityNegativeRunnable = new Runnable() { @Override public void run() { mCallbacks.onProximityNegative(); - mDisplaySuspendBlocker.release(); + mCallbacks.releaseSuspendBlocker(); } }; public void dump(final PrintWriter pw) { synchronized (mLock) { pw.println(); - pw.println("Display Controller Locked State:"); + pw.println("Display Power Controller Locked State:"); pw.println(" mDisplayReadyLocked=" + mDisplayReadyLocked); pw.println(" mPendingRequestLocked=" + mPendingRequestLocked); pw.println(" mPendingRequestChangedLocked=" + mPendingRequestChangedLocked); @@ -1218,7 +1238,8 @@ final class DisplayPowerController { } pw.println(); - pw.println("Display Controller Configuration:"); + pw.println("Display Power Controller Configuration:"); + pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig); pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig); pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum); pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum); @@ -1237,7 +1258,7 @@ final class DisplayPowerController { private void dumpLocal(PrintWriter pw) { pw.println(); - pw.println("Display Controller Thread State:"); + pw.println("Display Power Controller Thread State:"); pw.println(" mPowerRequest=" + mPowerRequest); pw.println(" mWaitingForNegativeProximity=" + mWaitingForNegativeProximity); @@ -1296,24 +1317,6 @@ final class DisplayPowerController { } } - private static boolean wantScreenOn(int state) { - switch (state) { - case DisplayPowerRequest.SCREEN_STATE_BRIGHT: - case DisplayPowerRequest.SCREEN_STATE_DIM: - return true; - } - return false; - } - - /** - * Asynchronous callbacks from the power controller to the power manager service. - */ - public interface Callbacks { - void onStateChanged(); - void onProximityPositive(); - void onProximityNegative(); - } - private final class DisplayControllerHandler extends Handler { public DisplayControllerHandler(Looper looper) { super(looper, null, true /*async*/); @@ -1370,8 +1373,7 @@ final class DisplayPowerController { } }; - private final TwilightService.TwilightListener mTwilightListener = - new TwilightService.TwilightListener() { + private final TwilightListener mTwilightListener = new TwilightListener() { @Override public void onTwilightStateChanged() { mTwilightChanged = true; diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java index 5c048f1..a5f8849 100644 --- a/services/java/com/android/server/power/DisplayPowerState.java +++ b/services/core/java/com/android/server/display/DisplayPowerState.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.server.power; +package com.android.server.display; -import com.android.server.LightsService; +import com.android.server.lights.Light; import android.os.AsyncTask; import android.os.Handler; @@ -26,14 +26,15 @@ import android.util.FloatProperty; import android.util.IntProperty; import android.util.Slog; import android.view.Choreographer; +import android.view.Display; import java.io.PrintWriter; /** * Controls the display power state. * <p> - * This component is similar in nature to a {@link View} except that it describes - * the properties of a display. When properties are changed, the component + * This component is similar in nature to a {@link android.view.View} except that it + * describes the properties of a display. When properties are changed, the component * invalidates itself and posts a callback to apply the changes in a consistent order. * This mechanism enables multiple properties of the display power state to be animated * together smoothly by the animation framework. Some of the work to blank or unblank @@ -43,8 +44,7 @@ import java.io.PrintWriter; * that belongs to the {@link DisplayPowerController}. * </p><p> * We don't need to worry about holding a suspend blocker here because the - * {@link PowerManagerService} does that for us whenever there is a change - * in progress. + * power manager does that for us whenever there is a change in progress. * </p> */ final class DisplayPowerState { @@ -54,12 +54,12 @@ final class DisplayPowerState { private final Handler mHandler; private final Choreographer mChoreographer; + private final DisplayBlanker mBlanker; + private final Light mBacklight; private final ElectronBeam mElectronBeam; - private final DisplayBlanker mDisplayBlanker; - private final LightsService.Light mBacklight; private final PhotonicModulator mPhotonicModulator; - private boolean mScreenOn; + private int mScreenState; private int mScreenBrightness; private boolean mScreenReady; private boolean mScreenUpdatePending; @@ -71,13 +71,12 @@ final class DisplayPowerState { private Runnable mCleanListener; - public DisplayPowerState(ElectronBeam electronBean, - DisplayBlanker displayBlanker, LightsService.Light backlight) { + public DisplayPowerState(DisplayBlanker blanker, Light backlight, ElectronBeam electronBeam) { mHandler = new Handler(true /*async*/); mChoreographer = Choreographer.getInstance(); - mElectronBeam = electronBean; - mDisplayBlanker = displayBlanker; + mBlanker = blanker; mBacklight = backlight; + mElectronBeam = electronBeam; mPhotonicModulator = new PhotonicModulator(); // At boot time, we know that the screen is on and the electron beam @@ -86,7 +85,7 @@ final class DisplayPowerState { // Although we set the brightness to full on here, the display power controller // will reset the brightness to a new level immediately before the changes // actually have a chance to be applied. - mScreenOn = true; + mScreenState = Display.STATE_ON; mScreenBrightness = PowerManager.BRIGHTNESS_ON; scheduleScreenUpdate(); @@ -122,25 +121,25 @@ final class DisplayPowerState { }; /** - * Sets whether the screen is on or off. + * Sets whether the screen is on, off, or dozing. */ - public void setScreenOn(boolean on) { - if (mScreenOn != on) { + public void setScreenState(int state) { + if (mScreenState != state) { if (DEBUG) { - Slog.d(TAG, "setScreenOn: on=" + on); + Slog.d(TAG, "setScreenState: state=" + state); } - mScreenOn = on; + mScreenState = state; mScreenReady = false; scheduleScreenUpdate(); } } /** - * Returns true if the screen is on. + * Gets the desired screen state. */ - public boolean isScreenOn() { - return mScreenOn; + public int getScreenState() { + return mScreenState; } /** @@ -155,7 +154,7 @@ final class DisplayPowerState { } mScreenBrightness = brightness; - if (mScreenOn) { + if (mScreenState != Display.STATE_OFF) { mScreenReady = false; scheduleScreenUpdate(); } @@ -219,7 +218,7 @@ final class DisplayPowerState { } mElectronBeamLevel = level; - if (mScreenOn) { + if (mScreenState != Display.STATE_OFF) { mScreenReady = false; scheduleScreenUpdate(); // update backlight brightness } @@ -256,7 +255,7 @@ final class DisplayPowerState { public void dump(PrintWriter pw) { pw.println(); pw.println("Display Power State:"); - pw.println(" mScreenOn=" + mScreenOn); + pw.println(" mScreenState=" + Display.stateToString(mScreenState)); pw.println(" mScreenBrightness=" + mScreenBrightness); pw.println(" mScreenReady=" + mScreenReady); pw.println(" mScreenUpdatePending=" + mScreenUpdatePending); @@ -302,8 +301,9 @@ final class DisplayPowerState { public void run() { mScreenUpdatePending = false; - int brightness = mScreenOn && mElectronBeamLevel > 0f ? mScreenBrightness : 0; - if (mPhotonicModulator.setState(mScreenOn, brightness)) { + int brightness = mScreenState != Display.STATE_OFF + && mElectronBeamLevel > 0f ? mScreenBrightness : 0; + if (mPhotonicModulator.setState(mScreenState, brightness)) { if (DEBUG) { Slog.d(TAG, "Screen ready"); } @@ -335,26 +335,26 @@ final class DisplayPowerState { * Updates the state of the screen and backlight asynchronously on a separate thread. */ private final class PhotonicModulator { - private static final boolean INITIAL_SCREEN_ON = false; // unknown, assume off + private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off private static final int INITIAL_BACKLIGHT = -1; // unknown private final Object mLock = new Object(); - private boolean mPendingOn = INITIAL_SCREEN_ON; + private int mPendingState = INITIAL_SCREEN_STATE; private int mPendingBacklight = INITIAL_BACKLIGHT; - private boolean mActualOn = INITIAL_SCREEN_ON; + private int mActualState = INITIAL_SCREEN_STATE; private int mActualBacklight = INITIAL_BACKLIGHT; private boolean mChangeInProgress; - public boolean setState(boolean on, int backlight) { + public boolean setState(int state, int backlight) { synchronized (mLock) { - if (on != mPendingOn || backlight != mPendingBacklight) { + if (state != mPendingState || backlight != mPendingBacklight) { if (DEBUG) { - Slog.d(TAG, "Requesting new screen state: on=" + on - + ", backlight=" + backlight); + Slog.d(TAG, "Requesting new screen state: state=" + + Display.stateToString(state) + ", backlight=" + backlight); } - mPendingOn = on; + mPendingState = state; mPendingBacklight = backlight; if (!mChangeInProgress) { @@ -369,9 +369,9 @@ final class DisplayPowerState { public void dump(PrintWriter pw) { pw.println(); pw.println("Photonic Modulator State:"); - pw.println(" mPendingOn=" + mPendingOn); + pw.println(" mPendingState=" + Display.stateToString(mPendingState)); pw.println(" mPendingBacklight=" + mPendingBacklight); - pw.println(" mActualOn=" + mActualOn); + pw.println(" mActualState=" + Display.stateToString(mActualState)); pw.println(" mActualBacklight=" + mActualBacklight); pw.println(" mChangeInProgress=" + mChangeInProgress); } @@ -381,35 +381,35 @@ final class DisplayPowerState { public void run() { // Apply pending changes until done. for (;;) { - final boolean on; - final boolean onChanged; + final int state; + final boolean stateChanged; final int backlight; final boolean backlightChanged; synchronized (mLock) { - on = mPendingOn; - onChanged = (on != mActualOn); + state = mPendingState; + stateChanged = (state != mActualState); backlight = mPendingBacklight; backlightChanged = (backlight != mActualBacklight); - if (!onChanged && !backlightChanged) { + if (!stateChanged && !backlightChanged) { mChangeInProgress = false; break; } - mActualOn = on; + mActualState = state; mActualBacklight = backlight; } if (DEBUG) { - Slog.d(TAG, "Updating screen state: on=" + on - + ", backlight=" + backlight); + Slog.d(TAG, "Updating screen state: state=" + + Display.stateToString(state) + ", backlight=" + backlight); } - if (onChanged && on) { - mDisplayBlanker.unblankAllDisplays(); + if (stateChanged && state != Display.STATE_OFF) { + mBlanker.requestDisplayState(state); } if (backlightChanged) { mBacklight.setBrightness(backlight); } - if (onChanged && !on) { - mDisplayBlanker.blankAllDisplays(); + if (stateChanged && state == Display.STATE_OFF) { + mBlanker.requestDisplayState(state); } } diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/core/java/com/android/server/display/ElectronBeam.java index 729bd16..18e4049 100644 --- a/services/java/com/android/server/power/ElectronBeam.java +++ b/services/core/java/com/android/server/display/ElectronBeam.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.power; +package com.android.server.display; import java.io.PrintWriter; import java.nio.ByteBuffer; @@ -23,6 +23,8 @@ import java.nio.FloatBuffer; import android.graphics.PixelFormat; import android.graphics.SurfaceTexture; +import android.hardware.display.DisplayManagerInternal; +import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener; import android.opengl.EGL14; import android.opengl.EGLConfig; import android.opengl.EGLContext; @@ -33,15 +35,13 @@ import android.opengl.GLES11Ext; import android.os.Looper; import android.util.FloatMath; import android.util.Slog; -import android.view.Display; import android.view.DisplayInfo; import android.view.Surface.OutOfResourcesException; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; -import com.android.server.display.DisplayManagerService; -import com.android.server.display.DisplayTransactionListener; +import com.android.server.LocalServices; /** * Bzzzoooop! *crackle* @@ -73,11 +73,13 @@ final class ElectronBeam { // See code for details. private static final int DEJANK_FRAMES = 3; + private final int mDisplayId; + // Set to true when the animation context has been fully prepared. private boolean mPrepared; private int mMode; - private final DisplayManagerService mDisplayManager; + private final DisplayManagerInternal mDisplayManagerInternal; private int mDisplayLayerStack; // layer stack associated with primary display private int mDisplayWidth; // real width, not rotated private int mDisplayHeight; // real height, not rotated @@ -117,9 +119,9 @@ final class ElectronBeam { */ public static final int MODE_FADE = 2; - - public ElectronBeam(DisplayManagerService displayManager) { - mDisplayManager = displayManager; + public ElectronBeam(int displayId) { + mDisplayId = displayId; + mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); } /** @@ -138,7 +140,7 @@ final class ElectronBeam { // Get the display size and layer stack. // This is not expected to change while the electron beam surface is showing. - DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY); + DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId); mDisplayLayerStack = displayInfo.layerStack; mDisplayWidth = displayInfo.getNaturalWidth(); mDisplayHeight = displayInfo.getNaturalHeight(); @@ -527,7 +529,8 @@ final class ElectronBeam { mSurface = new Surface(); mSurface.copyFrom(mSurfaceControl); - mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurfaceControl); + mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, + mDisplayId, mSurfaceControl); mSurfaceLayout.onDisplayTransaction(); } finally { SurfaceControl.closeTransaction(); @@ -685,20 +688,23 @@ final class ElectronBeam { * owns the electron beam. */ private static final class NaturalSurfaceLayout implements DisplayTransactionListener { - private final DisplayManagerService mDisplayManager; + private final DisplayManagerInternal mDisplayManagerInternal; + private final int mDisplayId; private SurfaceControl mSurfaceControl; - public NaturalSurfaceLayout(DisplayManagerService displayManager, SurfaceControl surfaceControl) { - mDisplayManager = displayManager; + public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal, + int displayId, SurfaceControl surfaceControl) { + mDisplayManagerInternal = displayManagerInternal; + mDisplayId = displayId; mSurfaceControl = surfaceControl; - mDisplayManager.registerDisplayTransactionListener(this); + mDisplayManagerInternal.registerDisplayTransactionListener(this); } public void dispose() { synchronized (this) { mSurfaceControl = null; } - mDisplayManager.unregisterDisplayTransactionListener(this); + mDisplayManagerInternal.unregisterDisplayTransactionListener(this); } @Override @@ -708,7 +714,7 @@ final class ElectronBeam { return; } - DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY); + DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId); switch (displayInfo.rotation) { case Surface.ROTATION_0: mSurfaceControl.setPosition(0, 0); diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index cb8f3e2..096f263 100644 --- a/services/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -96,13 +96,21 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } + static boolean shouldBlank(int state) { + return state == Display.STATE_OFF; + } + + static boolean shouldUnblank(int state) { + return state == Display.STATE_ON || state == Display.STATE_DOZING; + } + private final class LocalDisplayDevice extends DisplayDevice { private final int mBuiltInDisplayId; private final SurfaceControl.PhysicalDisplayInfo mPhys; private DisplayDeviceInfo mInfo; private boolean mHavePendingChanges; - private boolean mBlanked; + private int mState = Display.STATE_UNKNOWN; public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId, SurfaceControl.PhysicalDisplayInfo phys) { @@ -135,6 +143,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.width = mPhys.width; mInfo.height = mPhys.height; mInfo.refreshRate = mPhys.refreshRate; + mInfo.state = mState; // Assume that all built-in displays that have secure output (eg. HDCP) also // support compositing from gralloc protected buffers. @@ -172,15 +181,16 @@ final class LocalDisplayAdapter extends DisplayAdapter { } @Override - public void blankLocked() { - mBlanked = true; - SurfaceControl.blankDisplay(getDisplayTokenLocked()); - } - - @Override - public void unblankLocked() { - mBlanked = false; - SurfaceControl.unblankDisplay(getDisplayTokenLocked()); + public void requestDisplayStateLocked(int state) { + if (mState != state) { + if (shouldBlank(state) && !shouldBlank(mState)) { + SurfaceControl.blankDisplay(getDisplayTokenLocked()); + } else if (shouldUnblank(state) && !shouldUnblank(mState)) { + SurfaceControl.unblankDisplay(getDisplayTokenLocked()); + } + mState = state; + updateDeviceInfoLocked(); + } } @Override @@ -188,7 +198,12 @@ final class LocalDisplayAdapter extends DisplayAdapter { super.dumpLocked(pw); pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId); pw.println("mPhys=" + mPhys); - pw.println("mBlanked=" + mBlanked); + pw.println("mState=" + Display.stateToString(mState)); + } + + private void updateDeviceInfoLocked() { + mInfo = null; + sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); } } diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 7e357c0..5499af6 100644 --- a/services/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -114,6 +114,7 @@ final class LogicalDisplay { mInfo.copyFrom(mOverrideDisplayInfo); mInfo.layerStack = mBaseDisplayInfo.layerStack; mInfo.name = mBaseDisplayInfo.name; + mInfo.state = mBaseDisplayInfo.state; } else { mInfo.copyFrom(mBaseDisplayInfo); } @@ -212,6 +213,7 @@ final class LogicalDisplay { mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi; mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi; mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi; + mBaseDisplayInfo.state = deviceInfo.state; mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width; mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height; mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width; diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java index 007acf7..bfd8372 100644 --- a/services/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java @@ -194,12 +194,14 @@ final class OverlayDisplayAdapter extends DisplayAdapter { private final int mDensityDpi; private final boolean mSecure; - private Surface mSurface; + private int mState; private SurfaceTexture mSurfaceTexture; + private Surface mSurface; private DisplayDeviceInfo mInfo; public OverlayDisplayDevice(IBinder displayToken, String name, - int width, int height, float refreshRate, int densityDpi, boolean secure, + int width, int height, float refreshRate, + int densityDpi, boolean secure, int state, SurfaceTexture surfaceTexture) { super(OverlayDisplayAdapter.this, displayToken); mName = name; @@ -208,6 +210,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { mRefreshRate = refreshRate; mDensityDpi = densityDpi; mSecure = secure; + mState = state; mSurfaceTexture = surfaceTexture; } @@ -230,6 +233,11 @@ final class OverlayDisplayAdapter extends DisplayAdapter { } } + public void setStateLocked(int state) { + mState = state; + mInfo = null; + } + @Override public DisplayDeviceInfo getDisplayDeviceInfoLocked() { if (mInfo == null) { @@ -247,6 +255,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { } mInfo.type = Display.TYPE_OVERLAY; mInfo.touch = DisplayDeviceInfo.TOUCH_NONE; + mInfo.state = mState; } return mInfo; } @@ -288,11 +297,12 @@ final class OverlayDisplayAdapter extends DisplayAdapter { // Called on the UI thread. @Override - public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) { + public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate, int state) { synchronized (getSyncRoot()) { IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure); mDevice = new OverlayDisplayDevice(displayToken, mName, - mWidth, mHeight, refreshRate, mDensityDpi, mSecure, surfaceTexture); + mWidth, mHeight, refreshRate, mDensityDpi, mSecure, + state, surfaceTexture); sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED); } @@ -309,6 +319,17 @@ final class OverlayDisplayAdapter extends DisplayAdapter { } } + // Called on the UI thread. + @Override + public void onStateChanged(int state) { + synchronized (getSyncRoot()) { + if (mDevice != null) { + mDevice.setStateLocked(state); + sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_CHANGED); + } + } + } + public void dumpLocked(PrintWriter pw) { pw.println(" " + mName + ":"); pw.println(" mWidth=" + mWidth); diff --git a/services/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java index f1dd60a..06891f3 100644 --- a/services/java/com/android/server/display/OverlayDisplayWindow.java +++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java @@ -282,6 +282,7 @@ final class OverlayDisplayWindow implements DumpUtils.Dump { if (displayId == mDefaultDisplay.getDisplayId()) { if (updateDefaultDisplayInfo()) { relayout(); + mListener.onStateChanged(mDefaultDisplayInfo.state); } else { dismiss(); } @@ -301,7 +302,8 @@ final class OverlayDisplayWindow implements DumpUtils.Dump { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { - mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate); + mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate, + mDefaultDisplayInfo.state); } @Override @@ -370,7 +372,9 @@ final class OverlayDisplayWindow implements DumpUtils.Dump { * Watches for significant changes in the overlay display window lifecycle. */ public interface Listener { - public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate); + public void onWindowCreated(SurfaceTexture surfaceTexture, + float refreshRate, int state); public void onWindowDestroyed(); + public void onStateChanged(int state); } }
\ No newline at end of file diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java index 67b3695..67b3695 100644 --- a/services/java/com/android/server/display/PersistentDataStore.java +++ b/services/core/java/com/android/server/display/PersistentDataStore.java diff --git a/services/java/com/android/server/power/RampAnimator.java b/services/core/java/com/android/server/display/RampAnimator.java index 4a4f080..6688d6a 100644 --- a/services/java/com/android/server/power/RampAnimator.java +++ b/services/core/java/com/android/server/display/RampAnimator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.power; +package com.android.server.display; import android.animation.ValueAnimator; import android.util.IntProperty; diff --git a/services/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 46d473c..a165f26 100644 --- a/services/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -69,6 +69,13 @@ final class VirtualDisplayAdapter extends DisplayAdapter { return device; } + public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) { + VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); + if (device != null) { + device.setSurfaceLocked(surface); + } + } + public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) { VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken); if (device != null) { @@ -144,6 +151,17 @@ final class VirtualDisplayAdapter extends DisplayAdapter { } } + public void setSurfaceLocked(Surface surface) { + if (mSurface != surface) { + if ((mSurface != null) != (surface != null)) { + sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); + } + sendTraversalRequestLocked(); + mSurface = surface; + mInfo = null; + } + } + @Override public DisplayDeviceInfo getDisplayDeviceInfoLocked() { if (mInfo == null) { @@ -157,8 +175,11 @@ final class VirtualDisplayAdapter extends DisplayAdapter { mInfo.yDpi = mDensityDpi; mInfo.flags = 0; if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { - mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE | - DisplayDeviceInfo.FLAG_NEVER_BLANK; + mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE + | DisplayDeviceInfo.FLAG_NEVER_BLANK + | DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; + } else if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) { + mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; } if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE; @@ -168,6 +189,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { } mInfo.type = Display.TYPE_VIRTUAL; mInfo.touch = DisplayDeviceInfo.TOUCH_NONE; + mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF; mInfo.ownerUid = mOwnerUid; mInfo.ownerPackageName = mOwnerPackageName; } diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java index cd57941..cd57941 100644 --- a/services/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java index dbb59b2..dbb59b2 100644 --- a/services/java/com/android/server/display/WifiDisplayController.java +++ b/services/core/java/com/android/server/display/WifiDisplayController.java diff --git a/services/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java index 85ef33e..649b5c9 100644 --- a/services/java/com/android/server/dreams/DreamController.java +++ b/services/core/java/com/android/server/dreams/DreamController.java @@ -85,6 +85,7 @@ final class DreamController { pw.println(" mToken=" + mCurrentDream.mToken); pw.println(" mName=" + mCurrentDream.mName); pw.println(" mIsTest=" + mCurrentDream.mIsTest); + pw.println(" mCanDoze=" + mCurrentDream.mCanDoze); pw.println(" mUserId=" + mCurrentDream.mUserId); pw.println(" mBound=" + mCurrentDream.mBound); pw.println(" mService=" + mCurrentDream.mService); @@ -94,15 +95,18 @@ final class DreamController { } } - public void startDream(Binder token, ComponentName name, boolean isTest, int userId) { + public void startDream(Binder token, ComponentName name, + boolean isTest, boolean canDoze, int userId) { stopDream(); // Close the notification shade. Don't need to send to all, but better to be explicit. mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL); - Slog.i(TAG, "Starting dream: name=" + name + ", isTest=" + isTest + ", userId=" + userId); + Slog.i(TAG, "Starting dream: name=" + name + + ", isTest=" + isTest + ", canDoze=" + canDoze + + ", userId=" + userId); - mCurrentDream = new DreamRecord(token, name, isTest, userId); + mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId); try { mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM); @@ -140,7 +144,8 @@ final class DreamController { final DreamRecord oldDream = mCurrentDream; mCurrentDream = null; Slog.i(TAG, "Stopping dream: name=" + oldDream.mName - + ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId); + + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze + + ", userId=" + oldDream.mUserId); mHandler.removeCallbacks(mStopUnconnectedDreamRunnable); @@ -187,7 +192,7 @@ final class DreamController { private void attach(IDreamService service) { try { service.asBinder().linkToDeath(mCurrentDream, 0); - service.attach(mCurrentDream.mToken); + service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze); } catch (RemoteException ex) { Slog.e(TAG, "The dream service died unexpectedly.", ex); stopDream(); @@ -213,6 +218,7 @@ final class DreamController { public final Binder mToken; public final ComponentName mName; public final boolean mIsTest; + public final boolean mCanDoze; public final int mUserId; public boolean mBound; @@ -221,10 +227,11 @@ final class DreamController { public boolean mSentStartBroadcast; public DreamRecord(Binder token, ComponentName name, - boolean isTest, int userId) { + boolean isTest, boolean canDoze, int userId) { mToken = token; mName = name; mIsTest = isTest; + mCanDoze = canDoze; mUserId = userId; } diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java new file mode 100644 index 0000000..8968da3 --- /dev/null +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -0,0 +1,656 @@ +/* + * Copyright (C) 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. + */ + +package com.android.server.dreams; + +import com.android.internal.util.DumpUtils; +import com.android.server.FgThread; +import com.android.server.SystemService; + +import android.Manifest; +import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Binder; +import android.os.Build; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.PowerManager; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.os.UserHandle; +import android.provider.Settings; +import android.service.dreams.DreamManagerInternal; +import android.service.dreams.DreamService; +import android.service.dreams.IDozeHardware; +import android.service.dreams.IDreamManager; +import android.text.TextUtils; +import android.util.Slog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import libcore.util.Objects; + +/** + * Service api for managing dreams. + * + * @hide + */ +public final class DreamManagerService extends SystemService { + private static final boolean DEBUG = false; + private static final String TAG = "DreamManagerService"; + + private final Object mLock = new Object(); + + private final Context mContext; + private final DreamHandler mHandler; + private final DreamController mController; + private final PowerManager mPowerManager; + private final PowerManager.WakeLock mDozeWakeLock; + private final McuHal mMcuHal; // synchronized on self + + private Binder mCurrentDreamToken; + private ComponentName mCurrentDreamName; + private int mCurrentDreamUserId; + private boolean mCurrentDreamIsTest; + private boolean mCurrentDreamCanDoze; + private boolean mCurrentDreamIsDozing; + private DozeHardwareWrapper mCurrentDreamDozeHardware; + + public DreamManagerService(Context context) { + super(context); + mContext = context; + mHandler = new DreamHandler(FgThread.get().getLooper()); + mController = new DreamController(context, mHandler, mControllerListener); + + mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG); + + mMcuHal = McuHal.open(); + if (mMcuHal != null) { + mMcuHal.reset(); + } + } + + @Override + public void onStart() { + publishBinderService(DreamService.DREAM_SERVICE, new BinderService()); + publishLocalService(DreamManagerInternal.class, new LocalService()); + } + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + synchronized (mLock) { + stopDreamLocked(); + } + } + }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); + } + } + + private void dumpInternal(PrintWriter pw) { + pw.println("DREAM MANAGER (dumpsys dreams)"); + pw.println(); + + pw.println("mMcuHal=" + mMcuHal); + pw.println(); + pw.println("mCurrentDreamToken=" + mCurrentDreamToken); + pw.println("mCurrentDreamName=" + mCurrentDreamName); + pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId); + pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest); + pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze); + pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing); + pw.println("mCurrentDreamDozeHardware=" + mCurrentDreamDozeHardware); + pw.println(); + + DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() { + @Override + public void dump(PrintWriter pw) { + mController.dump(pw); + } + }, pw, 200); + } + + private boolean isDreamingInternal() { + synchronized (mLock) { + return mCurrentDreamToken != null && !mCurrentDreamIsTest; + } + } + + private void requestDreamInternal() { + // Ask the power manager to nap. It will eventually call back into + // startDream() if/when it is appropriate to start dreaming. + // Because napping could cause the screen to turn off immediately if the dream + // cannot be started, we keep one eye open and gently poke user activity. + long time = SystemClock.uptimeMillis(); + mPowerManager.userActivity(time, true /*noChangeLights*/); + mPowerManager.nap(time); + } + + private void requestAwakenInternal() { + // Treat an explicit request to awaken as user activity so that the + // device doesn't immediately go to sleep if the timeout expired, + // for example when being undocked. + long time = SystemClock.uptimeMillis(); + mPowerManager.userActivity(time, false /*noChangeLights*/); + stopDreamInternal(); + } + + private void finishSelfInternal(IBinder token) { + if (DEBUG) { + Slog.d(TAG, "Dream finished: " + token); + } + + // Note that a dream finishing and self-terminating is not + // itself considered user activity. If the dream is ending because + // the user interacted with the device then user activity will already + // have been poked so the device will stay awake a bit longer. + // If the dream is ending on its own for other reasons and no wake + // locks are held and the user activity timeout has expired then the + // device may simply go to sleep. + synchronized (mLock) { + if (mCurrentDreamToken == token) { + stopDreamLocked(); + } + } + } + + private void testDreamInternal(ComponentName dream, int userId) { + synchronized (mLock) { + startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId); + } + } + + private void startDreamInternal(boolean doze) { + final int userId = ActivityManager.getCurrentUser(); + final ComponentName dream = doze ? getDozeComponent() : chooseDreamForUser(userId); + if (dream != null) { + synchronized (mLock) { + startDreamLocked(dream, false /*isTest*/, doze, userId); + } + } + } + + private void stopDreamInternal() { + synchronized (mLock) { + stopDreamLocked(); + } + } + + private void startDozingInternal(IBinder token) { + if (DEBUG) { + Slog.d(TAG, "Dream requested to start dozing: " + token); + } + + synchronized (mLock) { + if (mCurrentDreamToken == token && mCurrentDreamCanDoze + && !mCurrentDreamIsDozing) { + mCurrentDreamIsDozing = true; + mDozeWakeLock.acquire(); + } + } + } + + private void stopDozingInternal(IBinder token) { + if (DEBUG) { + Slog.d(TAG, "Dream requested to stop dozing: " + token); + } + + synchronized (mLock) { + if (mCurrentDreamToken == token && mCurrentDreamIsDozing) { + mCurrentDreamIsDozing = false; + mDozeWakeLock.release(); + } + } + } + + private IDozeHardware getDozeHardwareInternal(IBinder token) { + synchronized (mLock) { + if (mCurrentDreamToken == token && mCurrentDreamCanDoze + && mCurrentDreamDozeHardware == null && mMcuHal != null) { + mCurrentDreamDozeHardware = new DozeHardwareWrapper(); + return mCurrentDreamDozeHardware; + } + return null; + } + } + + private ComponentName chooseDreamForUser(int userId) { + ComponentName[] dreams = getDreamComponentsForUser(userId); + return dreams != null && dreams.length != 0 ? dreams[0] : null; + } + + private ComponentName[] getDreamComponentsForUser(int userId) { + String names = Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_COMPONENTS, + userId); + ComponentName[] components = componentsFromString(names); + + // first, ensure components point to valid services + List<ComponentName> validComponents = new ArrayList<ComponentName>(); + if (components != null) { + for (ComponentName component : components) { + if (serviceExists(component)) { + validComponents.add(component); + } else { + Slog.w(TAG, "Dream " + component + " does not exist"); + } + } + } + + // fallback to the default dream component if necessary + if (validComponents.isEmpty()) { + ComponentName defaultDream = getDefaultDreamComponentForUser(userId); + if (defaultDream != null) { + Slog.w(TAG, "Falling back to default dream " + defaultDream); + validComponents.add(defaultDream); + } + } + return validComponents.toArray(new ComponentName[validComponents.size()]); + } + + private void setDreamComponentsForUser(int userId, ComponentName[] componentNames) { + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_COMPONENTS, + componentsToString(componentNames), + userId); + } + + private ComponentName getDefaultDreamComponentForUser(int userId) { + String name = Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT, + userId); + return name == null ? null : ComponentName.unflattenFromString(name); + } + + private ComponentName getDozeComponent() { + // Read the component from a system property to facilitate debugging. + // Note that for production devices, the dream should actually be declared in + // a config.xml resource. + String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null; + if (TextUtils.isEmpty(name)) { + // Read the component from a config.xml resource. + // The value should be specified in a resource overlay for the product. + name = mContext.getResources().getString( + com.android.internal.R.string.config_dozeComponent); + } + return TextUtils.isEmpty(name) ? null : ComponentName.unflattenFromString(name); + } + + private boolean serviceExists(ComponentName name) { + try { + return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null; + } catch (NameNotFoundException e) { + return false; + } + } + + private void startDreamLocked(final ComponentName name, + final boolean isTest, final boolean canDoze, final int userId) { + if (Objects.equal(mCurrentDreamName, name) + && mCurrentDreamIsTest == isTest + && mCurrentDreamCanDoze == canDoze + && mCurrentDreamUserId == userId) { + return; + } + + stopDreamLocked(); + + if (DEBUG) Slog.i(TAG, "Entering dreamland."); + + final Binder newToken = new Binder(); + mCurrentDreamToken = newToken; + mCurrentDreamName = name; + mCurrentDreamIsTest = isTest; + mCurrentDreamCanDoze = canDoze; + mCurrentDreamUserId = userId; + + mHandler.post(new Runnable() { + @Override + public void run() { + mController.startDream(newToken, name, isTest, canDoze, userId); + } + }); + } + + private void stopDreamLocked() { + if (mCurrentDreamToken != null) { + if (DEBUG) Slog.i(TAG, "Leaving dreamland."); + + cleanupDreamLocked(); + + mHandler.post(new Runnable() { + @Override + public void run() { + mController.stopDream(); + } + }); + } + } + + private void cleanupDreamLocked() { + mCurrentDreamToken = null; + mCurrentDreamName = null; + mCurrentDreamIsTest = false; + mCurrentDreamCanDoze = false; + mCurrentDreamUserId = 0; + if (mCurrentDreamIsDozing) { + mCurrentDreamIsDozing = false; + mDozeWakeLock.release(); + } + if (mCurrentDreamDozeHardware != null) { + mCurrentDreamDozeHardware.release(); + mCurrentDreamDozeHardware = null; + } + } + + private void checkPermission(String permission) { + if (mContext.checkCallingOrSelfPermission(permission) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Access denied to process: " + Binder.getCallingPid() + + ", must have permission " + permission); + } + } + + private static String componentsToString(ComponentName[] componentNames) { + StringBuilder names = new StringBuilder(); + if (componentNames != null) { + for (ComponentName componentName : componentNames) { + if (names.length() > 0) { + names.append(','); + } + names.append(componentName.flattenToString()); + } + } + return names.toString(); + } + + private static ComponentName[] componentsFromString(String names) { + if (names == null) { + return null; + } + String[] namesArray = names.split(","); + ComponentName[] componentNames = new ComponentName[namesArray.length]; + for (int i = 0; i < namesArray.length; i++) { + componentNames[i] = ComponentName.unflattenFromString(namesArray[i]); + } + return componentNames; + } + + private final DreamController.Listener mControllerListener = new DreamController.Listener() { + @Override + public void onDreamStopped(Binder token) { + synchronized (mLock) { + if (mCurrentDreamToken == token) { + cleanupDreamLocked(); + } + } + } + }; + + /** + * Handler for asynchronous operations performed by the dream manager. + * Ensures operations to {@link DreamController} are single-threaded. + */ + private final class DreamHandler extends Handler { + public DreamHandler(Looper looper) { + super(looper, null, true /*async*/); + } + } + + private final class BinderService extends IDreamManager.Stub { + @Override // Binder call + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump DreamManager from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + final long ident = Binder.clearCallingIdentity(); + try { + dumpInternal(pw); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public ComponentName[] getDreamComponents() { + checkPermission(android.Manifest.permission.READ_DREAM_STATE); + + final int userId = UserHandle.getCallingUserId(); + final long ident = Binder.clearCallingIdentity(); + try { + return getDreamComponentsForUser(userId); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void setDreamComponents(ComponentName[] componentNames) { + checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); + + final int userId = UserHandle.getCallingUserId(); + final long ident = Binder.clearCallingIdentity(); + try { + setDreamComponentsForUser(userId, componentNames); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public ComponentName getDefaultDreamComponent() { + checkPermission(android.Manifest.permission.READ_DREAM_STATE); + + final int userId = UserHandle.getCallingUserId(); + final long ident = Binder.clearCallingIdentity(); + try { + return getDefaultDreamComponentForUser(userId); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public boolean isDreaming() { + checkPermission(android.Manifest.permission.READ_DREAM_STATE); + + final long ident = Binder.clearCallingIdentity(); + try { + return isDreamingInternal(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void dream() { + checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); + + final long ident = Binder.clearCallingIdentity(); + try { + requestDreamInternal(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void testDream(ComponentName dream) { + if (dream == null) { + throw new IllegalArgumentException("dream must not be null"); + } + checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); + + final int callingUserId = UserHandle.getCallingUserId(); + final int currentUserId = ActivityManager.getCurrentUser(); + if (callingUserId != currentUserId) { + // This check is inherently prone to races but at least it's something. + Slog.w(TAG, "Aborted attempt to start a test dream while a different " + + " user is active: callingUserId=" + callingUserId + + ", currentUserId=" + currentUserId); + return; + } + final long ident = Binder.clearCallingIdentity(); + try { + testDreamInternal(dream, callingUserId); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void awaken() { + checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); + + final long ident = Binder.clearCallingIdentity(); + try { + requestAwakenInternal(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void finishSelf(IBinder token) { + // Requires no permission, called by Dream from an arbitrary process. + if (token == null) { + throw new IllegalArgumentException("token must not be null"); + } + + final long ident = Binder.clearCallingIdentity(); + try { + finishSelfInternal(token); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void startDozing(IBinder token) { + // Requires no permission, called by Dream from an arbitrary process. + if (token == null) { + throw new IllegalArgumentException("token must not be null"); + } + + final long ident = Binder.clearCallingIdentity(); + try { + startDozingInternal(token); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void stopDozing(IBinder token) { + // Requires no permission, called by Dream from an arbitrary process. + if (token == null) { + throw new IllegalArgumentException("token must not be null"); + } + + final long ident = Binder.clearCallingIdentity(); + try { + stopDozingInternal(token); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public IDozeHardware getDozeHardware(IBinder token) { + // Requires no permission, called by Dream from an arbitrary process. + if (token == null) { + throw new IllegalArgumentException("token must not be null"); + } + + final long ident = Binder.clearCallingIdentity(); + try { + return getDozeHardwareInternal(token); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + private final class LocalService extends DreamManagerInternal { + @Override + public void startDream(boolean doze) { + startDreamInternal(doze); + } + + @Override + public void stopDream() { + stopDreamInternal(); + } + + @Override + public boolean isDreaming() { + return isDreamingInternal(); + } + } + + private final class DozeHardwareWrapper extends IDozeHardware.Stub { + private boolean mReleased; + + public void release() { + synchronized (mMcuHal) { + if (!mReleased) { + mReleased = true; + mMcuHal.reset(); + } + } + } + + @Override // Binder call + public byte[] sendMessage(String msg, byte[] arg) { + if (msg == null) { + throw new IllegalArgumentException("msg must not be null"); + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mMcuHal) { + if (mReleased) { + Slog.w(TAG, "Ignoring message to MCU HAL because the dream " + + "has already ended: " + msg); + return null; + } + return mMcuHal.sendMessage(msg, arg); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } +} diff --git a/services/core/java/com/android/server/dreams/McuHal.java b/services/core/java/com/android/server/dreams/McuHal.java new file mode 100644 index 0000000..1dc79c7 --- /dev/null +++ b/services/core/java/com/android/server/dreams/McuHal.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.dreams; + +import android.service.dreams.DozeHardware; + +/** + * Provides access to the low-level microcontroller hardware abstraction layer. + */ +final class McuHal { + private final long mPtr; + + private static native long nativeOpen(); + private static native byte[] nativeSendMessage(long ptr, String msg, byte[] arg); + + private McuHal(long ptr) { + mPtr = ptr; + } + + public static McuHal open() { + long ptr = nativeOpen(); + return ptr != 0 ? new McuHal(ptr) : null; + } + + public void reset() { + sendMessage(DozeHardware.MSG_ENABLE_MCU, DozeHardware.VALUE_OFF); + } + + public byte[] sendMessage(String msg, byte[] arg) { + return nativeSendMessage(mPtr, msg, arg); + } +} diff --git a/services/java/com/android/server/firewall/AndFilter.java b/services/core/java/com/android/server/firewall/AndFilter.java index 13551de..13551de 100644 --- a/services/java/com/android/server/firewall/AndFilter.java +++ b/services/core/java/com/android/server/firewall/AndFilter.java diff --git a/services/java/com/android/server/firewall/CategoryFilter.java b/services/core/java/com/android/server/firewall/CategoryFilter.java index 246c096..246c096 100644 --- a/services/java/com/android/server/firewall/CategoryFilter.java +++ b/services/core/java/com/android/server/firewall/CategoryFilter.java diff --git a/services/java/com/android/server/firewall/Filter.java b/services/core/java/com/android/server/firewall/Filter.java index 0a124f7..0a124f7 100644 --- a/services/java/com/android/server/firewall/Filter.java +++ b/services/core/java/com/android/server/firewall/Filter.java diff --git a/services/java/com/android/server/firewall/FilterFactory.java b/services/core/java/com/android/server/firewall/FilterFactory.java index dea8b40..dea8b40 100644 --- a/services/java/com/android/server/firewall/FilterFactory.java +++ b/services/core/java/com/android/server/firewall/FilterFactory.java diff --git a/services/java/com/android/server/firewall/FilterList.java b/services/core/java/com/android/server/firewall/FilterList.java index d34b203..d34b203 100644 --- a/services/java/com/android/server/firewall/FilterList.java +++ b/services/core/java/com/android/server/firewall/FilterList.java diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java index aaa0b58..88a2207 100644 --- a/services/java/com/android/server/firewall/IntentFirewall.java +++ b/services/core/java/com/android/server/firewall/IntentFirewall.java @@ -26,6 +26,7 @@ import android.content.pm.PackageManager; import android.os.Environment; import android.os.FileObserver; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.ArrayMap; @@ -106,8 +107,9 @@ public class IntentFirewall { } } - public IntentFirewall(AMSInterface ams) { + public IntentFirewall(AMSInterface ams, Handler handler) { mAms = ams; + mHandler = new FirewallHandler(handler.getLooper()); File rulesDir = getRulesDir(); rulesDir.mkdirs(); @@ -531,7 +533,13 @@ public class IntentFirewall { new ArrayMap<ComponentName, Rule[]>(0); } - final Handler mHandler = new Handler() { + final FirewallHandler mHandler; + + private final class FirewallHandler extends Handler { + public FirewallHandler(Looper looper) { + super(looper, null, true); + } + @Override public void handleMessage(Message msg) { readRulesDir(getRulesDir()); diff --git a/services/java/com/android/server/firewall/NotFilter.java b/services/core/java/com/android/server/firewall/NotFilter.java index 09bf629..09bf629 100644 --- a/services/java/com/android/server/firewall/NotFilter.java +++ b/services/core/java/com/android/server/firewall/NotFilter.java diff --git a/services/java/com/android/server/firewall/OrFilter.java b/services/core/java/com/android/server/firewall/OrFilter.java index f6a6f22..f6a6f22 100644 --- a/services/java/com/android/server/firewall/OrFilter.java +++ b/services/core/java/com/android/server/firewall/OrFilter.java diff --git a/services/java/com/android/server/firewall/PortFilter.java b/services/core/java/com/android/server/firewall/PortFilter.java index 84ace55..84ace55 100644 --- a/services/java/com/android/server/firewall/PortFilter.java +++ b/services/core/java/com/android/server/firewall/PortFilter.java diff --git a/services/java/com/android/server/firewall/SenderFilter.java b/services/core/java/com/android/server/firewall/SenderFilter.java index c0eee69..c0eee69 100644 --- a/services/java/com/android/server/firewall/SenderFilter.java +++ b/services/core/java/com/android/server/firewall/SenderFilter.java diff --git a/services/java/com/android/server/firewall/SenderPermissionFilter.java b/services/core/java/com/android/server/firewall/SenderPermissionFilter.java index caa65f3..caa65f3 100644 --- a/services/java/com/android/server/firewall/SenderPermissionFilter.java +++ b/services/core/java/com/android/server/firewall/SenderPermissionFilter.java diff --git a/services/java/com/android/server/firewall/StringFilter.java b/services/core/java/com/android/server/firewall/StringFilter.java index 28e99b3..28e99b3 100644 --- a/services/java/com/android/server/firewall/StringFilter.java +++ b/services/core/java/com/android/server/firewall/StringFilter.java diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java new file mode 100644 index 0000000..baae1d9 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import android.hardware.hdmi.HdmiCec; +import android.hardware.hdmi.HdmiCecMessage; +import android.hardware.hdmi.IHdmiCecListener; +import android.os.Binder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * HdmiCecDevice class represents a CEC logical device characterized + * by its device type. It is a superclass of those serving concrete device type. + * Currently we're interested in playback(one of sources), display(sink) device type + * only. The support for the other types like recorder, audio system will come later. + * + * <p>A physical device can contain the functions of + * more than one logical device, in which case it should create + * as many logical devices as necessary. + * + * <p>Note that if a physical device has multiple instances of a particular + * functionality, it should advertize only one instance. For instance, if + * a device has multiple tuners, it should only expose one for control + * via CEC. In this case, it is up to the device itself to manage multiple tuners. + * + * <p>The version of HDMI-CEC protocol supported in this class is 1.3a. + * + * <p>Declared as package-private, accessed by HdmiCecService only. + */ +abstract class HdmiCecDevice { + private static final String TAG = "HdmiCecDevice"; + + private final int mType; + + // List of listeners to the message/event coming to the device. + private final List<IHdmiCecListener> mListeners = new ArrayList<IHdmiCecListener>(); + private final Binder mBinder = new Binder(); + private final HdmiCecService mService; + + private boolean mIsActiveSource; + + /** + * Factory method that creates HdmiCecDevice instance to the device type. + */ + public static HdmiCecDevice create(HdmiCecService service, int type) { + if (type == HdmiCec.DEVICE_PLAYBACK) { + return new HdmiCecDevicePlayback(service, type); + } else if (type == HdmiCec.DEVICE_TV) { + return new HdmiCecDeviceTv(service, type); + } + return null; + } + + /** + * Constructor. + */ + public HdmiCecDevice(HdmiCecService service, int type) { + mService = service; + mType = type; + mIsActiveSource = false; + } + + /** + * Called right after the class is instantiated. This method can be used to + * implement any initialization tasks for the instance. + */ + abstract public void initialize(); + + /** + * Return the binder token that identifies this instance. + */ + public Binder getToken() { + return mBinder; + } + + /** + * Return the service instance. + */ + public HdmiCecService getService() { + return mService; + } + + /** + * Return the type of this device. + */ + public int getType() { + return mType; + } + + /** + * Register a listener to be invoked when events occur. + * + * @param listener the listern that will run + */ + public void addListener(IHdmiCecListener listener) { + mListeners.add(listener); + } + + /** + * Remove the listener that was previously registered. + * + * @param listener IHdmiCecListener instance to be removed + */ + public void removeListener(IHdmiCecListener listener) { + mListeners.remove(listener); + } + + /** + * Indicate if the device has listeners. + * + * @return true if there are listener instances for this device + */ + public boolean hasListener() { + return !mListeners.isEmpty(); + } + + /** + * Handle HDMI-CEC message coming to the device by invoking the registered + * listeners. + */ + public void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) { + if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE) { + mIsActiveSource = false; + } + + if (mListeners.size() == 0) { + return; + } + HdmiCecMessage message = new HdmiCecMessage(srcAddress, dstAddress, opcode, params); + for (IHdmiCecListener listener : mListeners) { + try { + listener.onMessageReceived(message); + } catch (RemoteException e) { + Log.e(TAG, "listener.onMessageReceived failed."); + } + } + } + + public void handleHotplug(boolean connected) { + for (IHdmiCecListener listener : mListeners) { + try { + listener.onCableStatusChanged(connected); + } catch (RemoteException e) { + Log.e(TAG, "listener.onCableStatusChanged failed."); + } + } + } + + /** + * Return the active status of the device. + * + * @return true if the device is the active source among the connected + * HDMI-CEC-enabled devices; otherwise false. + */ + public boolean isActiveSource() { + return mIsActiveSource; + } + + /** + * Update the active source state of the device. + */ + public void setIsActiveSource(boolean state) { + mIsActiveSource = state; + } + + /** + * Send <Active Source> command. The default implementation does nothing. Should be + * overriden by subclass. + */ + public void sendActiveSource(int physicalAddress) { + logWarning("<Active Source> not valid for the device type: " + mType + + " address:" + physicalAddress); + } + + /** + * Send <Inactive Source> command. The default implementation does nothing. Should be + * overriden by subclass. + */ + public void sendInactiveSource(int physicalAddress) { + logWarning("<Inactive Source> not valid for the device type: " + mType + + " address:" + physicalAddress); + } + + /** + * Send <Image View On> command. The default implementation does nothing. Should be + * overriden by subclass. + */ + public void sendImageViewOn() { + logWarning("<Image View On> not valid for the device type: " + mType); + } + + /** + * Send <Text View On> command. The default implementation does nothing. Should be + * overriden by subclass. + */ + public void sendTextViewOn() { + logWarning("<Text View On> not valid for the device type: " + mType); + } + + /** + * Check if the connected sink device is in powered-on state. The default implementation + * simply returns false. Should be overriden by subclass to report the correct state. + */ + public boolean isSinkDeviceOn() { + logWarning("isSinkDeviceOn() not valid for the device type: " + mType); + return false; + } + + private void logWarning(String msg) { + Log.w(TAG, msg); + } +} diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java new file mode 100644 index 0000000..f8cf11d --- /dev/null +++ b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import android.hardware.hdmi.HdmiCec; + +/** + * Class for the logical device of playback type. Devices such as DVD/Blueray player + * that support 'playback' feature are classified as playback device. It is common + * that they don't have built-in display, therefore need to talk, stream their contents + * to TV/display device which is connected through HDMI cable. + * + * <p>It closely monitors the status of display device (other devices can be of interest + * too, but with much less priority), declares itself as 'active source' to have + * display show its output, switch the source state as ordered by display that may be + * talking to many other devices connected to it. It also receives commands from display + * such as remote control signal, standby, status report, playback mode. + * + * <p>Declared as package-private, accessed by HdmiCecService only. + */ +final class HdmiCecDevicePlayback extends HdmiCecDevice { + private static final String TAG = "HdmiCecDevicePlayback"; + + private int mSinkDevicePowerStatus; + + /** + * Constructor. + */ + public HdmiCecDevicePlayback(HdmiCecService service, int type) { + super(service, type); + mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_UNKNOWN; + } + + @Override + public void initialize() { + // Playback device tries to obtain the power status of TV/display when created, + // and maintains it all through its lifecycle. CEC spec says there is + // a maximum 1 second response time. Therefore it should be kept in mind + // that there can be as much amount of period of time the power status + // of the display remains unknown after the query is sent out. + queryTvPowerStatus(); + } + + private void queryTvPowerStatus() { + getService().sendMessage(getType(), HdmiCec.ADDR_TV, + HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, HdmiCecService.EMPTY_PARAM); + } + + @Override + public void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) { + // Updates power status of display. The cases are: + // 1) Response for the queried power status request arrives. Update the status. + // 2) Broadcast or direct <Standby> command from TV, which is sent as TV itself is going + // into standby mode too. + if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) { + mSinkDevicePowerStatus = params[0]; + } else if (srcAddress == HdmiCec.ADDR_TV) { + if (opcode == HdmiCec.MESSAGE_STANDBY) { + mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_STANDBY; + } + } + super.handleMessage(srcAddress, dstAddress, opcode, params); + } + + @Override + public void handleHotplug(boolean connected) { + // If cable get disconnected sink device becomes unreachable. Switch the status + // to unknown, and query the status once the cable gets connected back. + if (!connected) { + mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_UNKNOWN; + } else { + queryTvPowerStatus(); + } + super.handleHotplug(connected); + } + + @Override + public boolean isSinkDeviceOn() { + return mSinkDevicePowerStatus == HdmiCec.POWER_STATUS_ON; + } + + @Override + public void sendActiveSource(int physicalAddress) { + setIsActiveSource(true); + byte[] param = new byte[] { + (byte) ((physicalAddress >> 8) & 0xff), + (byte) (physicalAddress & 0xff) + }; + getService().sendMessage(getType(), HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ACTIVE_SOURCE, + param); + } + + @Override + public void sendInactiveSource(int physicalAddress) { + setIsActiveSource(false); + byte[] param = new byte[] { + (byte) ((physicalAddress >> 8) & 0xff), + (byte) (physicalAddress & 0xff) + }; + getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_INACTIVE_SOURCE, + param); + } + + @Override + public void sendImageViewOn() { + getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_IMAGE_VIEW_ON, + HdmiCecService.EMPTY_PARAM); + } + + @Override + public void sendTextViewOn() { + getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_TEXT_VIEW_ON, + HdmiCecService.EMPTY_PARAM); + } +} diff --git a/services/java/com/android/server/display/DisplayTransactionListener.java b/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java index 34eb8f9..09ff3ca 100644 --- a/services/java/com/android/server/display/DisplayTransactionListener.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,13 +14,22 @@ * limitations under the License. */ -package com.android.server.display; +package com.android.server.hdmi; /** - * Called within a Surface transaction whenever the size or orientation of a - * display may have changed. Provides an opportunity for the client to - * update the position of its surfaces as part of the same transaction. + * Class for logical device of TV type. */ -public interface DisplayTransactionListener { - void onDisplayTransaction(); +final class HdmiCecDeviceTv extends HdmiCecDevice { + private static final String TAG = "HdmiCecDeviceTv"; + + /** + * Constructor. + */ + public HdmiCecDeviceTv(HdmiCecService service, int type) { + super(service, type); + } + + public void initialize() { + // TODO: Do the initialization task for TV device here. + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecService.java b/services/core/java/com/android/server/hdmi/HdmiCecService.java new file mode 100644 index 0000000..0a4c719 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/HdmiCecService.java @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.hardware.hdmi.HdmiCec; +import android.hardware.hdmi.HdmiCecMessage; +import android.hardware.hdmi.IHdmiCecListener; +import android.hardware.hdmi.IHdmiCecService; +import android.os.Binder; +import android.os.Build; +import android.os.IBinder; +import android.os.RemoteException; +import android.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; + +import com.android.server.SystemService; +import libcore.util.EmptyArray; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Locale; + +/** + * Provides a service for sending and processing HDMI-CEC messages, and providing + * the information on HDMI settings in general. + */ +public final class HdmiCecService extends SystemService { + private static final String TAG = "HdmiCecService"; + + // Maintains the allocated logical devices. Device type, not logical address, + // is used for key as logical address is likely to change over time while + // device type is permanent. Type-address mapping is maintained only at + // native level. + private final SparseArray<HdmiCecDevice> mLogicalDevices = new SparseArray<HdmiCecDevice>(); + + // List of IBinder.DeathRecipient instances to handle dead IHdmiCecListener + // objects. + private final ArrayList<ListenerRecord> mListenerRecords = new ArrayList<ListenerRecord>(); + + // Used to synchronize the access to the service. + private final Object mLock = new Object(); + + // Stores the pointer to the native implementation of the service that + // interacts with HAL. + private long mNativePtr; + + private static final String PERMISSION = "android.permission.HDMI_CEC"; + + static final byte[] EMPTY_PARAM = EmptyArray.BYTE; + + public HdmiCecService(Context context) { + super(context); + } + + private static native long nativeInit(HdmiCecService service); + + @Override + public void onStart() { + mNativePtr = nativeInit(this); + if (mNativePtr != 0) { + // TODO: Consider using a dedicated, configurable identifier for OSD name, maybe from + // Settings. It should be ASCII only, not a very long one (limited to 15 chars). + setOsdNameLocked(Build.MODEL); + publishBinderService(Context.HDMI_CEC_SERVICE, new BinderService()); + } + } + + /** + * Called by native when an HDMI-CEC message arrived. Invokes the registered + * listeners to handle the message. + */ + private void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) { + // TODO: Messages like <Standby> may not need be passed to listener + // but better be handled in service by turning off the screen + // or putting the device into suspend mode. List up such messages + // and handle them here. + synchronized (mLock) { + if (dstAddress == HdmiCec.ADDR_BROADCAST) { + for (int i = 0; i < mLogicalDevices.size(); ++i) { + mLogicalDevices.valueAt(i).handleMessage(srcAddress, dstAddress, opcode, + params); + } + } else { + int type = HdmiCec.getTypeFromAddress(dstAddress); + HdmiCecDevice device = mLogicalDevices.get(type); + if (device == null) { + Log.w(TAG, "logical device not found. type: " + type); + return; + } + device.handleMessage(srcAddress, dstAddress, opcode, params); + } + } + } + + /** + * Called by native when internal HDMI hotplug event occurs. Invokes the registered + * listeners to handle the event. + */ + private void handleHotplug(boolean connected) { + synchronized(mLock) { + for (int i = 0; i < mLogicalDevices.size(); ++i) { + mLogicalDevices.valueAt(i).handleHotplug(connected); + } + } + } + + /** + * Called by native when it needs to know whether we have an active source. + * The native part uses the return value to respond to <Request Active + * Source >. + * + * @return type of the device which is active; DEVICE_INACTIVE if there is + * no active logical device in the system. + */ + private int getActiveSource() { + synchronized(mLock) { + for (int i = 0; i < mLogicalDevices.size(); ++i) { + if (mLogicalDevices.valueAt(i).isActiveSource()) { + return mLogicalDevices.keyAt(i); + } + } + } + return HdmiCec.DEVICE_INACTIVE; + } + + /** + * Called by native when a request for the menu language of the device was + * received. The native part uses the return value to generate the message + * <Set Menu Language> in response. The language should be of + * the 3-letter format as defined in ISO/FDIS 639-2. We use system default + * locale. + */ + private String getLanguage(int type) { + return Locale.getDefault().getISO3Language(); + } + + private void enforceAccessPermission() { + getContext().enforceCallingOrSelfPermission(PERMISSION, "HdmiCecService"); + } + + private void dumpInternal(PrintWriter pw) { + pw.println("HdmiCecService (dumpsys hdmi_cec)"); + pw.println(""); + synchronized (mLock) { + for (int i = 0; i < mLogicalDevices.size(); ++i) { + HdmiCecDevice device = mLogicalDevices.valueAt(i); + pw.println("Device: type=" + device.getType() + + ", active=" + device.isActiveSource()); + } + } + } + + // Remove logical device of a given type. + private void removeLogicalDeviceLocked(int type) { + ensureValidType(type); + mLogicalDevices.remove(type); + nativeRemoveLogicalAddress(mNativePtr, type); + } + + private static void ensureValidType(int type) { + if (!HdmiCec.isValidType(type)) { + throw new IllegalArgumentException("invalid type: " + type); + } + } + + // Return the logical device identified by the given binder token. + private HdmiCecDevice getLogicalDeviceLocked(IBinder b) { + for (int i = 0; i < mLogicalDevices.size(); ++i) { + HdmiCecDevice device = mLogicalDevices.valueAt(i); + if (device.getToken() == b) { + return device; + } + } + throw new IllegalArgumentException("Device not found"); + } + + // package-private. Used by HdmiCecDevice and its subclasses only. + void sendMessage(int type, int address, int opcode, byte[] params) { + nativeSendMessage(mNativePtr, type, address, opcode, params); + } + + private void setOsdNameLocked(String name) { + nativeSetOsdName(mNativePtr, name.getBytes(Charset.forName("US-ASCII"))); + } + + private final class ListenerRecord implements IBinder.DeathRecipient { + private final IHdmiCecListener mListener; + private final int mType; + + public ListenerRecord(IHdmiCecListener listener, int type) { + mListener = listener; + mType = type; + } + + @Override + public void binderDied() { + synchronized (mLock) { + mListenerRecords.remove(this); + HdmiCecDevice device = mLogicalDevices.get(mType); + if (device != null) { + device.removeListener(mListener); + if (!device.hasListener()) { + removeLogicalDeviceLocked(mType); + } + } + } + } + } + + private final class BinderService extends IHdmiCecService.Stub { + + @Override + public IBinder allocateLogicalDevice(int type, IHdmiCecListener listener) { + enforceAccessPermission(); + ensureValidType(type); + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + synchronized (mLock) { + HdmiCecDevice device = mLogicalDevices.get(type); + if (device != null) { + Log.v(TAG, "Logical address already allocated. Adding listener only."); + } else { + int address = nativeAllocateLogicalAddress(mNativePtr, type); + if (!HdmiCec.isValidAddress(address)) { + Log.e(TAG, "Logical address was not allocated"); + return null; + } else { + device = HdmiCecDevice.create(HdmiCecService.this, type); + if (device == null) { + Log.e(TAG, "Device type not supported yet."); + return null; + } + device.initialize(); + mLogicalDevices.put(type, device); + } + } + + // Adds the listener and its monitor + ListenerRecord record = new ListenerRecord(listener, type); + try { + listener.asBinder().linkToDeath(record, 0); + } catch (RemoteException e) { + Log.w(TAG, "Listener already died"); + if (!device.hasListener()) { + removeLogicalDeviceLocked(type); + } + return null; + } + mListenerRecords.add(record); + device.addListener(listener); + return device.getToken(); + } + } + + @Override + public void sendActiveSource(IBinder b) { + enforceAccessPermission(); + synchronized (mLock) { + HdmiCecDevice device = getLogicalDeviceLocked(b); + device.sendActiveSource(nativeGetPhysicalAddress(mNativePtr)); + } + } + + @Override + public void sendInactiveSource(IBinder b) { + enforceAccessPermission(); + synchronized (mLock) { + HdmiCecDevice device = getLogicalDeviceLocked(b); + device.sendInactiveSource(nativeGetPhysicalAddress(mNativePtr)); + } + } + + @Override + public void sendImageViewOn(IBinder b) { + enforceAccessPermission(); + synchronized (mLock) { + HdmiCecDevice device = getLogicalDeviceLocked(b); + device.sendImageViewOn(); + } + } + + @Override + public void sendTextViewOn(IBinder b) { + enforceAccessPermission(); + synchronized (mLock) { + HdmiCecDevice device = getLogicalDeviceLocked(b); + device.sendTextViewOn(); + } + } + + public void sendGiveDevicePowerStatus(IBinder b, int address) { + enforceAccessPermission(); + synchronized (mLock) { + HdmiCecDevice device = getLogicalDeviceLocked(b); + nativeSendMessage(mNativePtr, device.getType(), address, + HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, EMPTY_PARAM); + } + } + + @Override + public boolean isTvOn(IBinder b) { + enforceAccessPermission(); + synchronized (mLock) { + HdmiCecDevice device = getLogicalDeviceLocked(b); + return device.isSinkDeviceOn(); + } + } + + @Override + public void removeServiceListener(IBinder b, IHdmiCecListener listener) { + enforceAccessPermission(); + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + synchronized (mLock) { + HdmiCecDevice device = getLogicalDeviceLocked(b); + for (ListenerRecord record : mListenerRecords) { + if (record.mType == device.getType() + && record.mListener.asBinder() == listener.asBinder()) { + mListenerRecords.remove(record); + device.removeListener(record.mListener); + if (!device.hasListener()) { + removeLogicalDeviceLocked(record.mType); + } + break; + } + } + } + } + + @Override + public void sendMessage(IBinder b, HdmiCecMessage message) { + enforceAccessPermission(); + if (message == null) { + throw new IllegalArgumentException("message must not be null"); + } + synchronized (mLock) { + HdmiCecDevice device = getLogicalDeviceLocked(b); + nativeSendMessage(mNativePtr, device.getType(), message.getDestination(), + message.getOpcode(), message.getParams()); + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission denial: can't dump HdmiCecService from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + + " without permission " + android.Manifest.permission.DUMP); + return; + } + final long ident = Binder.clearCallingIdentity(); + try { + dumpInternal(pw); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + private static native int nativeAllocateLogicalAddress(long handler, int deviceType); + private static native void nativeRemoveLogicalAddress(long handler, int deviceType); + private static native void nativeSendMessage(long handler, int deviceType, int destination, + int opcode, byte[] params); + private static native int nativeGetPhysicalAddress(long handler); + private static native void nativeSetOsdName(long handler, byte[] name); +} diff --git a/services/java/com/android/server/input/InputApplicationHandle.java b/services/core/java/com/android/server/input/InputApplicationHandle.java index 42c1052..3cf7edc 100644 --- a/services/java/com/android/server/input/InputApplicationHandle.java +++ b/services/core/java/com/android/server/input/InputApplicationHandle.java @@ -26,7 +26,7 @@ public final class InputApplicationHandle { // Pointer to the native input application handle. // This field is lazily initialized via JNI. @SuppressWarnings("unused") - private int ptr; + private long ptr; // The window manager's application window token. public final Object appWindowToken; diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 3145805..a32f7c1 100644 --- a/services/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -16,11 +16,12 @@ package com.android.server.input; +import android.view.Display; import com.android.internal.R; import com.android.internal.util.XmlUtils; +import com.android.server.DisplayThread; +import com.android.server.LocalServices; import com.android.server.Watchdog; -import com.android.server.display.DisplayManagerService; -import com.android.server.display.DisplayViewport; import org.xmlpull.v1.XmlPullParser; @@ -44,9 +45,12 @@ import android.content.res.Resources.NotFoundException; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.database.ContentObserver; +import android.hardware.display.DisplayViewport; import android.hardware.input.IInputDevicesChangedListener; import android.hardware.input.IInputManager; +import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; +import android.hardware.input.InputManagerInternal; import android.hardware.input.KeyboardLayout; import android.os.Binder; import android.os.Bundle; @@ -94,7 +98,7 @@ import libcore.util.Objects; * Wraps the C++ InputManager and provides its callbacks. */ public class InputManagerService extends IInputManager.Stub - implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs { + implements Watchdog.Monitor { static final String TAG = "InputManager"; static final boolean DEBUG = false; @@ -107,7 +111,7 @@ public class InputManagerService extends IInputManager.Stub private static final int MSG_RELOAD_DEVICE_ALIASES = 5; // Pointer to native input manager service object. - private final int mPtr; + private final long mPtr; private final Context mContext; private final InputManagerHandler mHandler; @@ -146,46 +150,47 @@ public class InputManagerService extends IInputManager.Stub IInputFilter mInputFilter; // guarded by mInputFilterLock InputFilterHost mInputFilterHost; // guarded by mInputFilterLock - private static native int nativeInit(InputManagerService service, + private static native long nativeInit(InputManagerService service, Context context, MessageQueue messageQueue); - private static native void nativeStart(int ptr); - private static native void nativeSetDisplayViewport(int ptr, boolean external, + private static native void nativeStart(long ptr); + private static native void nativeSetDisplayViewport(long ptr, boolean external, int displayId, int rotation, int logicalLeft, int logicalTop, int logicalRight, int logicalBottom, int physicalLeft, int physicalTop, int physicalRight, int physicalBottom, int deviceWidth, int deviceHeight); - private static native int nativeGetScanCodeState(int ptr, + private static native int nativeGetScanCodeState(long ptr, int deviceId, int sourceMask, int scanCode); - private static native int nativeGetKeyCodeState(int ptr, + private static native int nativeGetKeyCodeState(long ptr, int deviceId, int sourceMask, int keyCode); - private static native int nativeGetSwitchState(int ptr, + private static native int nativeGetSwitchState(long ptr, int deviceId, int sourceMask, int sw); - private static native boolean nativeHasKeys(int ptr, + private static native boolean nativeHasKeys(long ptr, int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists); - private static native void nativeRegisterInputChannel(int ptr, InputChannel inputChannel, + private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel, InputWindowHandle inputWindowHandle, boolean monitor); - private static native void nativeUnregisterInputChannel(int ptr, InputChannel inputChannel); - private static native void nativeSetInputFilterEnabled(int ptr, boolean enable); - private static native int nativeInjectInputEvent(int ptr, InputEvent event, + private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel); + private static native void nativeSetInputFilterEnabled(long ptr, boolean enable); + private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId, int injectorPid, int injectorUid, int syncMode, int timeoutMillis, int policyFlags); - private static native void nativeSetInputWindows(int ptr, InputWindowHandle[] windowHandles); - private static native void nativeSetInputDispatchMode(int ptr, boolean enabled, boolean frozen); - private static native void nativeSetSystemUiVisibility(int ptr, int visibility); - private static native void nativeSetFocusedApplication(int ptr, + private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles); + private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen); + private static native void nativeSetSystemUiVisibility(long ptr, int visibility); + private static native void nativeSetFocusedApplication(long ptr, InputApplicationHandle application); - private static native boolean nativeTransferTouchFocus(int ptr, + private static native boolean nativeTransferTouchFocus(long ptr, InputChannel fromChannel, InputChannel toChannel); - private static native void nativeSetPointerSpeed(int ptr, int speed); - private static native void nativeSetShowTouches(int ptr, boolean enabled); - private static native void nativeVibrate(int ptr, int deviceId, long[] pattern, + private static native void nativeSetPointerSpeed(long ptr, int speed); + private static native void nativeSetShowTouches(long ptr, boolean enabled); + private static native void nativeSetInteractive(long ptr, boolean interactive); + private static native void nativeVibrate(long ptr, int deviceId, long[] pattern, int repeat, int token); - private static native void nativeCancelVibrate(int ptr, int deviceId, int token); - private static native void nativeReloadKeyboardLayouts(int ptr); - private static native void nativeReloadDeviceAliases(int ptr); - private static native String nativeDump(int ptr); - private static native void nativeMonitor(int ptr); + private static native void nativeCancelVibrate(long ptr, int deviceId, int token); + private static native void nativeReloadKeyboardLayouts(long ptr); + private static native void nativeReloadDeviceAliases(long ptr); + private static native String nativeDump(long ptr); + private static native void nativeMonitor(long ptr); // Input event injection constants defined in InputDispatcher.h. private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0; @@ -241,15 +246,17 @@ public class InputManagerService extends IInputManager.Stub /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */ final boolean mUseDevInputEventForAudioJack; - public InputManagerService(Context context, Handler handler) { + public InputManagerService(Context context) { this.mContext = context; - this.mHandler = new InputManagerHandler(handler.getLooper()); + this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack=" + mUseDevInputEventForAudioJack); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); + + LocalServices.addService(InputManagerInternal.class, new LocalService()); } public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) { @@ -329,8 +336,7 @@ public class InputManagerService extends IInputManager.Stub nativeReloadDeviceAliases(mPtr); } - @Override - public void setDisplayViewports(DisplayViewport defaultViewport, + private void setDisplayViewportsInternal(DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) { if (defaultViewport.valid) { setDisplayViewport(false, defaultViewport); @@ -378,7 +384,7 @@ public class InputManagerService extends IInputManager.Stub public int getScanCodeState(int deviceId, int sourceMask, int scanCode) { return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode); } - + /** * Gets the current state of a switch by switch code. * @param deviceId The input device id, or -1 to consult all devices. @@ -413,10 +419,10 @@ public class InputManagerService extends IInputManager.Stub throw new IllegalArgumentException("keyExists must not be null and must be at " + "least as large as keyCodes."); } - + return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists); } - + /** * Creates an input channel that will receive all input from the input dispatcher. * @param inputChannelName The input channel name. @@ -426,7 +432,7 @@ public class InputManagerService extends IInputManager.Stub if (inputChannelName == null) { throw new IllegalArgumentException("inputChannelName must not be null."); } - + InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); nativeRegisterInputChannel(mPtr, inputChannels[0], null, true); inputChannels[0].dispose(); // don't need to retain the Java object reference @@ -444,10 +450,10 @@ public class InputManagerService extends IInputManager.Stub if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null."); } - + nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false); } - + /** * Unregisters an input channel. * @param inputChannel The input channel to unregister. @@ -456,7 +462,7 @@ public class InputManagerService extends IInputManager.Stub if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null."); } - + nativeUnregisterInputChannel(mPtr, inputChannel); } @@ -505,6 +511,10 @@ public class InputManagerService extends IInputManager.Stub @Override // Binder call public boolean injectInputEvent(InputEvent event, int mode) { + return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode); + } + + private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) { if (event == null) { throw new IllegalArgumentException("event must not be null"); } @@ -519,7 +529,7 @@ public class InputManagerService extends IInputManager.Stub final long ident = Binder.clearCallingIdentity(); final int result; try { - result = nativeInjectInputEvent(mPtr, event, pid, uid, mode, + result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode, INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); } finally { Binder.restoreCallingIdentity(ident); @@ -894,35 +904,62 @@ public class InputManagerService extends IInputManager.Stub } } - @Override // Binder call - public String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor) { - if (inputDeviceDescriptor == null) { - throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); + /** + * Builds a layout descriptor for the vendor/product. This returns the + * descriptor for ids that aren't useful (such as the default 0, 0). + */ + private String getLayoutDescriptor(InputDeviceIdentifier identifier) { + if (identifier == null || identifier.getDescriptor() == null) { + throw new IllegalArgumentException("identifier and descriptor must not be null"); + } + + if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) { + return identifier.getDescriptor(); } + StringBuilder bob = new StringBuilder(); + bob.append("vendor:").append(identifier.getVendorId()); + bob.append(",product:").append(identifier.getProductId()); + return bob.toString(); + } + @Override // Binder call + public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) { + + String key = getLayoutDescriptor(identifier); synchronized (mDataStore) { - return mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor); + String layout = null; + // try loading it using the layout descriptor if we have it + layout = mDataStore.getCurrentKeyboardLayout(key); + if (layout == null && !key.equals(identifier.getDescriptor())) { + // if it doesn't exist fall back to the device descriptor + layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); + } + if (DEBUG) { + Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got " + + layout); + } + return layout; } } @Override // Binder call - public void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor, + public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor) { if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, "setCurrentKeyboardLayoutForInputDevice()")) { throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); } - if (inputDeviceDescriptor == null) { - throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); - } if (keyboardLayoutDescriptor == null) { throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); } + String key = getLayoutDescriptor(identifier); synchronized (mDataStore) { try { - if (mDataStore.setCurrentKeyboardLayout( - inputDeviceDescriptor, keyboardLayoutDescriptor)) { + if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) { + if (DEBUG) { + Slog.d(TAG, "Saved keyboard layout using " + key); + } mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); } } finally { @@ -932,36 +969,39 @@ public class InputManagerService extends IInputManager.Stub } @Override // Binder call - public String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor) { - if (inputDeviceDescriptor == null) { - throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); - } - + public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { + String key = getLayoutDescriptor(identifier); synchronized (mDataStore) { - return mDataStore.getKeyboardLayouts(inputDeviceDescriptor); + String[] layouts = mDataStore.getKeyboardLayouts(key); + if ((layouts == null || layouts.length == 0) + && !key.equals(identifier.getDescriptor())) { + layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor()); + } + return layouts; } } @Override // Binder call - public void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor, + public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor) { if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, "addKeyboardLayoutForInputDevice()")) { throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); } - if (inputDeviceDescriptor == null) { - throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); - } if (keyboardLayoutDescriptor == null) { throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); } + String key = getLayoutDescriptor(identifier); synchronized (mDataStore) { try { - String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor); - if (mDataStore.addKeyboardLayout(inputDeviceDescriptor, keyboardLayoutDescriptor) + String oldLayout = mDataStore.getCurrentKeyboardLayout(key); + if (oldLayout == null && !key.equals(identifier.getDescriptor())) { + oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); + } + if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor) && !Objects.equal(oldLayout, - mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) { + mDataStore.getCurrentKeyboardLayout(key))) { mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); } } finally { @@ -971,26 +1011,31 @@ public class InputManagerService extends IInputManager.Stub } @Override // Binder call - public void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor, + public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor) { if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, "removeKeyboardLayoutForInputDevice()")) { throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); } - if (inputDeviceDescriptor == null) { - throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); - } if (keyboardLayoutDescriptor == null) { throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); } + String key = getLayoutDescriptor(identifier); synchronized (mDataStore) { try { - String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor); - if (mDataStore.removeKeyboardLayout(inputDeviceDescriptor, - keyboardLayoutDescriptor) - && !Objects.equal(oldLayout, - mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) { + String oldLayout = mDataStore.getCurrentKeyboardLayout(key); + if (oldLayout == null && !key.equals(identifier.getDescriptor())) { + oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); + } + boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor); + if (!key.equals(identifier.getDescriptor())) { + // We need to remove from both places to ensure it is gone + removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(), + keyboardLayoutDescriptor); + } + if (removed && !Objects.equal(oldLayout, + mDataStore.getCurrentKeyboardLayout(key))) { mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); } } finally { @@ -1007,14 +1052,15 @@ public class InputManagerService extends IInputManager.Stub private void handleSwitchKeyboardLayout(int deviceId, int direction) { final InputDevice device = getInputDevice(deviceId); if (device != null) { - final String inputDeviceDescriptor = device.getDescriptor(); final boolean changed; final String keyboardLayoutDescriptor; + + String key = getLayoutDescriptor(device.getIdentifier()); synchronized (mDataStore) { try { - changed = mDataStore.switchKeyboardLayout(inputDeviceDescriptor, direction); + changed = mDataStore.switchKeyboardLayout(key, direction); keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout( - inputDeviceDescriptor); + key); } finally { mDataStore.saveIfNeeded(); } @@ -1042,11 +1088,11 @@ public class InputManagerService extends IInputManager.Stub public void setInputWindows(InputWindowHandle[] windowHandles) { nativeSetInputWindows(mPtr, windowHandles); } - + public void setFocusedApplication(InputApplicationHandle application) { nativeSetFocusedApplication(mPtr, application); } - + public void setInputDispatchMode(boolean enabled, boolean frozen) { nativeSetInputDispatchMode(mPtr, enabled, frozen); } @@ -1315,14 +1361,14 @@ public class InputManagerService extends IInputManager.Stub } // Native callback. - private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) { - return mWindowManagerCallbacks.interceptKeyBeforeQueueing( - event, policyFlags, isScreenOn); + private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { + return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags); } // Native callback. - private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { - return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); + private int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) { + return mWindowManagerCallbacks.interceptWakeMotionBeforeQueueing( + whenNanos, policyFlags); } // Native callback. @@ -1426,13 +1472,12 @@ public class InputManagerService extends IInputManager.Stub } // Native callback. - private String[] getKeyboardLayoutOverlay(String inputDeviceDescriptor) { + private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) { if (!mSystemReady) { return null; } - String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice( - inputDeviceDescriptor); + String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier); if (keyboardLayoutDescriptor == null) { return null; } @@ -1481,9 +1526,9 @@ public class InputManagerService extends IInputManager.Stub public long notifyANR(InputApplicationHandle inputApplicationHandle, InputWindowHandle inputWindowHandle, String reason); - public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn); + public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags); - public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags); + public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags); public long interceptKeyBeforeDispatching(InputWindowHandle focus, KeyEvent event, int policyFlags); @@ -1549,7 +1594,7 @@ public class InputManagerService extends IInputManager.Stub synchronized (mInputFilterLock) { if (!mDisconnected) { - nativeInjectInputEvent(mPtr, event, 0, 0, + nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, policyFlags | WindowManagerPolicy.FLAG_FILTERED); } @@ -1639,4 +1684,22 @@ public class InputManagerService extends IInputManager.Stub onVibratorTokenDied(this); } } + + private final class LocalService extends InputManagerInternal { + @Override + public void setDisplayViewports( + DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) { + setDisplayViewportsInternal(defaultViewport, externalTouchViewport); + } + + @Override + public boolean injectInputEvent(InputEvent event, int displayId, int mode) { + return injectInputEventInternal(event, displayId, mode); + } + + @Override + public void setInteractive(boolean interactive) { + nativeSetInteractive(mPtr, interactive); + } + } } diff --git a/services/java/com/android/server/input/InputWindowHandle.java b/services/core/java/com/android/server/input/InputWindowHandle.java index 9eb9a33..9a70f38 100644 --- a/services/java/com/android/server/input/InputWindowHandle.java +++ b/services/core/java/com/android/server/input/InputWindowHandle.java @@ -28,7 +28,7 @@ public final class InputWindowHandle { // Pointer to the native input window handle. // This field is lazily initialized via JNI. @SuppressWarnings("unused") - private int ptr; + private long ptr; // The input application handle. public final InputApplicationHandle inputApplicationHandle; diff --git a/services/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java index 71de776..71de776 100644 --- a/services/java/com/android/server/input/PersistentDataStore.java +++ b/services/core/java/com/android/server/input/PersistentDataStore.java diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/Light.java new file mode 100644 index 0000000..b496b4c --- /dev/null +++ b/services/core/java/com/android/server/lights/Light.java @@ -0,0 +1,41 @@ +/* + * 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.server.lights; + +public abstract class Light { + public static final int LIGHT_FLASH_NONE = 0; + public static final int LIGHT_FLASH_TIMED = 1; + public static final int LIGHT_FLASH_HARDWARE = 2; + + /** + * Light brightness is managed by a user setting. + */ + public static final int BRIGHTNESS_MODE_USER = 0; + + /** + * Light brightness is managed by a light sensor. + */ + public static final int BRIGHTNESS_MODE_SENSOR = 1; + + public abstract void setBrightness(int brightness); + public abstract void setBrightness(int brightness, int brightnessMode); + public abstract void setColor(int color); + public abstract void setFlashing(int color, int mode, int onMS, int offMS); + public abstract void pulse(); + public abstract void pulse(int color, int onMS); + public abstract void turnOff(); +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/lights/LightsManager.java b/services/core/java/com/android/server/lights/LightsManager.java new file mode 100644 index 0000000..2f20509 --- /dev/null +++ b/services/core/java/com/android/server/lights/LightsManager.java @@ -0,0 +1,31 @@ +/* + * 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.server.lights; + +public abstract class LightsManager { + public static final int LIGHT_ID_BACKLIGHT = 0; + public static final int LIGHT_ID_KEYBOARD = 1; + public static final int LIGHT_ID_BUTTONS = 2; + public static final int LIGHT_ID_BATTERY = 3; + public static final int LIGHT_ID_NOTIFICATIONS = 4; + public static final int LIGHT_ID_ATTENTION = 5; + public static final int LIGHT_ID_BLUETOOTH = 6; + public static final int LIGHT_ID_WIFI = 7; + public static final int LIGHT_ID_COUNT = 8; + + public abstract Light getLight(int id); +} diff --git a/services/java/com/android/server/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java index 89bfcac..62c0ec9 100644 --- a/services/java/com/android/server/LightsService.java +++ b/services/core/java/com/android/server/lights/LightsService.java @@ -14,59 +14,38 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.lights; + +import com.android.server.SystemService; import android.content.Context; import android.content.pm.PackageManager; import android.os.Handler; import android.os.IHardwareService; -import android.os.ServiceManager; import android.os.Message; import android.util.Slog; import java.io.FileInputStream; import java.io.FileOutputStream; -public class LightsService { - private static final String TAG = "LightsService"; - private static final boolean DEBUG = false; - - public static final int LIGHT_ID_BACKLIGHT = 0; - public static final int LIGHT_ID_KEYBOARD = 1; - public static final int LIGHT_ID_BUTTONS = 2; - public static final int LIGHT_ID_BATTERY = 3; - public static final int LIGHT_ID_NOTIFICATIONS = 4; - public static final int LIGHT_ID_ATTENTION = 5; - public static final int LIGHT_ID_BLUETOOTH = 6; - public static final int LIGHT_ID_WIFI = 7; - public static final int LIGHT_ID_COUNT = 8; - - public static final int LIGHT_FLASH_NONE = 0; - public static final int LIGHT_FLASH_TIMED = 1; - public static final int LIGHT_FLASH_HARDWARE = 2; - - /** - * Light brightness is managed by a user setting. - */ - public static final int BRIGHTNESS_MODE_USER = 0; - - /** - * Light brightness is managed by a light sensor. - */ - public static final int BRIGHTNESS_MODE_SENSOR = 1; +public class LightsService extends SystemService { + static final String TAG = "LightsService"; + static final boolean DEBUG = false; - private final Light mLights[] = new Light[LIGHT_ID_COUNT]; + final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT]; - public final class Light { + private final class LightImpl extends Light { - private Light(int id) { + private LightImpl(int id) { mId = id; } + @Override public void setBrightness(int brightness) { setBrightness(brightness, BRIGHTNESS_MODE_USER); } + @Override public void setBrightness(int brightness, int brightnessMode) { synchronized (this) { int color = brightness & 0x000000ff; @@ -75,23 +54,26 @@ public class LightsService { } } + @Override public void setColor(int color) { synchronized (this) { setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0); } } + @Override public void setFlashing(int color, int mode, int onMS, int offMS) { synchronized (this) { setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER); } } - + @Override public void pulse() { pulse(0x00ffffff, 7); } + @Override public void pulse(int color, int onMS) { synchronized (this) { if (mColor == 0 && !mFlashing) { @@ -101,6 +83,7 @@ public class LightsService { } } + @Override public void turnOff() { synchronized (this) { setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0); @@ -153,9 +136,10 @@ public class LightsService { } public void setFlashlightEnabled(boolean on) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT) + final Context context = getContext(); + if (context.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT) != PackageManager.PERMISSION_GRANTED && - mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) + context.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission"); } @@ -172,42 +156,52 @@ public class LightsService { } }; - LightsService(Context context) { + public LightsService(Context context) { + super(context); mNativePointer = init_native(); - mContext = context; - ServiceManager.addService("hardware", mLegacyFlashlightHack); - - for (int i = 0; i < LIGHT_ID_COUNT; i++) { - mLights[i] = new Light(i); + for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) { + mLights[i] = new LightImpl(i); } } + @Override + public void onStart() { + publishBinderService("hardware", mLegacyFlashlightHack); + publishLocalService(LightsManager.class, mService); + } + + private final LightsManager mService = new LightsManager() { + @Override + public com.android.server.lights.Light getLight(int id) { + if (id < LIGHT_ID_COUNT) { + return mLights[id]; + } else { + return null; + } + } + }; + + @Override protected void finalize() throws Throwable { finalize_native(mNativePointer); super.finalize(); } - public Light getLight(int id) { - return mLights[id]; - } - private Handler mH = new Handler() { @Override public void handleMessage(Message msg) { - Light light = (Light)msg.obj; + LightImpl light = (LightImpl)msg.obj; light.stopFlashing(); } }; - private static native int init_native(); - private static native void finalize_native(int ptr); + private static native long init_native(); + private static native void finalize_native(long ptr); - private static native void setLight_native(int ptr, int light, int color, int mode, + static native void setLight_native(long ptr, int light, int color, int mode, int onMS, int offMS, int brightnessMode); - private final Context mContext; - - private int mNativePointer; + private long mNativePointer; } diff --git a/services/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/core/java/com/android/server/location/ComprehensiveCountryDetector.java index 354858b..354858b 100644 --- a/services/java/com/android/server/location/ComprehensiveCountryDetector.java +++ b/services/core/java/com/android/server/location/ComprehensiveCountryDetector.java diff --git a/services/java/com/android/server/location/CountryDetectorBase.java b/services/core/java/com/android/server/location/CountryDetectorBase.java index 8326ef9..8326ef9 100644 --- a/services/java/com/android/server/location/CountryDetectorBase.java +++ b/services/core/java/com/android/server/location/CountryDetectorBase.java diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java index fab84a8..fab84a8 100644 --- a/services/java/com/android/server/location/FlpHardwareProvider.java +++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java diff --git a/services/java/com/android/server/location/FusedLocationHardwareSecure.java b/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java index 389bd24..389bd24 100644 --- a/services/java/com/android/server/location/FusedLocationHardwareSecure.java +++ b/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java diff --git a/services/java/com/android/server/location/FusedProxy.java b/services/core/java/com/android/server/location/FusedProxy.java index f7fac77..f7fac77 100644 --- a/services/java/com/android/server/location/FusedProxy.java +++ b/services/core/java/com/android/server/location/FusedProxy.java diff --git a/services/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java index 5d4a770..5d4a770 100644 --- a/services/java/com/android/server/location/GeocoderProxy.java +++ b/services/core/java/com/android/server/location/GeocoderProxy.java diff --git a/services/java/com/android/server/location/GeofenceManager.java b/services/core/java/com/android/server/location/GeofenceManager.java index e24bf76..e24bf76 100644 --- a/services/java/com/android/server/location/GeofenceManager.java +++ b/services/core/java/com/android/server/location/GeofenceManager.java diff --git a/services/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java index bbc1f47..bbc1f47 100644 --- a/services/java/com/android/server/location/GeofenceProxy.java +++ b/services/core/java/com/android/server/location/GeofenceProxy.java diff --git a/services/java/com/android/server/location/GeofenceState.java b/services/core/java/com/android/server/location/GeofenceState.java index 3ebe20a..3ebe20a 100644 --- a/services/java/com/android/server/location/GeofenceState.java +++ b/services/core/java/com/android/server/location/GeofenceState.java diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java index 9c76c19..9c76c19 100644 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/core/java/com/android/server/location/GpsLocationProvider.java diff --git a/services/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java index e420073..e420073 100644 --- a/services/java/com/android/server/location/GpsXtraDownloader.java +++ b/services/core/java/com/android/server/location/GpsXtraDownloader.java diff --git a/services/java/com/android/server/location/LocationBasedCountryDetector.java b/services/core/java/com/android/server/location/LocationBasedCountryDetector.java index 03db621..03db621 100644 --- a/services/java/com/android/server/location/LocationBasedCountryDetector.java +++ b/services/core/java/com/android/server/location/LocationBasedCountryDetector.java diff --git a/services/java/com/android/server/location/LocationBlacklist.java b/services/core/java/com/android/server/location/LocationBlacklist.java index 6f22689..6f22689 100644 --- a/services/java/com/android/server/location/LocationBlacklist.java +++ b/services/core/java/com/android/server/location/LocationBlacklist.java diff --git a/services/java/com/android/server/location/LocationFudger.java b/services/core/java/com/android/server/location/LocationFudger.java index 2a68743..2a68743 100644 --- a/services/java/com/android/server/location/LocationFudger.java +++ b/services/core/java/com/android/server/location/LocationFudger.java diff --git a/services/java/com/android/server/location/LocationProviderInterface.java b/services/core/java/com/android/server/location/LocationProviderInterface.java index 6f09232..6f09232 100644 --- a/services/java/com/android/server/location/LocationProviderInterface.java +++ b/services/core/java/com/android/server/location/LocationProviderInterface.java diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index 14db862..14db862 100644 --- a/services/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java diff --git a/services/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java index 36c43ff..36c43ff 100644 --- a/services/java/com/android/server/location/MockProvider.java +++ b/services/core/java/com/android/server/location/MockProvider.java diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java index 71bae07..71bae07 100644 --- a/services/java/com/android/server/location/PassiveProvider.java +++ b/services/core/java/com/android/server/location/PassiveProvider.java diff --git a/services/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index a31695b..f91ea8c 100644 --- a/services/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -16,7 +16,6 @@ package com.android.server.media; -import com.android.internal.util.Objects; import com.android.server.Watchdog; import android.Manifest; @@ -52,6 +51,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; /** * Provides a mechanism for discovering media routes and manages media playback @@ -384,7 +384,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); if (clientRecord != null) { final String oldRouteId = clientRecord.mSelectedRouteId; - if (!Objects.equal(routeId, oldRouteId)) { + if (!Objects.equals(routeId, oldRouteId)) { if (DEBUG) { Slog.d(TAG, clientRecord + ": Set selected route, routeId=" + routeId + ", oldRouteId=" + oldRouteId @@ -1257,12 +1257,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub mDescriptor = descriptor; if (descriptor != null) { final String name = computeName(descriptor); - if (!Objects.equal(mMutableInfo.name, name)) { + if (!Objects.equals(mMutableInfo.name, name)) { mMutableInfo.name = name; changed = true; } final String description = computeDescription(descriptor); - if (!Objects.equal(mMutableInfo.description, description)) { + if (!Objects.equals(mMutableInfo.description, description)) { mMutableInfo.description = description; changed = true; } diff --git a/services/java/com/android/server/media/RemoteDisplayProviderProxy.java b/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java index b248ee0..a5fe9f2 100644 --- a/services/java/com/android/server/media/RemoteDisplayProviderProxy.java +++ b/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java @@ -16,8 +16,6 @@ package com.android.server.media; -import com.android.internal.util.Objects; - import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -35,6 +33,7 @@ import android.util.Slog; import java.io.PrintWriter; import java.lang.ref.WeakReference; +import java.util.Objects; /** * Maintains a connection to a particular remote display provider service. @@ -101,7 +100,7 @@ final class RemoteDisplayProviderProxy implements ServiceConnection { } public void setSelectedDisplay(String id) { - if (!Objects.equal(mSelectedDisplayId, id)) { + if (!Objects.equals(mSelectedDisplayId, id)) { if (mConnectionReady && mSelectedDisplayId != null) { mActiveConnection.disconnect(mSelectedDisplayId); } @@ -293,7 +292,7 @@ final class RemoteDisplayProviderProxy implements ServiceConnection { } private void setDisplayState(RemoteDisplayState state) { - if (!Objects.equal(mDisplayState, state)) { + if (!Objects.equals(mDisplayState, state)) { mDisplayState = state; if (!mScheduledDisplayStateChangedCallback) { mScheduledDisplayStateChangedCallback = true; diff --git a/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java index 6a5f563..6a5f563 100644 --- a/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java +++ b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java diff --git a/services/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java index a2e9d67..a2e9d67 100644 --- a/services/java/com/android/server/net/LockdownVpnTracker.java +++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java diff --git a/services/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 397f9f4..397f9f4 100644 --- a/services/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index d568b11..855ae23 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -133,7 +133,6 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Objects; import com.google.android.collect.Lists; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -155,6 +154,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import libcore.io.IoUtils; @@ -688,7 +688,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // mobile templates are relevant when SIM is ready and // subscriberId matches. if (tele.getSimState() == SIM_STATE_READY) { - return Objects.equal(tele.getSubscriberId(), template.getSubscriberId()); + return Objects.equals(tele.getSubscriberId(), template.getSubscriberId()); } else { return false; } @@ -946,7 +946,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // TODO: offer more granular control over radio states once // 4965893 is available. if (tele.getSimState() == SIM_STATE_READY - && Objects.equal(tele.getSubscriberId(), template.getSubscriberId())) { + && Objects.equals(tele.getSubscriberId(), template.getSubscriberId())) { setPolicyDataEnable(TYPE_MOBILE, enabled); setPolicyDataEnable(TYPE_WIMAX, enabled); } @@ -1730,7 +1730,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private void updateScreenOn() { synchronized (mRulesLock) { try { - mScreenOn = mPowerManager.isScreenOn(); + mScreenOn = mPowerManager.isInteractive(); } catch (RemoteException e) { // ignored; service lives in system_server } diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 3169035..475482f 100644 --- a/services/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -34,7 +34,6 @@ import android.util.AtomicFile; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Objects; import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -50,6 +49,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import libcore.io.IoUtils; @@ -508,7 +508,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { this.uid = uid; this.set = set; this.tag = tag; - hashCode = Objects.hashCode(ident, uid, set, tag); + hashCode = Objects.hash(ident, uid, set, tag); } @Override @@ -521,7 +521,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { if (obj instanceof Key) { final Key key = (Key) obj; return uid == key.uid && set == key.set && tag == key.tag - && Objects.equal(ident, key.ident); + && Objects.equals(ident, key.ident); } return false; } diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index cea084b..cea084b 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 5d6adc2..5d6adc2 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java new file mode 100644 index 0000000..df2aaca --- /dev/null +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -0,0 +1,27 @@ +/** + * 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.server.notification; + +public interface NotificationDelegate { + void onSetDisabled(int status); + void onClearAll(); + void onNotificationClick(String pkg, String tag, int id); + void onNotificationClear(String pkg, String tag, int id); + void onNotificationError(String pkg, String tag, int id, + int uid, int initialPid, String message); + void onPanelRevealed(); +} diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java new file mode 100644 index 0000000..b695b68 --- /dev/null +++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.notification; + +import android.app.Notification; + +public interface NotificationManagerInternal { + void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid, + String tag, int id, Notification notification, int[] idReceived, int userId); +} diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index dedc9bd..38b8dc6 100644 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.notification; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_TAG; @@ -47,7 +47,6 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; import android.media.AudioManager; -import android.media.IAudioService; import android.media.IRingtonePlayer; import android.net.Uri; import android.os.Binder; @@ -56,9 +55,7 @@ import android.os.IBinder; import android.os.Message; import android.os.Process; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; -import android.os.UserManager; import android.os.Vibrator; import android.provider.Settings; import android.service.notification.INotificationListener; @@ -66,6 +63,7 @@ import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.AtomicFile; import android.util.EventLog; import android.util.Log; @@ -78,6 +76,12 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.notification.NotificationScorer; +import com.android.server.EventLogTags; +import com.android.server.statusbar.StatusBarManagerInternal; +import com.android.server.SystemService; +import com.android.server.lights.Light; +import com.android.server.lights.LightsManager; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -99,66 +103,61 @@ import java.util.Set; import libcore.io.IoUtils; - /** {@hide} */ -public class NotificationManagerService extends INotificationManager.Stub -{ - private static final String TAG = "NotificationService"; - private static final boolean DBG = false; +public class NotificationManagerService extends SystemService { + static final String TAG = "NotificationService"; + static final boolean DBG = false; - private static final int MAX_PACKAGE_NOTIFICATIONS = 50; + static final int MAX_PACKAGE_NOTIFICATIONS = 50; // message codes - private static final int MESSAGE_TIMEOUT = 2; + static final int MESSAGE_TIMEOUT = 2; - private static final int LONG_DELAY = 3500; // 3.5 seconds - private static final int SHORT_DELAY = 2000; // 2 seconds + static final int LONG_DELAY = 3500; // 3.5 seconds + static final int SHORT_DELAY = 2000; // 2 seconds - private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; - private static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps + static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; + static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps - private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; - private static final boolean SCORE_ONGOING_HIGHER = false; + static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; + static final boolean SCORE_ONGOING_HIGHER = false; - private static final int JUNK_SCORE = -1000; - private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; - private static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER; + static final int JUNK_SCORE = -1000; + static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; + static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER; // Notifications with scores below this will not interrupt the user, either via LED or // sound or vibration - private static final int SCORE_INTERRUPTION_THRESHOLD = + static final int SCORE_INTERRUPTION_THRESHOLD = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER; - private static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true; - private static final boolean ENABLE_BLOCKED_TOASTS = true; + static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true; + static final boolean ENABLE_BLOCKED_TOASTS = true; - private static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":"; + static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":"; - final Context mContext; - final IActivityManager mAm; - final UserManager mUserManager; - final IBinder mForegroundToken = new Binder(); + private IActivityManager mAm; + AudioManager mAudioManager; + StatusBarManagerInternal mStatusBar; + Vibrator mVibrator; + final IBinder mForegroundToken = new Binder(); private WorkerHandler mHandler; - private StatusBarManagerService mStatusBar; - private LightsService.Light mNotificationLight; - private LightsService.Light mAttentionLight; + private Light mNotificationLight; + Light mAttentionLight; private int mDefaultNotificationColor; private int mDefaultNotificationLedOn; - private int mDefaultNotificationLedOff; + private int mDefaultNotificationLedOff; private long[] mDefaultVibrationPattern; - private long[] mFallbackVibrationPattern; - - private boolean mSystemReady; - private int mDisabledNotifications; - private NotificationRecord mSoundNotification; - private NotificationRecord mVibrateNotification; + private long[] mFallbackVibrationPattern; + boolean mSystemReady; - private IAudioService mAudioService; - private Vibrator mVibrator; + int mDisabledNotifications; + NotificationRecord mSoundNotification; + NotificationRecord mVibrateNotification; // for enabling and disabling notification pulse behavior private boolean mScreenOn = true; @@ -166,15 +165,17 @@ public class NotificationManagerService extends INotificationManager.Stub private boolean mNotificationPulseEnabled; // used as a mutex for access to all active notifications & listeners - private final ArrayList<NotificationRecord> mNotificationList = + final ArrayList<NotificationRecord> mNotificationList = new ArrayList<NotificationRecord>(); + final ArrayMap<String, NotificationRecord> mNotificationsByKey = + new ArrayMap<String, NotificationRecord>(); - private ArrayList<ToastRecord> mToastQueue; + final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); - private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>(); - private NotificationRecord mLedNotification; + ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>(); + NotificationRecord mLedNotification; - private final AppOpsManager mAppOps; + private AppOpsManager mAppOps; // contains connections to all connected listeners, including app services // and system listeners @@ -202,9 +203,9 @@ public class NotificationManagerService extends INotificationManager.Stub private static final String TAG_PACKAGE = "package"; private static final String ATTR_NAME = "name"; - private final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>(); + final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>(); - private class NotificationListenerInfo implements DeathRecipient { + private class NotificationListenerInfo implements IBinder.DeathRecipient { INotificationListener listener; ComponentName component; int userid; @@ -401,12 +402,14 @@ public class NotificationManagerService extends INotificationManager.Stub tag = parser.getName(); if (type == START_TAG) { if (TAG_BODY.equals(tag)) { - version = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION)); + version = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VERSION)); } else if (TAG_BLOCKED_PKGS.equals(tag)) { while ((type = parser.next()) != END_DOCUMENT) { tag = parser.getName(); if (TAG_PACKAGE.equals(tag)) { - mBlockedPackages.add(parser.getAttributeValue(null, ATTR_NAME)); + mBlockedPackages.add( + parser.getAttributeValue(null, ATTR_NAME)); } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) { break; } @@ -429,15 +432,6 @@ public class NotificationManagerService extends INotificationManager.Stub } } - /** - * Use this when you just want to know if notifications are OK for this package. - */ - public boolean areNotificationsEnabledForPackage(String pkg, int uid) { - checkCallerIsSystem(); - return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) - == AppOpsManager.MODE_ALLOWED); - } - /** Use this when you actually want to post a notification or toast. * * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*(). @@ -451,21 +445,6 @@ public class NotificationManagerService extends INotificationManager.Stub return true; } - public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { - checkCallerIsSystem(); - - Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg); - - mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, - enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); - - // Now, cancel any outstanding notifications that are part of a just-disabled app - if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { - cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid)); - } - } - - private static String idDebugString(Context baseContext, String packageName, int id) { Context c = null; @@ -491,57 +470,6 @@ public class NotificationManagerService extends INotificationManager.Stub } } - /** - * System-only API for getting a list of current (i.e. not cleared) notifications. - * - * Requires ACCESS_NOTIFICATIONS which is signature|system. - */ - @Override - public StatusBarNotification[] getActiveNotifications(String callingPkg) { - // enforce() will ensure the calling uid has the correct permission - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS, - "NotificationManagerService.getActiveNotifications"); - - StatusBarNotification[] tmp = null; - int uid = Binder.getCallingUid(); - - // noteOp will check to make sure the callingPkg matches the uid - if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) - == AppOpsManager.MODE_ALLOWED) { - synchronized (mNotificationList) { - tmp = new StatusBarNotification[mNotificationList.size()]; - final int N = mNotificationList.size(); - for (int i=0; i<N; i++) { - tmp[i] = mNotificationList.get(i).sbn; - } - } - } - return tmp; - } - - /** - * System-only API for getting a list of recent (cleared, no longer shown) notifications. - * - * Requires ACCESS_NOTIFICATIONS which is signature|system. - */ - @Override - public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { - // enforce() will ensure the calling uid has the correct permission - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS, - "NotificationManagerService.getHistoricalNotifications"); - - StatusBarNotification[] tmp = null; - int uid = Binder.getCallingUid(); - - // noteOp will check to make sure the callingPkg matches the uid - if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) - == AppOpsManager.MODE_ALLOWED) { - synchronized (mArchive) { - tmp = mArchive.getArray(count); - } - } - return tmp; - } /** * Remove notification access for any services that no longer exist. @@ -549,12 +477,12 @@ public class NotificationManagerService extends INotificationManager.Stub void disableNonexistentListeners() { int currentUser = ActivityManager.getCurrentUser(); String flatIn = Settings.Secure.getStringForUser( - mContext.getContentResolver(), + getContext().getContentResolver(), Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, currentUser); if (!TextUtils.isEmpty(flatIn)) { if (DBG) Slog.v(TAG, "flat before: " + flatIn); - PackageManager pm = mContext.getPackageManager(); + PackageManager pm = getContext().getPackageManager(); List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( new Intent(NotificationListenerService.SERVICE_INTERFACE), PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, @@ -590,7 +518,7 @@ public class NotificationManagerService extends INotificationManager.Stub } if (DBG) Slog.v(TAG, "flat after: " + flatOut); if (!flatIn.equals(flatOut)) { - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(getContext().getContentResolver(), Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, flatOut, currentUser); } @@ -604,7 +532,7 @@ public class NotificationManagerService extends INotificationManager.Stub void rebindListenerServices() { final int currentUser = ActivityManager.getCurrentUser(); String flat = Settings.Secure.getStringForUser( - mContext.getContentResolver(), + getContext().getContentResolver(), Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, currentUser); @@ -653,28 +581,6 @@ public class NotificationManagerService extends INotificationManager.Stub } } - /** - * Register a listener binder directly with the notification manager. - * - * Only works with system callers. Apps should extend - * {@link android.service.notification.NotificationListenerService}. - */ - @Override - public void registerListener(final INotificationListener listener, - final ComponentName component, final int userid) { - checkCallerIsSystem(); - - synchronized (mNotificationList) { - try { - NotificationListenerInfo info - = new NotificationListenerInfo(listener, component, userid, true); - listener.asBinder().linkToDeath(info, 0); - mListeners.add(info); - } catch (RemoteException e) { - // already dead - } - } - } /** * Version of registerListener that takes the name of a @@ -704,7 +610,7 @@ public class NotificationManagerService extends INotificationManager.Stub if (DBG) Slog.v(TAG, " disconnecting old listener: " + info.listener); mListeners.remove(i); if (info.connection != null) { - mContext.unbindService(info.connection); + getContext().unbindService(info.connection); } } } @@ -714,28 +620,42 @@ public class NotificationManagerService extends INotificationManager.Stub intent.putExtra(Intent.EXTRA_CLIENT_LABEL, R.string.notification_listener_binding_label); - intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( - mContext, 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0)); + + final PendingIntent pendingIntent = PendingIntent.getActivity( + getContext(), 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0); + intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent); try { if (DBG) Slog.v(TAG, "binding: " + intent); - if (!mContext.bindServiceAsUser(intent, + if (!getContext().bindServiceAsUser(intent, new ServiceConnection() { INotificationListener mListener; + @Override public void onServiceConnected(ComponentName name, IBinder service) { + boolean added = false; synchronized (mNotificationList) { mServicesBinding.remove(servicesBindingTag); try { mListener = INotificationListener.Stub.asInterface(service); - NotificationListenerInfo info = new NotificationListenerInfo( + NotificationListenerInfo info + = new NotificationListenerInfo( mListener, name, userid, this); service.linkToDeath(info, 0); - mListeners.add(info); + added = mListeners.add(info); } catch (RemoteException e) { // already dead } } + if (added) { + final String[] keys = + getActiveNotificationKeysFromListener(mListener); + try { + mListener.onListenerConnected(keys); + } catch (RemoteException e) { + // we tried + } + } } @Override @@ -757,38 +677,6 @@ public class NotificationManagerService extends INotificationManager.Stub } } - /** - * Removes a listener from the list and unbinds from its service. - */ - public void unregisterListener(final INotificationListener listener, final int userid) { - if (listener == null) return; - - NotificationListenerInfo info = removeListenerImpl(listener, userid); - if (info != null && info.connection != null) { - mContext.unbindService(info.connection); - } - } - - /** - * Removes a listener from the list but does not unbind from the listener's service. - * - * @return the removed listener. - */ - NotificationListenerInfo removeListenerImpl( - final INotificationListener listener, final int userid) { - NotificationListenerInfo listenerInfo = null; - synchronized (mNotificationList) { - final int N = mListeners.size(); - for (int i=N-1; i>=0; i--) { - final NotificationListenerInfo info = mListeners.get(i); - if (info.listener.asBinder() == listener.asBinder() - && info.userid == userid) { - listenerInfo = mListeners.remove(i); - } - } - } - return listenerInfo; - } /** * Remove a listener service for the given user by ComponentName @@ -805,7 +693,7 @@ public class NotificationManagerService extends INotificationManager.Stub mListeners.remove(i); if (info.connection != null) { try { - mContext.unbindService(info.connection); + getContext().unbindService(info.connection); } catch (IllegalArgumentException ex) { // something happened to the service: we think we have a connection // but it's bogus. @@ -820,7 +708,7 @@ public class NotificationManagerService extends INotificationManager.Stub /** * asynchronously notify all listeners about a new notification */ - private void notifyPostedLocked(NotificationRecord n) { + void notifyPostedLocked(NotificationRecord n) { // make a copy in case changes are made to the underlying Notification object final StatusBarNotification sbn = n.sbn.clone(); for (final NotificationListenerInfo info : mListeners) { @@ -835,7 +723,7 @@ public class NotificationManagerService extends INotificationManager.Stub /** * asynchronously notify all listeners about a removed notification */ - private void notifyRemovedLocked(NotificationRecord n) { + void notifyRemovedLocked(NotificationRecord n) { // make a copy in case changes are made to the underlying Notification object // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the notification final StatusBarNotification sbn_light = n.sbn.cloneLight(); @@ -851,7 +739,14 @@ public class NotificationManagerService extends INotificationManager.Stub // -- APIs to support listeners clicking/clearing notifications -- - private NotificationListenerInfo checkListenerToken(INotificationListener listener) { + private void checkNullListener(INotificationListener listener) { + if (listener == null) { + throw new IllegalArgumentException("Listener must not be null"); + } + } + + private NotificationListenerInfo checkListenerTokenLocked(INotificationListener listener) { + checkNullListener(listener); final IBinder token = listener.asBinder(); final int N = mListeners.size(); for (int i=0; i<N; i++) { @@ -861,66 +756,7 @@ public class NotificationManagerService extends INotificationManager.Stub throw new SecurityException("Disallowed call from unknown listener: " + listener); } - /** - * Allow an INotificationListener to simulate a "clear all" operation. - * - * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} - * - * @param token The binder for the listener, to check that the caller is allowed - */ - public void cancelAllNotificationsFromListener(INotificationListener token) { - NotificationListenerInfo info = checkListenerToken(token); - long identity = Binder.clearCallingIdentity(); - try { - cancelAll(info.userid); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - /** - * Allow an INotificationListener to simulate clearing (dismissing) a single notification. - * - * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} - * - * @param token The binder for the listener, to check that the caller is allowed - */ - public void cancelNotificationFromListener(INotificationListener token, String pkg, String tag, int id) { - NotificationListenerInfo info = checkListenerToken(token); - long identity = Binder.clearCallingIdentity(); - try { - cancelNotification(pkg, tag, id, 0, - Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, - true, - info.userid); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Allow an INotificationListener to request the list of outstanding notifications seen by - * the current user. Useful when starting up, after which point the listener callbacks should - * be used. - * - * @param token The binder for the listener, to check that the caller is allowed - */ - public StatusBarNotification[] getActiveNotificationsFromListener(INotificationListener token) { - NotificationListenerInfo info = checkListenerToken(token); - - StatusBarNotification[] result = new StatusBarNotification[0]; - ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>(); - synchronized (mNotificationList) { - final int N = mNotificationList.size(); - for (int i=0; i<N; i++) { - StatusBarNotification sbn = mNotificationList.get(i).sbn; - if (info.enabledAndUserMatches(sbn)) { - list.add(sbn); - } - } - } - return list.toArray(result); - } // -- end of listener APIs -- @@ -945,6 +781,7 @@ public class NotificationManagerService extends INotificationManager.Stub pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon) + " / " + idDebugString(baseContext, sbn.getPackageName(), notification.icon)); pw.println(prefix + " pri=" + notification.priority + " score=" + sbn.getScore()); + pw.println(prefix + " key=" + sbn.getKey()); pw.println(prefix + " contentIntent=" + notification.contentIntent); pw.println(prefix + " deleteIntent=" + notification.deleteIntent); pw.println(prefix + " tickerText=" + notification.tickerText); @@ -1001,10 +838,11 @@ public class NotificationManagerService extends INotificationManager.Stub @Override public final String toString() { return String.format( - "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d: %s)", + "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)", System.identityHashCode(this), - this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(), this.sbn.getTag(), - this.sbn.getScore(), this.sbn.getNotification()); + this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(), + this.sbn.getTag(), this.sbn.getScore(), this.sbn.getKey(), + this.sbn.getNotification()); } } @@ -1042,9 +880,9 @@ public class NotificationManagerService extends INotificationManager.Stub } } - private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks - = new StatusBarManagerService.NotificationCallbacks() { + private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { + @Override public void onSetDisabled(int status) { synchronized (mNotificationList) { mDisabledNotifications = status; @@ -1052,7 +890,7 @@ public class NotificationManagerService extends INotificationManager.Stub // cancel whatever's going on long identity = Binder.clearCallingIdentity(); try { - final IRingtonePlayer player = mAudioService.getRingtonePlayer(); + final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); if (player != null) { player.stopAsync(); } @@ -1071,12 +909,17 @@ public class NotificationManagerService extends INotificationManager.Stub } } + @Override public void onClearAll() { // XXX to be totally correct, the caller should tell us which user // this is for. - cancelAll(ActivityManager.getCurrentUser()); + int currentUser = ActivityManager.getCurrentUser(); + synchronized (mNotificationList) { + cancelAllLocked(currentUser); + } } + @Override public void onNotificationClick(String pkg, String tag, int id) { // XXX to be totally correct, the caller should tell us which user // this is for. @@ -1085,6 +928,7 @@ public class NotificationManagerService extends INotificationManager.Stub ActivityManager.getCurrentUser()); } + @Override public void onNotificationClear(String pkg, String tag, int id) { // XXX to be totally correct, the caller should tell us which user // this is for. @@ -1093,6 +937,7 @@ public class NotificationManagerService extends INotificationManager.Stub true, ActivityManager.getCurrentUser()); } + @Override public void onPanelRevealed() { synchronized (mNotificationList) { // sound @@ -1100,7 +945,7 @@ public class NotificationManagerService extends INotificationManager.Stub long identity = Binder.clearCallingIdentity(); try { - final IRingtonePlayer player = mAudioService.getRingtonePlayer(); + final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); if (player != null) { player.stopAsync(); } @@ -1125,6 +970,7 @@ public class NotificationManagerService extends INotificationManager.Stub } } + @Override public void onNotificationError(String pkg, String tag, int id, int uid, int initialPid, String message) { Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id @@ -1179,7 +1025,7 @@ public class NotificationManagerService extends INotificationManager.Stub if (packageChanged) { // We cancel notifications for packages which have just been disabled try { - final int enabled = mContext.getPackageManager() + final int enabled = getContext().getPackageManager() .getApplicationEnabledSetting(pkgName); if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { @@ -1255,7 +1101,7 @@ public class NotificationManagerService extends INotificationManager.Stub } void observe() { - ContentResolver resolver = mContext.getContentResolver(); + ContentResolver resolver = getContext().getContentResolver(); resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, false, this, UserHandle.USER_ALL); resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI, @@ -1268,7 +1114,7 @@ public class NotificationManagerService extends INotificationManager.Stub } public void update(Uri uri) { - ContentResolver resolver = mContext.getContentResolver(); + ContentResolver resolver = getContext().getContentResolver(); if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { boolean pulseEnabled = Settings.System.getInt(resolver, Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; @@ -1298,28 +1144,28 @@ public class NotificationManagerService extends INotificationManager.Stub return out; } - NotificationManagerService(Context context, StatusBarManagerService statusBar, - LightsService lights) - { - super(); - mContext = context; - mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); + public NotificationManagerService(Context context) { + super(context); + } + + @Override + public void onStart() { mAm = ActivityManagerNative.getDefault(); - mUserManager = (UserManager)context.getSystemService(Context.USER_SERVICE); - mToastQueue = new ArrayList<ToastRecord>(); - mHandler = new WorkerHandler(); + mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); + mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); - mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); + mHandler = new WorkerHandler(); importOldBlockDb(); - mStatusBar = statusBar; - statusBar.setNotificationCallbacks(mNotificationCallbacks); + mStatusBar = getLocalService(StatusBarManagerInternal.class); + mStatusBar.setNotificationDelegate(mNotificationDelegate); - mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS); - mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION); + final LightsManager lights = getLocalService(LightsManager.class); + mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS); + mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION); - Resources resources = mContext.getResources(); + Resources resources = getContext().getResources(); mDefaultNotificationColor = resources.getColor( R.color.config_defaultNotificationColor); mDefaultNotificationLedOn = resources.getInteger( @@ -1341,7 +1187,7 @@ public class NotificationManagerService extends INotificationManager.Stub // After that, including subsequent boots, init with notifications turned on. // This works on the first boot because the setup wizard will toggle this // flag at least once and we'll go back to 0 after that. - if (0 == Settings.Global.getInt(mContext.getContentResolver(), + if (0 == Settings.Global.getInt(getContext().getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) { mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS; } @@ -1354,7 +1200,7 @@ public class NotificationManagerService extends INotificationManager.Stub filter.addAction(Intent.ACTION_USER_PRESENT); filter.addAction(Intent.ACTION_USER_STOPPED); filter.addAction(Intent.ACTION_USER_SWITCHED); - mContext.registerReceiver(mIntentReceiver, filter); + getContext().registerReceiver(mIntentReceiver, filter); IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); @@ -1362,21 +1208,20 @@ public class NotificationManagerService extends INotificationManager.Stub pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); pkgFilter.addDataScheme("package"); - mContext.registerReceiver(mIntentReceiver, pkgFilter); + getContext().registerReceiver(mIntentReceiver, pkgFilter); IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); - mContext.registerReceiver(mIntentReceiver, sdFilter); + getContext().registerReceiver(mIntentReceiver, sdFilter); mSettingsObserver = new SettingsObserver(mHandler); - mSettingsObserver.observe(); // spin up NotificationScorers String[] notificationScorerNames = resources.getStringArray( R.array.config_notificationScorers); for (String scorerName : notificationScorerNames) { try { - Class<?> scorerClass = mContext.getClassLoader().loadClass(scorerName); + Class<?> scorerClass = getContext().getClassLoader().loadClass(scorerName); NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance(); - scorer.initialize(mContext); + scorer.initialize(getContext()); mScorers.add(scorer); } catch (ClassNotFoundException e) { Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e); @@ -1386,6 +1231,9 @@ public class NotificationManagerService extends INotificationManager.Stub Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e); } } + + publishBinderService(Context.NOTIFICATION_SERVICE, mService); + publishLocalService(NotificationManagerInternal.class, mInternalService); } /** @@ -1394,12 +1242,12 @@ public class NotificationManagerService extends INotificationManager.Stub private void importOldBlockDb() { loadBlockDb(); - PackageManager pm = mContext.getPackageManager(); + PackageManager pm = getContext().getPackageManager(); for (String pkg : mBlockedPackages) { PackageInfo info = null; try { info = pm.getPackageInfo(pkg, 0); - setNotificationsEnabledForPackage(pkg, info.applicationInfo.uid, false); + setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false); } catch (NameNotFoundException e) { // forget you } @@ -1410,244 +1258,475 @@ public class NotificationManagerService extends INotificationManager.Stub } } - void systemReady() { - mAudioService = IAudioService.Stub.asInterface( - ServiceManager.getService(Context.AUDIO_SERVICE)); + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { + // no beeping until we're basically done booting + mSystemReady = true; - // no beeping until we're basically done booting - mSystemReady = true; + // Grab our optional AudioService + mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); - // make sure our listener services are properly bound - rebindListenerServices(); + } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { + // This observer will force an update when observe is called, causing us to + // bind to listener services. + mSettingsObserver.observe(); + } } - // Toasts - // ============================================================================ - public void enqueueToast(String pkg, ITransientNotification callback, int duration) - { - if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration); + void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) { + Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg); + + mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, + enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); - if (pkg == null || callback == null) { - Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); - return ; + // Now, cancel any outstanding notifications that are part of a just-disabled app + if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { + cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid)); } + } - final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); + private final IBinder mService = new INotificationManager.Stub() { + // Toasts + // ============================================================================ - if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) { - if (!isSystemToast) { - Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request."); - return; + @Override + public void enqueueToast(String pkg, ITransientNotification callback, int duration) + { + if (DBG) { + Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + + " duration=" + duration); } - } - synchronized (mToastQueue) { - int callingPid = Binder.getCallingPid(); - long callingId = Binder.clearCallingIdentity(); - try { - ToastRecord record; - int index = indexOfToastLocked(pkg, callback); - // If it's already in the queue, we update it in place, we don't - // move it to the end of the queue. - if (index >= 0) { - record = mToastQueue.get(index); - record.update(duration); - } else { - // Limit the number of toasts that any given package except the android - // package can enqueue. Prevents DOS attacks and deals with leaks. - if (!isSystemToast) { - int count = 0; - final int N = mToastQueue.size(); - for (int i=0; i<N; i++) { - final ToastRecord r = mToastQueue.get(i); - if (r.pkg.equals(pkg)) { - count++; - if (count >= MAX_PACKAGE_NOTIFICATIONS) { - Slog.e(TAG, "Package has already posted " + count - + " toasts. Not showing more. Package=" + pkg); - return; + if (pkg == null || callback == null) { + Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); + return ; + } + + final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); + + if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) { + if (!isSystemToast) { + Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request."); + return; + } + } + + synchronized (mToastQueue) { + int callingPid = Binder.getCallingPid(); + long callingId = Binder.clearCallingIdentity(); + try { + ToastRecord record; + int index = indexOfToastLocked(pkg, callback); + // If it's already in the queue, we update it in place, we don't + // move it to the end of the queue. + if (index >= 0) { + record = mToastQueue.get(index); + record.update(duration); + } else { + // Limit the number of toasts that any given package except the android + // package can enqueue. Prevents DOS attacks and deals with leaks. + if (!isSystemToast) { + int count = 0; + final int N = mToastQueue.size(); + for (int i=0; i<N; i++) { + final ToastRecord r = mToastQueue.get(i); + if (r.pkg.equals(pkg)) { + count++; + if (count >= MAX_PACKAGE_NOTIFICATIONS) { + Slog.e(TAG, "Package has already posted " + count + + " toasts. Not showing more. Package=" + pkg); + return; + } } - } + } } + + record = new ToastRecord(callingPid, pkg, callback, duration); + mToastQueue.add(record); + index = mToastQueue.size() - 1; + keepProcessAliveLocked(callingPid); + } + // If it's at index 0, it's the current toast. It doesn't matter if it's + // new or just been updated. Call back and tell it to show itself. + // If the callback fails, this will remove it from the list, so don't + // assume that it's valid after this. + if (index == 0) { + showNextToastLocked(); } + } finally { + Binder.restoreCallingIdentity(callingId); + } + } + } + + @Override + public void cancelToast(String pkg, ITransientNotification callback) { + Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); - record = new ToastRecord(callingPid, pkg, callback, duration); - mToastQueue.add(record); - index = mToastQueue.size() - 1; - keepProcessAliveLocked(callingPid); + if (pkg == null || callback == null) { + Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); + return ; + } + + synchronized (mToastQueue) { + long callingId = Binder.clearCallingIdentity(); + try { + int index = indexOfToastLocked(pkg, callback); + if (index >= 0) { + cancelToastLocked(index); + } else { + Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + + " callback=" + callback); + } + } finally { + Binder.restoreCallingIdentity(callingId); } - // If it's at index 0, it's the current toast. It doesn't matter if it's - // new or just been updated. Call back and tell it to show itself. - // If the callback fails, this will remove it from the list, so don't - // assume that it's valid after this. - if (index == 0) { - showNextToastLocked(); + } + } + + @Override + public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id, + Notification notification, int[] idOut, int userId) throws RemoteException { + enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(), + Binder.getCallingPid(), tag, id, notification, idOut, userId); + } + + @Override + public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { + checkCallerIsSystemOrSameApp(pkg); + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); + // Don't allow client applications to cancel foreground service notis. + cancelNotification(pkg, tag, id, 0, + Binder.getCallingUid() == Process.SYSTEM_UID + ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId); + } + + @Override + public void cancelAllNotifications(String pkg, int userId) { + checkCallerIsSystemOrSameApp(pkg); + + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); + + // Calling from user space, don't allow the canceling of actively + // running foreground services. + cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId); + } + + @Override + public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { + checkCallerIsSystem(); + + setNotificationsEnabledForPackageImpl(pkg, uid, enabled); + } + + /** + * Use this when you just want to know if notifications are OK for this package. + */ + @Override + public boolean areNotificationsEnabledForPackage(String pkg, int uid) { + checkCallerIsSystem(); + return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) + == AppOpsManager.MODE_ALLOWED); + } + + /** + * System-only API for getting a list of current (i.e. not cleared) notifications. + * + * Requires ACCESS_NOTIFICATIONS which is signature|system. + */ + @Override + public StatusBarNotification[] getActiveNotifications(String callingPkg) { + // enforce() will ensure the calling uid has the correct permission + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.ACCESS_NOTIFICATIONS, + "NotificationManagerService.getActiveNotifications"); + + StatusBarNotification[] tmp = null; + int uid = Binder.getCallingUid(); + + // noteOp will check to make sure the callingPkg matches the uid + if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) + == AppOpsManager.MODE_ALLOWED) { + synchronized (mNotificationList) { + tmp = new StatusBarNotification[mNotificationList.size()]; + final int N = mNotificationList.size(); + for (int i=0; i<N; i++) { + tmp[i] = mNotificationList.get(i).sbn; + } } - } finally { - Binder.restoreCallingIdentity(callingId); } + return tmp; } - } - public void cancelToast(String pkg, ITransientNotification callback) { - Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); + /** + * System-only API for getting a list of recent (cleared, no longer shown) notifications. + * + * Requires ACCESS_NOTIFICATIONS which is signature|system. + */ + @Override + public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { + // enforce() will ensure the calling uid has the correct permission + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.ACCESS_NOTIFICATIONS, + "NotificationManagerService.getHistoricalNotifications"); + + StatusBarNotification[] tmp = null; + int uid = Binder.getCallingUid(); + + // noteOp will check to make sure the callingPkg matches the uid + if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) + == AppOpsManager.MODE_ALLOWED) { + synchronized (mArchive) { + tmp = mArchive.getArray(count); + } + } + return tmp; + } - if (pkg == null || callback == null) { - Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); - return ; + /** + * Register a listener binder directly with the notification manager. + * + * Only works with system callers. Apps should extend + * {@link android.service.notification.NotificationListenerService}. + */ + @Override + public void registerListener(final INotificationListener listener, + final ComponentName component, final int userid) { + checkCallerIsSystem(); + checkNullListener(listener); + registerListenerImpl(listener, component, userid); } - synchronized (mToastQueue) { - long callingId = Binder.clearCallingIdentity(); + /** + * Remove a listener binder directly + */ + @Override + public void unregisterListener(INotificationListener listener, int userid) { + checkNullListener(listener); + // no need to check permissions; if your listener binder is in the list, + // that's proof that you had permission to add it in the first place + unregisterListenerImpl(listener, userid); + } + + /** + * Allow an INotificationListener to simulate a "clear all" operation. + * + * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} + * + * @param token The binder for the listener, to check that the caller is allowed + */ + @Override + public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { + long identity = Binder.clearCallingIdentity(); try { - int index = indexOfToastLocked(pkg, callback); - if (index >= 0) { - cancelToastLocked(index); - } else { - Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback); + synchronized (mNotificationList) { + final NotificationListenerInfo info = checkListenerTokenLocked(token); + if (keys != null) { + final int N = keys.length; + for (int i = 0; i < N; i++) { + NotificationRecord r = mNotificationsByKey.get(keys[i]); + if (r != null) { + cancelNotificationFromListenerLocked(info, + r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId()); + } + } + } else { + cancelAllLocked(info.userid); + } } } finally { - Binder.restoreCallingIdentity(callingId); + Binder.restoreCallingIdentity(identity); } } - } - private void showNextToastLocked() { - ToastRecord record = mToastQueue.get(0); - while (record != null) { - if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); + private void cancelNotificationFromListenerLocked(NotificationListenerInfo info, + String pkg, String tag, int id) { + cancelNotification(pkg, tag, id, 0, + Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, + true, + info.userid); + } + + /** + * Allow an INotificationListener to simulate clearing (dismissing) a single notification. + * + * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} + * + * @param token The binder for the listener, to check that the caller is allowed + */ + @Override + public void cancelNotificationFromListener(INotificationListener token, String pkg, + String tag, int id) { + long identity = Binder.clearCallingIdentity(); try { - record.callback.show(); - scheduleTimeoutLocked(record); - return; - } catch (RemoteException e) { - Slog.w(TAG, "Object died trying to show notification " + record.callback - + " in package " + record.pkg); - // remove it from the list and let the process die - int index = mToastQueue.indexOf(record); - if (index >= 0) { - mToastQueue.remove(index); + synchronized (mNotificationList) { + final NotificationListenerInfo info = checkListenerTokenLocked(token); + cancelNotificationFromListenerLocked(info, + pkg, tag, id); } - keepProcessAliveLocked(record.pid); - if (mToastQueue.size() > 0) { - record = mToastQueue.get(0); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + /** + * Allow an INotificationListener to request the list of outstanding notifications seen by + * the current user. Useful when starting up, after which point the listener callbacks + * should be used. + * + * @param token The binder for the listener, to check that the caller is allowed + */ + @Override + public StatusBarNotification[] getActiveNotificationsFromListener( + INotificationListener token, String[] keys) { + synchronized (mNotificationList) { + final NotificationListenerInfo info = checkListenerTokenLocked(token); + final ArrayList<StatusBarNotification> list + = new ArrayList<StatusBarNotification>(); + if (keys == null) { + final int N = mNotificationList.size(); + for (int i=0; i<N; i++) { + StatusBarNotification sbn = mNotificationList.get(i).sbn; + if (info.enabledAndUserMatches(sbn)) { + list.add(sbn); + } + } } else { - record = null; + final int N = keys.length; + for (int i=0; i<N; i++) { + NotificationRecord r = mNotificationsByKey.get(keys[i]); + if (r != null && info.enabledAndUserMatches(r.sbn)) { + list.add(r.sbn); + } + } } + return list.toArray(new StatusBarNotification[list.size()]); } } - } - private void cancelToastLocked(int index) { - ToastRecord record = mToastQueue.get(index); - try { - record.callback.hide(); - } catch (RemoteException e) { - Slog.w(TAG, "Object died trying to hide notification " + record.callback - + " in package " + record.pkg); - // don't worry about this, we're about to remove it from - // the list anyway - } - mToastQueue.remove(index); - keepProcessAliveLocked(record.pid); - if (mToastQueue.size() > 0) { - // Show the next one. If the callback fails, this will remove - // it from the list, so don't assume that the list hasn't changed - // after this point. - showNextToastLocked(); + @Override + public String[] getActiveNotificationKeysFromListener(INotificationListener token) { + return NotificationManagerService.this.getActiveNotificationKeysFromListener(token); } - } - private void scheduleTimeoutLocked(ToastRecord r) - { - mHandler.removeCallbacksAndMessages(r); - Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); - long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; - mHandler.sendMessageDelayed(m, delay); - } - - private void handleTimeout(ToastRecord record) - { - if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); - synchronized (mToastQueue) { - int index = indexOfToastLocked(record.pkg, record.callback); - if (index >= 0) { - cancelToastLocked(index); + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump NotificationManager from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; } + + dumpImpl(pw); } - } + }; - // lock on mToastQueue - private int indexOfToastLocked(String pkg, ITransientNotification callback) - { - IBinder cbak = callback.asBinder(); - ArrayList<ToastRecord> list = mToastQueue; - int len = list.size(); - for (int i=0; i<len; i++) { - ToastRecord r = list.get(i); - if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { - return i; + private String[] getActiveNotificationKeysFromListener(INotificationListener token) { + synchronized (mNotificationList) { + final NotificationListenerInfo info = checkListenerTokenLocked(token); + final ArrayList<String> keys = new ArrayList<String>(); + final int N = mNotificationList.size(); + for (int i=0; i<N; i++) { + final StatusBarNotification sbn = mNotificationList.get(i).sbn; + if (info.enabledAndUserMatches(sbn)) { + keys.add(sbn.getKey()); + } } + return keys.toArray(new String[keys.size()]); } - return -1; } - // lock on mToastQueue - private void keepProcessAliveLocked(int pid) - { - int toastCount = 0; // toasts from this pid - ArrayList<ToastRecord> list = mToastQueue; - int N = list.size(); - for (int i=0; i<N; i++) { - ToastRecord r = list.get(i); - if (r.pid == pid) { - toastCount++; - } + void dumpImpl(PrintWriter pw) { + pw.println("Current Notification Manager state:"); + + pw.println(" Listeners (" + mEnabledListenersForCurrentUser.size() + + ") enabled for current user:"); + for (ComponentName cmpt : mEnabledListenersForCurrentUser) { + pw.println(" " + cmpt); } - try { - mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); - } catch (RemoteException e) { - // Shouldn't happen. + + pw.println(" Live listeners (" + mListeners.size() + "):"); + for (NotificationListenerInfo info : mListeners) { + pw.println(" " + info.component + + " (user " + info.userid + "): " + info.listener + + (info.isSystem?" SYSTEM":"")); } - } - private final class WorkerHandler extends Handler - { - @Override - public void handleMessage(Message msg) - { - switch (msg.what) - { - case MESSAGE_TIMEOUT: - handleTimeout((ToastRecord)msg.obj); - break; + int N; + + synchronized (mToastQueue) { + N = mToastQueue.size(); + if (N > 0) { + pw.println(" Toast Queue:"); + for (int i=0; i<N; i++) { + mToastQueue.get(i).dump(pw, " "); + } + pw.println(" "); } + } - } + synchronized (mNotificationList) { + N = mNotificationList.size(); + if (N > 0) { + pw.println(" Notification List:"); + for (int i=0; i<N; i++) { + mNotificationList.get(i).dump(pw, " ", getContext()); + } + pw.println(" "); + } - // Notifications - // ============================================================================ - public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id, - Notification notification, int[] idOut, int userId) - { - enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(), Binder.getCallingPid(), - tag, id, notification, idOut, userId); - } - - private final static int clamp(int x, int low, int high) { - return (x < low) ? low : ((x > high) ? high : x); + N = mLights.size(); + if (N > 0) { + pw.println(" Lights List:"); + for (int i=0; i<N; i++) { + pw.println(" " + mLights.get(i)); + } + pw.println(" "); + } + + pw.println(" mSoundNotification=" + mSoundNotification); + pw.println(" mVibrateNotification=" + mVibrateNotification); + pw.println(" mDisabledNotifications=0x" + + Integer.toHexString(mDisabledNotifications)); + pw.println(" mSystemReady=" + mSystemReady); + pw.println(" mArchive=" + mArchive.toString()); + Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); + int i=0; + while (iter.hasNext()) { + pw.println(" " + iter.next()); + if (++i >= 5) { + if (iter.hasNext()) pw.println(" ..."); + break; + } + } + + } } - // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the - // uid/pid of another application) + /** + * The private API only accessible to the system process. + */ + private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { + @Override + public void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid, + String tag, int id, Notification notification, int[] idReceived, int userId) { + enqueueNotificationInternal(pkg, basePkg, callingUid, callingPid, tag, id, notification, + idReceived, userId); + } + }; - public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid, + void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid, final int callingPid, final String tag, final int id, final Notification notification, - int[] idOut, int incomingUserId) - { + int[] idOut, int incomingUserId) { if (DBG) { - Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification); + Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + + " notification=" + notification); } checkCallerIsSystemOrSameApp(pkg); final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); @@ -1779,6 +1858,10 @@ public class NotificationManagerService extends INotificationManager.Stub old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; } } + if (old != null) { + mNotificationsByKey.remove(old.sbn.getKey()); + } + mNotificationsByKey.put(n.getKey(), r); // Ensure if this is a foreground service that the proper additional // flags are set. @@ -1798,23 +1881,21 @@ public class NotificationManagerService extends INotificationManager.Stub if (notification.icon != 0) { if (old != null && old.statusBarKey != null) { r.statusBarKey = old.statusBarKey; - long identity = Binder.clearCallingIdentity(); + final long identity = Binder.clearCallingIdentity(); try { mStatusBar.updateNotification(r.statusBarKey, n); - } - finally { + } finally { Binder.restoreCallingIdentity(identity); } } else { - long identity = Binder.clearCallingIdentity(); + final long identity = Binder.clearCallingIdentity(); try { r.statusBarKey = mStatusBar.addNotification(n); if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0 && canInterrupt) { mAttentionLight.pulse(); } - } - finally { + } finally { Binder.restoreCallingIdentity(identity); } } @@ -1827,33 +1908,32 @@ public class NotificationManagerService extends INotificationManager.Stub } else { Slog.e(TAG, "Not posting notification with icon==0: " + notification); if (old != null && old.statusBarKey != null) { - long identity = Binder.clearCallingIdentity(); + final long identity = Binder.clearCallingIdentity(); try { mStatusBar.removeNotification(old.statusBarKey); - } - finally { + } finally { Binder.restoreCallingIdentity(identity); } notifyRemovedLocked(r); } // ATTENTION: in a future release we will bail out here - // so that we do not play sounds, show lights, etc. for invalid notifications + // so that we do not play sounds, show lights, etc. for invalid + // notifications Slog.e(TAG, "WARNING: In a future release this will crash the app: " + n.getPackageName()); } // If we're not supposed to beep, vibrate, etc. then don't. - if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0) + if (((mDisabledNotifications + & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0) && (!(old != null && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 )) && (r.getUserId() == UserHandle.USER_ALL || (r.getUserId() == userId && r.getUserId() == currentUser)) && canInterrupt - && mSystemReady) { - - final AudioManager audioManager = (AudioManager) mContext - .getSystemService(Context.AUDIO_SERVICE); + && mSystemReady + && mAudioManager != null) { // sound @@ -1872,7 +1952,7 @@ public class NotificationManagerService extends INotificationManager.Stub soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; // check to see if the default notification sound is silent - ContentResolver resolver = mContext.getContentResolver(); + ContentResolver resolver = getContext().getContentResolver(); hasValidSound = Settings.System.getString(resolver, Settings.System.NOTIFICATION_SOUND) != null; } else if (notification.sound != null) { @@ -1881,7 +1961,8 @@ public class NotificationManagerService extends INotificationManager.Stub } if (hasValidSound) { - boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0; + boolean looping = + (notification.flags & Notification.FLAG_INSISTENT) != 0; int audioStreamType; if (notification.audioStreamType >= 0) { audioStreamType = notification.audioStreamType; @@ -1891,11 +1972,12 @@ public class NotificationManagerService extends INotificationManager.Stub mSoundNotification = r; // do not play notifications if stream volume is 0 (typically because // ringer mode is silent) or if there is a user of exclusive audio focus - if ((audioManager.getStreamVolume(audioStreamType) != 0) - && !audioManager.isAudioFocusExclusive()) { + if ((mAudioManager.getStreamVolume(audioStreamType) != 0) + && !mAudioManager.isAudioFocusExclusive()) { final long identity = Binder.clearCallingIdentity(); try { - final IRingtonePlayer player = mAudioService.getRingtonePlayer(); + final IRingtonePlayer player = + mAudioManager.getRingtonePlayer(); if (player != null) { player.playAsync(soundUri, user, looping, audioStreamType); } @@ -1915,7 +1997,7 @@ public class NotificationManagerService extends INotificationManager.Stub final boolean convertSoundToVibration = !hasCustomVibrate && hasValidSound - && (audioManager.getRingerMode() + && (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. @@ -1923,7 +2005,7 @@ public class NotificationManagerService extends INotificationManager.Stub (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate) - && !(audioManager.getRingerMode() + && !(mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT)) { mVibrateNotification = r; @@ -1977,8 +2059,173 @@ public class NotificationManagerService extends INotificationManager.Stub idOut[0] = id; } - private void sendAccessibilityEvent(Notification notification, CharSequence packageName) { - AccessibilityManager manager = AccessibilityManager.getInstance(mContext); + void registerListenerImpl(final INotificationListener listener, + final ComponentName component, final int userid) { + synchronized (mNotificationList) { + try { + NotificationListenerInfo info + = new NotificationListenerInfo(listener, component, userid, true); + listener.asBinder().linkToDeath(info, 0); + mListeners.add(info); + } catch (RemoteException e) { + // already dead + } + } + } + + /** + * Removes a listener from the list and unbinds from its service. + */ + void unregisterListenerImpl(final INotificationListener listener, final int userid) { + NotificationListenerInfo info = removeListenerImpl(listener, userid); + if (info != null && info.connection != null) { + getContext().unbindService(info.connection); + } + } + + /** + * Removes a listener from the list but does not unbind from the listener's service. + * + * @return the removed listener. + */ + NotificationListenerInfo removeListenerImpl( + final INotificationListener listener, final int userid) { + NotificationListenerInfo listenerInfo = null; + synchronized (mNotificationList) { + final int N = mListeners.size(); + for (int i=N-1; i>=0; i--) { + final NotificationListenerInfo info = mListeners.get(i); + if (info.listener.asBinder() == listener.asBinder() + && info.userid == userid) { + listenerInfo = mListeners.remove(i); + } + } + } + return listenerInfo; + } + + void showNextToastLocked() { + ToastRecord record = mToastQueue.get(0); + while (record != null) { + if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); + try { + record.callback.show(); + scheduleTimeoutLocked(record); + return; + } catch (RemoteException e) { + Slog.w(TAG, "Object died trying to show notification " + record.callback + + " in package " + record.pkg); + // remove it from the list and let the process die + int index = mToastQueue.indexOf(record); + if (index >= 0) { + mToastQueue.remove(index); + } + keepProcessAliveLocked(record.pid); + if (mToastQueue.size() > 0) { + record = mToastQueue.get(0); + } else { + record = null; + } + } + } + } + + void cancelToastLocked(int index) { + ToastRecord record = mToastQueue.get(index); + try { + record.callback.hide(); + } catch (RemoteException e) { + Slog.w(TAG, "Object died trying to hide notification " + record.callback + + " in package " + record.pkg); + // don't worry about this, we're about to remove it from + // the list anyway + } + mToastQueue.remove(index); + keepProcessAliveLocked(record.pid); + if (mToastQueue.size() > 0) { + // Show the next one. If the callback fails, this will remove + // it from the list, so don't assume that the list hasn't changed + // after this point. + showNextToastLocked(); + } + } + + private void scheduleTimeoutLocked(ToastRecord r) + { + mHandler.removeCallbacksAndMessages(r); + Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); + long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; + mHandler.sendMessageDelayed(m, delay); + } + + private void handleTimeout(ToastRecord record) + { + if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); + synchronized (mToastQueue) { + int index = indexOfToastLocked(record.pkg, record.callback); + if (index >= 0) { + cancelToastLocked(index); + } + } + } + + // lock on mToastQueue + int indexOfToastLocked(String pkg, ITransientNotification callback) + { + IBinder cbak = callback.asBinder(); + ArrayList<ToastRecord> list = mToastQueue; + int len = list.size(); + for (int i=0; i<len; i++) { + ToastRecord r = list.get(i); + if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { + return i; + } + } + return -1; + } + + // lock on mToastQueue + void keepProcessAliveLocked(int pid) + { + int toastCount = 0; // toasts from this pid + ArrayList<ToastRecord> list = mToastQueue; + int N = list.size(); + for (int i=0; i<N; i++) { + ToastRecord r = list.get(i); + if (r.pid == pid) { + toastCount++; + } + } + try { + mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); + } catch (RemoteException e) { + // Shouldn't happen. + } + } + + private final class WorkerHandler extends Handler + { + @Override + public void handleMessage(Message msg) + { + switch (msg.what) + { + case MESSAGE_TIMEOUT: + handleTimeout((ToastRecord)msg.obj); + break; + } + } + } + + + // Notifications + // ============================================================================ + static int clamp(int x, int low, int high) { + return (x < low) ? low : ((x > high) ? high : x); + } + + void sendAccessibilityEvent(Notification notification, CharSequence packageName) { + AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); if (!manager.isEnabled()) { return; } @@ -2012,11 +2259,10 @@ public class NotificationManagerService extends INotificationManager.Stub // status bar if (r.getNotification().icon != 0) { - long identity = Binder.clearCallingIdentity(); + final long identity = Binder.clearCallingIdentity(); try { mStatusBar.removeNotification(r.statusBarKey); - } - finally { + } finally { Binder.restoreCallingIdentity(identity); } r.statusBarKey = null; @@ -2028,7 +2274,7 @@ public class NotificationManagerService extends INotificationManager.Stub mSoundNotification = null; final long identity = Binder.clearCallingIdentity(); try { - final IRingtonePlayer player = mAudioService.getRingtonePlayer(); + final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); if (player != null) { player.stopAsync(); } @@ -2064,7 +2310,7 @@ public class NotificationManagerService extends INotificationManager.Stub * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} * and none of the {@code mustNotHaveFlags}. */ - private void cancelNotification(final String pkg, final String tag, final int id, + void cancelNotification(final String pkg, final String tag, final int id, final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, final int userId) { // In enqueueNotificationInternal notifications are added by scheduling the @@ -2090,6 +2336,7 @@ public class NotificationManagerService extends INotificationManager.Stub } mNotificationList.remove(index); + mNotificationsByKey.remove(r.sbn.getKey()); cancelNotificationLocked(r, sendDelete); updateLightsLocked(); @@ -2148,6 +2395,7 @@ public class NotificationManagerService extends INotificationManager.Stub return true; } mNotificationList.remove(i); + mNotificationsByKey.remove(r.sbn.getKey()); cancelNotificationLocked(r, false); } if (canceledSomething) { @@ -2157,26 +2405,7 @@ public class NotificationManagerService extends INotificationManager.Stub } } - public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { - checkCallerIsSystemOrSameApp(pkg); - userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), - Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); - // Don't allow client applications to cancel foreground service notis. - cancelNotification(pkg, tag, id, 0, - Binder.getCallingUid() == Process.SYSTEM_UID - ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId); - } - - public void cancelAllNotifications(String pkg, int userId) { - checkCallerIsSystemOrSameApp(pkg); - - userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), - Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); - // Calling from user space, don't allow the canceling of actively - // running foreground services. - cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId); - } // Return true if the UID is a system or phone UID and therefore should not have // any notifications or toasts blocked. @@ -2214,29 +2443,28 @@ public class NotificationManagerService extends INotificationManager.Stub } } - void cancelAll(int userId) { - synchronized (mNotificationList) { - final int N = mNotificationList.size(); - for (int i=N-1; i>=0; i--) { - NotificationRecord r = mNotificationList.get(i); - - if (!notificationMatchesUserId(r, userId)) { - continue; - } + void cancelAllLocked(int userId) { + final int N = mNotificationList.size(); + for (int i=N-1; i>=0; i--) { + NotificationRecord r = mNotificationList.get(i); - if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT - | Notification.FLAG_NO_CLEAR)) == 0) { - mNotificationList.remove(i); - cancelNotificationLocked(r, true); - } + if (!notificationMatchesUserId(r, userId)) { + continue; } - updateLightsLocked(); + if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT + | Notification.FLAG_NO_CLEAR)) == 0) { + mNotificationList.remove(i); + mNotificationsByKey.remove(r.sbn.getKey()); + cancelNotificationLocked(r, true); + } } + + updateLightsLocked(); } // lock on mNotificationList - private void updateLightsLocked() + void updateLightsLocked() { // handle notification lights if (mLedNotification == null) { @@ -2262,14 +2490,14 @@ public class NotificationManagerService extends INotificationManager.Stub } if (mNotificationPulseEnabled) { // pulse repeatedly - mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED, + mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, ledOnMS, ledOffMS); } } } // lock on mNotificationList - private int indexOfNotificationLocked(String pkg, String tag, int id, int userId) + int indexOfNotificationLocked(String pkg, String tag, int id, int userId) { ArrayList<NotificationRecord> list = mNotificationList; final int len = list.size(); @@ -2299,81 +2527,4 @@ public class NotificationManagerService extends INotificationManager.Stub updateLightsLocked(); } } - - // ====================================================================== - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump NotificationManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - pw.println("Current Notification Manager state:"); - - pw.println(" Listeners (" + mEnabledListenersForCurrentUser.size() - + ") enabled for current user:"); - for (ComponentName cmpt : mEnabledListenersForCurrentUser) { - pw.println(" " + cmpt); - } - - pw.println(" Live listeners (" + mListeners.size() + "):"); - for (NotificationListenerInfo info : mListeners) { - pw.println(" " + info.component - + " (user " + info.userid + "): " + info.listener - + (info.isSystem?" SYSTEM":"")); - } - - int N; - - synchronized (mToastQueue) { - N = mToastQueue.size(); - if (N > 0) { - pw.println(" Toast Queue:"); - for (int i=0; i<N; i++) { - mToastQueue.get(i).dump(pw, " "); - } - pw.println(" "); - } - - } - - synchronized (mNotificationList) { - N = mNotificationList.size(); - if (N > 0) { - pw.println(" Notification List:"); - for (int i=0; i<N; i++) { - mNotificationList.get(i).dump(pw, " ", mContext); - } - pw.println(" "); - } - - N = mLights.size(); - if (N > 0) { - pw.println(" Lights List:"); - for (int i=0; i<N; i++) { - pw.println(" " + mLights.get(i)); - } - pw.println(" "); - } - - pw.println(" mSoundNotification=" + mSoundNotification); - pw.println(" mVibrateNotification=" + mVibrateNotification); - pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications)); - pw.println(" mSystemReady=" + mSystemReady); - pw.println(" mArchive=" + mArchive.toString()); - Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); - int i=0; - while (iter.hasNext()) { - pw.println(" " + iter.next()); - if (++i >= 5) { - if (iter.hasNext()) pw.println(" ..."); - break; - } - } - - } - } } diff --git a/services/java/com/android/server/os/SchedulingPolicyService.java b/services/core/java/com/android/server/os/SchedulingPolicyService.java index c0123bf..c0123bf 100644 --- a/services/java/com/android/server/os/SchedulingPolicyService.java +++ b/services/core/java/com/android/server/os/SchedulingPolicyService.java diff --git a/services/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java index 4f27408..4f27408 100644 --- a/services/java/com/android/server/pm/BasePermission.java +++ b/services/core/java/com/android/server/pm/BasePermission.java diff --git a/services/java/com/android/server/pm/GrantedPermissions.java b/services/core/java/com/android/server/pm/GrantedPermissions.java index 14258a4..14258a4 100644 --- a/services/java/com/android/server/pm/GrantedPermissions.java +++ b/services/core/java/com/android/server/pm/GrantedPermissions.java diff --git a/services/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 734d071..6185e50 100644 --- a/services/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -16,6 +16,9 @@ package com.android.server.pm; +import com.android.server.SystemService; + +import android.content.Context; import android.content.pm.PackageStats; import android.net.LocalSocket; import android.net.LocalSocketAddress; @@ -25,21 +28,28 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -public final class Installer { +public final class Installer extends SystemService { private static final String TAG = "Installer"; private static final boolean LOCAL_DEBUG = false; InputStream mIn; - OutputStream mOut; - LocalSocket mSocket; byte buf[] = new byte[1024]; - int buflen = 0; + public Installer(Context context) { + super(context); + } + + @Override + public void onStart() { + Slog.i(TAG, "Waiting for installd to be ready."); + ping(); + } + private boolean connect() { if (mSocket != null) { return true; @@ -265,7 +275,7 @@ public final class Installer { return execute(builder.toString()); } - public int createUserData(String name, int uid, int userId) { + public int createUserData(String name, int uid, int userId, String seinfo) { StringBuilder builder = new StringBuilder("mkuserdata"); builder.append(' '); builder.append(name); @@ -273,6 +283,8 @@ public final class Installer { builder.append(uid); builder.append(' '); builder.append(userId); + builder.append(' '); + builder.append(seinfo != null ? seinfo : "!"); return execute(builder.toString()); } diff --git a/services/java/com/android/server/pm/KeySetManager.java b/services/core/java/com/android/server/pm/KeySetManager.java index 66dc1d1..66dc1d1 100644 --- a/services/java/com/android/server/pm/KeySetManager.java +++ b/services/core/java/com/android/server/pm/KeySetManager.java diff --git a/services/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java index cb60621..cb60621 100644 --- a/services/java/com/android/server/pm/PackageKeySetData.java +++ b/services/core/java/com/android/server/pm/PackageKeySetData.java diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index dc63ca2..0f2bea6 100755 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -38,10 +38,11 @@ import com.android.internal.content.PackageHelper; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; -import com.android.server.DeviceStorageMonitorService; import com.android.server.EventLogTags; import com.android.server.IntentResolver; +import com.android.server.ServiceThread; +import com.android.server.LocalServices; import com.android.server.Watchdog; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -92,6 +93,7 @@ import android.content.pm.VerificationParams; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; import android.content.res.Resources; +import android.hardware.display.DisplayManager; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -127,7 +129,6 @@ import android.util.Slog; import android.util.SparseArray; import android.util.Xml; import android.view.Display; -import android.view.WindowManager; import java.io.BufferedOutputStream; import java.io.File; @@ -162,6 +163,7 @@ import libcore.io.Libcore; import libcore.io.StructStat; import com.android.internal.R; +import com.android.server.storage.DeviceStorageMonitorInternal; /** * Keep track of all those .apks everywhere. @@ -260,8 +262,7 @@ public class PackageManagerService extends IPackageManager.Stub { static final String mTempContainerPrefix = "smdl2tmp"; - final HandlerThread mHandlerThread = new HandlerThread("PackageManager", - Process.THREAD_PRIORITY_BACKGROUND); + final ServiceThread mHandlerThread; final PackageHandler mHandler; final int mSdkVersion = Build.VERSION.SDK_INT; @@ -1067,6 +1068,12 @@ public class PackageManagerService extends IPackageManager.Stub { return res; } + private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) { + DisplayManager displayManager = (DisplayManager) context.getSystemService( + Context.DISPLAY_SERVICE); + displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics); + } + public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, @@ -1114,17 +1121,16 @@ public class PackageManagerService extends IPackageManager.Stub { mInstaller = installer; - WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); - Display d = wm.getDefaultDisplay(); - d.getMetrics(mMetrics); + getDefaultDisplayMetrics(context, mMetrics); synchronized (mInstallLock) { // writer synchronized (mPackages) { + mHandlerThread = new ServiceThread(TAG, + Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/); mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); - Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName(), - WATCHDOG_TIMEOUT); + Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT); File dataDir = Environment.getDataDirectory(); mAppDataDir = new File(dataDir, "data"); @@ -2540,15 +2546,41 @@ public class PackageManagerService extends IPackageManager.Stub { } } + /** + * Compares two sets of signatures. Returns: + * <br /> + * {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null, + * <br /> + * {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null, + * <br /> + * {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null, + * <br /> + * {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical, + * <br /> + * {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ. + */ static int compareSignatures(Signature[] s1, Signature[] s2) { if (s1 == null) { return s2 == null ? PackageManager.SIGNATURE_NEITHER_SIGNED : PackageManager.SIGNATURE_FIRST_NOT_SIGNED; } + if (s2 == null) { return PackageManager.SIGNATURE_SECOND_NOT_SIGNED; } + + if (s1.length != s2.length) { + return PackageManager.SIGNATURE_NO_MATCH; + } + + // Since both signature sets are of size 1, we can compare without HashSets. + if (s1.length == 1) { + return s1[0].equals(s2[0]) ? + PackageManager.SIGNATURE_MATCH : + PackageManager.SIGNATURE_NO_MATCH; + } + HashSet<Signature> set1 = new HashSet<Signature>(); for (Signature sig : s1) { set1.add(sig); @@ -3999,7 +4031,7 @@ public class PackageManagerService extends IPackageManager.Stub { for (int user : users) { if (user != 0) { res = mInstaller.createUserData(packageName, - UserHandle.getUid(user, uid), user); + UserHandle.getUid(user, uid), user, seinfo); if (res < 0) { return res; } @@ -7352,6 +7384,15 @@ public class PackageManagerService extends IPackageManager.Stub { return pkgLite.recommendedInstallLocation; } + private long getMemoryLowThreshold() { + final DeviceStorageMonitorInternal + dsm = LocalServices.getService(DeviceStorageMonitorInternal.class); + if (dsm == null) { + return 0L; + } + return dsm.getMemoryLowThreshold(); + } + /* * Invoke remote method to get package information and install * location values. Override install location based on default @@ -7369,15 +7410,9 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { - final long lowThreshold; - - final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager - .getService(DeviceStorageMonitorService.SERVICE); - if (dsm == null) { + final long lowThreshold = getMemoryLowThreshold(); + if (lowThreshold == 0L) { Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed"); - lowThreshold = 0L; - } else { - lowThreshold = dsm.getMemoryLowThreshold(); } try { @@ -7935,8 +7970,8 @@ public class PackageManagerService extends IPackageManager.Stub { boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { final long lowThreshold; - final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager - .getService(DeviceStorageMonitorService.SERVICE); + final DeviceStorageMonitorInternal + dsm = LocalServices.getService(DeviceStorageMonitorInternal.class); if (dsm == null) { Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed"); lowThreshold = 0L; @@ -9751,10 +9786,10 @@ public class PackageManagerService extends IPackageManager.Stub { clearExternalStorageDataSync(packageName, userId, true); if (succeeded) { // invoke DeviceStorageMonitor's update method to clear any notifications - DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) - ServiceManager.getService(DeviceStorageMonitorService.SERVICE); + DeviceStorageMonitorInternal + dsm = LocalServices.getService(DeviceStorageMonitorInternal.class); if (dsm != null) { - dsm.updateMemory(); + dsm.checkMemory(); } } if(observer != null) { @@ -11614,12 +11649,17 @@ public class PackageManagerService extends IPackageManager.Stub { return true; } + @Override public boolean isStorageLow() { final long token = Binder.clearCallingIdentity(); try { - final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager - .getService(DeviceStorageMonitorService.SERVICE); - return dsm.isMemoryLow(); + final DeviceStorageMonitorInternal + dsm = LocalServices.getService(DeviceStorageMonitorInternal.class); + if (dsm != null) { + return dsm.isMemoryLow(); + } else { + return false; + } } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index b447861..b447861 100644 --- a/services/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 7747c8f..7747c8f 100644 --- a/services/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java diff --git a/services/java/com/android/server/pm/PackageSignatures.java b/services/core/java/com/android/server/pm/PackageSignatures.java index 9a20be7..9a20be7 100644 --- a/services/java/com/android/server/pm/PackageSignatures.java +++ b/services/core/java/com/android/server/pm/PackageSignatures.java diff --git a/services/java/com/android/server/pm/PackageVerificationResponse.java b/services/core/java/com/android/server/pm/PackageVerificationResponse.java index b2ae0dd..b2ae0dd 100644 --- a/services/java/com/android/server/pm/PackageVerificationResponse.java +++ b/services/core/java/com/android/server/pm/PackageVerificationResponse.java diff --git a/services/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java index 3214e88..3214e88 100644 --- a/services/java/com/android/server/pm/PackageVerificationState.java +++ b/services/core/java/com/android/server/pm/PackageVerificationState.java diff --git a/services/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java index c17cc46..c17cc46 100644 --- a/services/java/com/android/server/pm/PendingPackage.java +++ b/services/core/java/com/android/server/pm/PendingPackage.java diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/core/java/com/android/server/pm/PreferredActivity.java index f93ba2f..8916926 100644 --- a/services/java/com/android/server/pm/PreferredActivity.java +++ b/services/core/java/com/android/server/pm/PreferredActivity.java @@ -17,7 +17,6 @@ package com.android.server.pm; import com.android.internal.util.XmlUtils; -import com.android.server.PreferredComponent; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/services/java/com/android/server/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java index a7af252..f437372 100644 --- a/services/java/com/android/server/PreferredComponent.java +++ b/services/core/java/com/android/server/pm/PreferredComponent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.pm; import com.android.internal.util.XmlUtils; diff --git a/services/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java index bce24d7..bce24d7 100644 --- a/services/java/com/android/server/pm/PreferredIntentResolver.java +++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java diff --git a/services/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java index 04f43d9..1d68afa 100644 --- a/services/java/com/android/server/pm/SELinuxMMAC.java +++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java @@ -48,12 +48,11 @@ public final class SELinuxMMAC { private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false; // Signature seinfo values read from policy. - private static final HashMap<Signature, String> sSigSeinfo = - new HashMap<Signature, String>(); + private static HashMap<Signature, Policy> sSigSeinfo = + new HashMap<Signature, Policy>(); - // Package name seinfo values read from policy. - private static final HashMap<String, String> sPackageSeinfo = - new HashMap<String, String>(); + // Default seinfo read from policy. + private static String sDefaultSeinfo = null; // Locations of potential install policy files. private static final File[] INSTALL_POLICY_FILE = { @@ -61,9 +60,45 @@ public final class SELinuxMMAC { new File(Environment.getRootDirectory(), "etc/security/mac_permissions.xml"), null}; + // Signature policy stanzas + static class Policy { + private String seinfo; + private final HashMap<String, String> pkgMap; + + Policy() { + seinfo = null; + pkgMap = new HashMap<String, String>(); + } + + void putSeinfo(String seinfoValue) { + seinfo = seinfoValue; + } + + void putPkg(String pkg, String seinfoValue) { + pkgMap.put(pkg, seinfoValue); + } + + // Valid policy stanza means there exists a global + // seinfo value or at least one package policy. + boolean isValid() { + return (seinfo != null) || (!pkgMap.isEmpty()); + } + + String checkPolicy(String pkgName) { + // Check for package name seinfo value first. + String seinfoValue = pkgMap.get(pkgName); + if (seinfoValue != null) { + return seinfoValue; + } + + // Return the global seinfo value. + return seinfo; + } + } + private static void flushInstallPolicy() { sSigSeinfo.clear(); - sPackageSeinfo.clear(); + sDefaultSeinfo = null; } /** @@ -87,6 +122,10 @@ public final class SELinuxMMAC { } private static boolean readInstallPolicy(File[] policyFiles) { + // Temp structures to hold the rules while we parse the xml file. + // We add all the rules together once we know there's no structural problems. + HashMap<Signature, Policy> sigSeinfo = new HashMap<Signature, Policy>(); + String defaultSeinfo = null; FileReader policyFile = null; int i = 0; @@ -107,8 +146,6 @@ public final class SELinuxMMAC { Slog.d(TAG, "Using install policy file " + policyFiles[i].getPath()); - flushInstallPolicy(); - try { XmlPullParser parser = Xml.newPullParser(); parser.setInput(policyFile); @@ -138,63 +175,49 @@ public final class SELinuxMMAC { XmlUtils.skipCurrentTag(parser); continue; } - String seinfo = readSeinfoTag(parser); - if (seinfo != null) { - if (DEBUG_POLICY_INSTALL) - Slog.i(TAG, "<signer> tag: (" + cert + ") assigned seinfo=" - + seinfo); - - sSigSeinfo.put(signature, seinfo); + Policy policy = readPolicyTags(parser); + if (policy.isValid()) { + sigSeinfo.put(signature, policy); } } else if ("default".equals(tagName)) { - String seinfo = readSeinfoTag(parser); - if (seinfo != null) { - if (DEBUG_POLICY_INSTALL) - Slog.i(TAG, "<default> tag assigned seinfo=" + seinfo); - - // The 'null' signature is the default seinfo value - sSigSeinfo.put(null, seinfo); - } - } else if ("package".equals(tagName)) { - String pkgName = parser.getAttributeValue(null, "name"); - if (pkgName == null) { - Slog.w(TAG, "<package> without name at " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } - String seinfo = readSeinfoTag(parser); - if (seinfo != null) { - if (DEBUG_POLICY_INSTALL) - Slog.i(TAG, "<package> tag: (" + pkgName + - ") assigned seinfo=" + seinfo); + // Value is null if default tag is absent or seinfo tag is malformed. + defaultSeinfo = readSeinfoTag(parser); + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "<default> tag assigned seinfo=" + defaultSeinfo); - sPackageSeinfo.put(pkgName, seinfo); - } } else { XmlUtils.skipCurrentTag(parser); - continue; } } } catch (XmlPullParserException e) { - Slog.w(TAG, "Got execption parsing ", e); - } catch (IOException e) { - Slog.w(TAG, "Got execption parsing ", e); - } - try { - policyFile.close(); + // An error outside of a stanza means a structural problem + // with the xml file. So ignore it. + Slog.w(TAG, "Got exception parsing ", e); + return false; } catch (IOException e) { - //omit + Slog.w(TAG, "Got exception parsing ", e); + return false; + } finally { + try { + policyFile.close(); + } catch (IOException e) { + //omit + } } + + flushInstallPolicy(); + sSigSeinfo = sigSeinfo; + sDefaultSeinfo = defaultSeinfo; + return true; } - private static String readSeinfoTag(XmlPullParser parser) throws + private static Policy readPolicyTags(XmlPullParser parser) throws IOException, XmlPullParserException { int type; int outerDepth = parser.getDepth(); - String seinfo = null; + Policy policy = new Policy(); while ((type=parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { @@ -205,19 +228,98 @@ public final class SELinuxMMAC { String tagName = parser.getName(); if ("seinfo".equals(tagName)) { - String seinfoValue = parser.getAttributeValue(null, "value"); - if (validateValue(seinfoValue)) { - seinfo = seinfoValue; - } else { - Slog.w(TAG, "<seinfo> without valid value at " + String seinfo = parseSeinfo(parser); + if (seinfo != null) { + policy.putSeinfo(seinfo); + } + XmlUtils.skipCurrentTag(parser); + } else if ("package".equals(tagName)) { + String pkg = parser.getAttributeValue(null, "name"); + if (!validatePackageName(pkg)) { + Slog.w(TAG, "<package> without valid name at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + + String seinfo = readSeinfoTag(parser); + if (seinfo != null) { + policy.putPkg(pkg, seinfo); } + } else { + XmlUtils.skipCurrentTag(parser); + } + } + return policy; + } + + private static String readSeinfoTag(XmlPullParser parser) throws + IOException, XmlPullParserException { + + int type; + int outerDepth = parser.getDepth(); + String seinfo = null; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if ("seinfo".equals(tagName)) { + seinfo = parseSeinfo(parser); } XmlUtils.skipCurrentTag(parser); } return seinfo; } + private static String parseSeinfo(XmlPullParser parser) { + + String seinfoValue = parser.getAttributeValue(null, "value"); + if (!validateValue(seinfoValue)) { + Slog.w(TAG, "<seinfo> without valid value at " + + parser.getPositionDescription()); + seinfoValue = null; + } + return seinfoValue; + } + + /** + * General validation routine for package names. + * Returns a boolean indicating if the passed string + * is a valid android package name. + */ + private static boolean validatePackageName(String name) { + if (name == null) + return false; + + final int N = name.length(); + boolean hasSep = false; + boolean front = true; + for (int i=0; i<N; i++) { + final char c = name.charAt(i); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + front = false; + continue; + } + if (!front) { + if ((c >= '0' && c <= '9') || c == '_') { + continue; + } + } + if (c == '.') { + hasSep = true; + front = true; + continue; + } + return false; + } + return hasSep; + } + /** * General validation routine for tag values. * Returns a boolean indicating if the passed string @@ -245,10 +347,11 @@ public final class SELinuxMMAC { * The label is attached to the ApplicationInfo instance of the package. * @param PackageParser.Package object representing the package * to labeled. - * @return String holding the value of the seinfo label that was assigned. - * Value may be null which indicates no seinfo label was assigned. + * @return boolean which determines whether a non null seinfo label + * was assigned to the package. A null value simply meaning that + * no policy matched. */ - public static void assignSeinfoValue(PackageParser.Package pkg) { + public static boolean assignSeinfoValue(PackageParser.Package pkg) { /* * Non system installed apps should be treated the same. This @@ -264,31 +367,28 @@ public final class SELinuxMMAC { if (s == null) continue; - if (sSigSeinfo.containsKey(s)) { - String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(s); - if (DEBUG_POLICY_INSTALL) - Slog.i(TAG, "package (" + pkg.packageName + - ") labeled with seinfo=" + seinfo); + Policy policy = sSigSeinfo.get(s); + if (policy != null) { + String seinfo = policy.checkPolicy(pkg.packageName); + if (seinfo != null) { + pkg.applicationInfo.seinfo = seinfo; + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "package (" + pkg.packageName + + ") labeled with seinfo=" + seinfo); - return; + return true; + } } } - - // Check for seinfo labeled by package. - if (sPackageSeinfo.containsKey(pkg.packageName)) { - String seinfo = pkg.applicationInfo.seinfo = sPackageSeinfo.get(pkg.packageName); - if (DEBUG_POLICY_INSTALL) - Slog.i(TAG, "package (" + pkg.packageName + - ") labeled with seinfo=" + seinfo); - return; - } } // If we have a default seinfo value then great, otherwise // we set a null object and that is what we started with. - String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(null); + pkg.applicationInfo.seinfo = sDefaultSeinfo; if (DEBUG_POLICY_INSTALL) - Slog.i(TAG, "package (" + pkg.packageName + - ") labeled with seinfo=" + (seinfo == null ? "null" : seinfo)); + Slog.i(TAG, "package (" + pkg.packageName + ") labeled with seinfo=" + + (sDefaultSeinfo == null ? "null" : sDefaultSeinfo)); + + return (sDefaultSeinfo != null); } } diff --git a/services/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 19bfe01..8f18b23 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2679,7 +2679,8 @@ final class Settings { ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle); // Need to create a data directory for all apps under this user. installer.createUserData(ps.name, - UserHandle.getUid(userHandle, ps.appId), userHandle); + UserHandle.getUid(userHandle, ps.appId), userHandle, + ps.pkg.applicationInfo.seinfo); } readDefaultPreferredAppsLPw(service, userHandle); writePackageRestrictionsLPr(userHandle); diff --git a/services/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java index ca1eeea..ca1eeea 100644 --- a/services/java/com/android/server/pm/SharedUserSetting.java +++ b/services/core/java/com/android/server/pm/SharedUserSetting.java diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index c33134a..557b6a3 100644 --- a/services/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -233,9 +233,7 @@ public class UserManagerService extends IUserManager.Stub { } void systemReady() { - final Context context = ActivityThread.systemMain().getSystemContext(); - mUserPackageMonitor.register(context, - null, UserHandle.ALL, false); + mUserPackageMonitor.register(mContext, null, UserHandle.ALL, false); userForeground(UserHandle.USER_OWNER); } diff --git a/services/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 264e2e9..f431b0d 100644 --- a/services/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -16,15 +16,19 @@ package com.android.server.power; +import android.app.ActivityManagerInternal; import android.app.AppOpsManager; + import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import android.app.ActivityManagerNative; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.hardware.input.InputManagerInternal; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; @@ -81,6 +85,8 @@ final class Notifier { private final SuspendBlocker mSuspendBlocker; private final ScreenOnBlocker mScreenOnBlocker; private final WindowManagerPolicy mPolicy; + private final ActivityManagerInternal mActivityManagerInternal; + private final InputManagerInternal mInputManagerInternal; private final NotifierHandler mHandler; private final Intent mScreenOnIntent; @@ -115,6 +121,8 @@ final class Notifier { mSuspendBlocker = suspendBlocker; mScreenOnBlocker = screenOnBlocker; mPolicy = policy; + mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); + mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); mHandler = new NotifierHandler(looper); mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON); @@ -123,6 +131,11 @@ final class Notifier { mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); mScreenOffIntent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); + + // Initialize interactive state for battery stats. + try { + mBatteryStats.noteInteractive(true); + } catch (RemoteException ex) { } } /** @@ -189,120 +202,73 @@ final class Notifier { } /** - * Called when the screen is turned on. - */ - public void onScreenOn() { - if (DEBUG) { - Slog.d(TAG, "onScreenOn"); - } - - try { - mBatteryStats.noteScreenOn(); - } catch (RemoteException ex) { - // Ignore - } - } - - /** - * Called when the screen is turned off. - */ - public void onScreenOff() { - if (DEBUG) { - Slog.d(TAG, "onScreenOff"); - } - - try { - mBatteryStats.noteScreenOff(); - } catch (RemoteException ex) { - // Ignore - } - } - - /** - * Called when the screen changes brightness. - */ - public void onScreenBrightness(int brightness) { - if (DEBUG) { - Slog.d(TAG, "onScreenBrightness: brightness=" + brightness); - } - - try { - mBatteryStats.noteScreenBrightness(brightness); - } catch (RemoteException ex) { - // Ignore - } - } - - /** - * Called when the device is waking up from sleep and the - * display is about to be turned on. + * Notifies that the device is changing interactive state. */ - public void onWakeUpStarted() { + public void onInteractiveStateChangeStarted(boolean interactive, int reason) { if (DEBUG) { - Slog.d(TAG, "onWakeUpStarted"); + Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive + + ", reason=" + reason); } synchronized (mLock) { - if (mActualPowerState != POWER_STATE_AWAKE) { - mActualPowerState = POWER_STATE_AWAKE; - mPendingWakeUpBroadcast = true; - if (!mScreenOnBlockerAcquired) { - mScreenOnBlockerAcquired = true; - mScreenOnBlocker.acquire(); + if (interactive) { + // Waking up... + if (mActualPowerState != POWER_STATE_AWAKE) { + mActualPowerState = POWER_STATE_AWAKE; + mPendingWakeUpBroadcast = true; + if (!mScreenOnBlockerAcquired) { + mScreenOnBlockerAcquired = true; + mScreenOnBlocker.acquire(); + } + updatePendingBroadcastLocked(); } - updatePendingBroadcastLocked(); + } else { + // Going to sleep... + mLastGoToSleepReason = reason; } } - } - - /** - * Called when the device has finished waking up from sleep - * and the display has been turned on. - */ - public void onWakeUpFinished() { - if (DEBUG) { - Slog.d(TAG, "onWakeUpFinished"); - } - } - /** - * Called when the device is going to sleep. - */ - public void onGoToSleepStarted(int reason) { - if (DEBUG) { - Slog.d(TAG, "onGoToSleepStarted"); - } + mInputManagerInternal.setInteractive(interactive); - synchronized (mLock) { - mLastGoToSleepReason = reason; + if (interactive) { + try { + mBatteryStats.noteInteractive(true); + } catch (RemoteException ex) { } } } /** - * Called when the device has finished going to sleep and the - * display has been turned off. - * - * This is a good time to make transitions that we don't want the user to see, - * such as bringing the key guard to focus. There's no guarantee for this, - * however because the user could turn the device on again at any time. - * Some things may need to be protected by other mechanisms that defer screen on. + * Notifies that the device has finished changing interactive state. */ - public void onGoToSleepFinished() { + public void onInteractiveStateChangeFinished(boolean interactive) { if (DEBUG) { - Slog.d(TAG, "onGoToSleepFinished"); + Slog.d(TAG, "onInteractiveChangeFinished"); } synchronized (mLock) { - if (mActualPowerState != POWER_STATE_ASLEEP) { - mActualPowerState = POWER_STATE_ASLEEP; - mPendingGoToSleepBroadcast = true; - if (mUserActivityPending) { - mUserActivityPending = false; - mHandler.removeMessages(MSG_USER_ACTIVITY); + if (!interactive) { + // Finished going to sleep... + // This is a good time to make transitions that we don't want the user to see, + // such as bringing the key guard to focus. There's no guarantee for this, + // however because the user could turn the device on again at any time. + // Some things may need to be protected by other mechanisms that defer screen on. + if (mActualPowerState != POWER_STATE_ASLEEP) { + mActualPowerState = POWER_STATE_ASLEEP; + mPendingGoToSleepBroadcast = true; + if (mUserActivityPending) { + mUserActivityPending = false; + mHandler.removeMessages(MSG_USER_ACTIVITY); + } + updatePendingBroadcastLocked(); } - updatePendingBroadcastLocked(); } } + + if (!interactive) { + try { + mBatteryStats.noteInteractive(false); + } catch (RemoteException ex) { } + } } /** @@ -423,13 +389,8 @@ final class Notifier { EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0); - mPolicy.screenTurningOn(mScreenOnListener); - - try { - ActivityManagerNative.getDefault().wakingUp(); - } catch (RemoteException e) { - // ignore it - } + mPolicy.wakingUp(mScreenOnListener); + mActivityManagerInternal.wakingUp(); if (ActivityManagerNative.isSystemReady()) { mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null, @@ -479,12 +440,8 @@ final class Notifier { EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0); - mPolicy.screenTurnedOff(why); - try { - ActivityManagerNative.getDefault().goingToSleep(); - } catch (RemoteException e) { - // ignore it. - } + mPolicy.goingToSleep(why); + mActivityManagerInternal.goingToSleep(); if (ActivityManagerNative.isSystemReady()) { mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null, diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 134718b..7138c3e 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -20,12 +20,11 @@ import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; import com.android.server.BatteryService; import com.android.server.EventLogTags; -import com.android.server.LightsService; -import com.android.server.TwilightService; +import com.android.server.LocalServices; +import com.android.server.ServiceThread; +import com.android.server.lights.Light; +import com.android.server.lights.LightsManager; import com.android.server.Watchdog; -import com.android.server.am.ActivityManagerService; -import com.android.server.display.DisplayManagerService; -import com.android.server.dreams.DreamManagerService; import android.Manifest; import android.content.BroadcastReceiver; @@ -38,16 +37,18 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.SensorManager; import android.hardware.SystemSensorManager; +import android.hardware.display.DisplayManagerInternal; +import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; import android.net.Uri; import android.os.BatteryManager; import android.os.Binder; import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; import android.os.IPowerManager; import android.os.Looper; import android.os.Message; import android.os.PowerManager; +import android.os.PowerManagerInternal; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; @@ -56,10 +57,12 @@ import android.os.SystemService; import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; +import android.service.dreams.DreamManagerInternal; import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.TimeUtils; +import android.view.Display; import android.view.WindowManagerPolicy; import java.io.FileDescriptor; @@ -72,7 +75,7 @@ import libcore.util.Objects; * The power manager service is responsible for coordinating power management * functions on the device. */ -public final class PowerManagerService extends IPowerManager.Stub +public final class PowerManagerService extends com.android.server.SystemService implements Watchdog.Monitor { private static final String TAG = "PowerManagerService"; @@ -81,7 +84,7 @@ public final class PowerManagerService extends IPowerManager.Stub // Message: Sent when a user activity timeout occurs to update the power state. private static final int MSG_USER_ACTIVITY_TIMEOUT = 1; - // Message: Sent when the device enters or exits a napping or dreaming state. + // Message: Sent when the device enters or exits a dreaming or dozing state. private static final int MSG_SANDMAN = 2; // Message: Sent when the screen on blocker is released. private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3; @@ -115,19 +118,21 @@ public final class PowerManagerService extends IPowerManager.Stub // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp(). // The screen should be off or in the process of being turned off by the display controller. + // The device typically passes through the dozing state first. private static final int WAKEFULNESS_ASLEEP = 0; // Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep(). - // When the user activity timeout expires, the device may start napping or go to sleep. + // When the user activity timeout expires, the device may start dreaming or go to sleep. private static final int WAKEFULNESS_AWAKE = 1; - // Wakefulness: The device is napping. It is deciding whether to dream or go to sleep - // but hasn't gotten around to it yet. It can be awoken by a call to wakeUp(), which - // ends the nap. User activity may brighten the screen but does not end the nap. - private static final int WAKEFULNESS_NAPPING = 2; // Wakefulness: The device is dreaming. It can be awoken by a call to wakeUp(), // which ends the dream. The device goes to sleep when goToSleep() is called, when // the dream ends or when unplugged. // User activity may brighten the screen but does not end the dream. - private static final int WAKEFULNESS_DREAMING = 3; + private static final int WAKEFULNESS_DREAMING = 2; + // Wakefulness: The device is dozing. It is almost asleep but is allowing a special + // low-power "doze" dream to run which keeps the display on but lets the application + // processor be suspended. It can be awoken by a call to wakeUp() which ends the dream. + // The device fully goes to sleep if the dream cannot be started or ends on its own. + private static final int WAKEFULNESS_DOZING = 3; // Summarizes the state of all active wakelocks. private static final int WAKE_LOCK_CPU = 1 << 0; @@ -136,6 +141,7 @@ public final class PowerManagerService extends IPowerManager.Stub private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3; private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4; private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake + private static final int WAKE_LOCK_DOZE = 1 << 6; // Summarizes the user activity state. private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0; @@ -162,26 +168,20 @@ public final class PowerManagerService extends IPowerManager.Stub // Poll interval in milliseconds for watching boot animation finished. private static final int BOOT_ANIMATION_POLL_INTERVAL = 200; - // If the battery level drops by this percentage and the user activity timeout - // has expired, then assume the device is receiving insufficient current to charge - // effectively and terminate the dream. - private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5; - - private Context mContext; - private LightsService mLightsService; + private final Context mContext; + private LightsManager mLightsManager; private BatteryService mBatteryService; - private DisplayManagerService mDisplayManagerService; + private DisplayManagerInternal mDisplayManagerInternal; private IBatteryStats mBatteryStats; private IAppOpsService mAppOps; - private HandlerThread mHandlerThread; + private ServiceThread mHandlerThread; private PowerManagerHandler mHandler; private WindowManagerPolicy mPolicy; private Notifier mNotifier; - private DisplayPowerController mDisplayPowerController; private WirelessChargerDetector mWirelessChargerDetector; private SettingsObserver mSettingsObserver; - private DreamManagerService mDreamManager; - private LightsService.Light mAttentionLight; + private DreamManagerInternal mDreamManager; + private Light mAttentionLight; private final Object mLock = new Object(); @@ -193,6 +193,10 @@ public final class PowerManagerService extends IPowerManager.Stub // This is distinct from the screen power state, which is managed separately. private int mWakefulness; + // True if the sandman has just been summoned for the first time since entering the + // dreaming or dozing state. Indicates whether a new dream should begin. + private boolean mSandmanSummoned; + // True if MSG_SANDMAN has been scheduled. private boolean mSandmanScheduled; @@ -206,6 +210,10 @@ public final class PowerManagerService extends IPowerManager.Stub // A bitfield that summarizes the state of all active wakelocks. private int mWakeLockSummary; + // True if the device is in an interactive state. + private boolean mInteractive; + private boolean mInteractiveChanging; + // If true, instructs the display controller to wait for the proximity sensor to // go negative before turning the screen on. private boolean mRequestWaitForNegativeProximity; @@ -214,11 +222,6 @@ public final class PowerManagerService extends IPowerManager.Stub private long mLastWakeTime; private long mLastSleepTime; - // True if we need to send a wake up or go to sleep finished notification - // when the display is ready. - private boolean mSendWakeUpFinishedNotificationWhenReady; - private boolean mSendGoToSleepFinishedNotificationWhenReady; - // Timestamp of the last call to user activity. private long mLastUserActivityTime; private long mLastUserActivityTimeNoChangeLights; @@ -231,9 +234,6 @@ public final class PowerManagerService extends IPowerManager.Stub // requested because it is updated asynchronously by the display power controller. private final DisplayPowerRequest mDisplayPowerRequest = new DisplayPowerRequest(); - // The time the screen was last turned off, in elapsedRealtime() timebase. - private long mLastScreenOffEventElapsedRealTime; - // True if the display power state has been fully applied, which means the display // is actually on or actually off or whatever was requested. private boolean mDisplayReady; @@ -257,15 +257,20 @@ public final class PowerManagerService extends IPowerManager.Stub // screen is coming up. private final ScreenOnBlockerImpl mScreenOnBlocker; - // The display blanker used to turn the screen on or off. - private final DisplayBlankerImpl mDisplayBlanker; - // True if systemReady() has been called. private boolean mSystemReady; // True if boot completed occurred. We keep the screen on until this happens. private boolean mBootCompleted; + // True if auto-suspend mode is enabled. + // Refer to autosuspend.h. + private boolean mHalAutoSuspendModeEnabled; + + // True if interactive mode is enabled. + // Refer to power.h. + private boolean mHalInteractiveModeEnabled; + // True if the device is plugged into a power source. private boolean mIsPowered; @@ -283,6 +288,12 @@ public final class PowerManagerService extends IPowerManager.Stub // The current dock state. private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + // True to decouple auto-suspend mode from the display state. + private boolean mDecoupleHalAutoSuspendModeFromDisplayConfig; + + // True to decouple interactive mode from the display state. + private boolean mDecoupleHalInteractiveModeFromDisplayConfig; + // True if the device should wake up when plugged or unplugged. private boolean mWakeUpWhenPluggedOrUnpluggedConfig; @@ -301,6 +312,22 @@ public final class PowerManagerService extends IPowerManager.Stub // Default value for dreams activate-on-dock private boolean mDreamsActivatedOnDockByDefaultConfig; + // True if dreams can run while not plugged in. + private boolean mDreamsEnabledOnBatteryConfig; + + // Minimum battery level to allow dreaming when powered. + // Use -1 to disable this safety feature. + private int mDreamsBatteryLevelMinimumWhenPoweredConfig; + + // Minimum battery level to allow dreaming when not powered. + // Use -1 to disable this safety feature. + private int mDreamsBatteryLevelMinimumWhenNotPoweredConfig; + + // If the battery level drops by this percentage and the user activity timeout + // has expired, then assume the device is receiving insufficient current to charge + // effectively and terminate the dream. Use -1 to disable this safety feature. + private int mDreamsBatteryLevelDrainCutoffConfig; + // True if dreams are enabled by the user. private boolean mDreamsEnabledSetting; @@ -370,69 +397,71 @@ public final class PowerManagerService extends IPowerManager.Stub private native void nativeInit(); - private static native void nativeSetPowerState(boolean screenOn, boolean screenBright); private static native void nativeAcquireSuspendBlocker(String name); private static native void nativeReleaseSuspendBlocker(String name); private static native void nativeSetInteractive(boolean enable); private static native void nativeSetAutoSuspend(boolean enable); - public PowerManagerService() { + public PowerManagerService(Context context) { + super(context); + mContext = context; synchronized (mLock) { mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks"); mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display"); mDisplaySuspendBlocker.acquire(); mHoldingDisplaySuspendBlocker = true; + mHalAutoSuspendModeEnabled = false; + mHalInteractiveModeEnabled = true; mScreenOnBlocker = new ScreenOnBlockerImpl(); - mDisplayBlanker = new DisplayBlankerImpl(); mWakefulness = WAKEFULNESS_AWAKE; + mInteractive = true; + + nativeInit(); + nativeSetAutoSuspend(false); + nativeSetInteractive(true); } + } - nativeInit(); - nativeSetPowerState(true, true); + @Override + public void onStart() { + publishBinderService(Context.POWER_SERVICE, new BinderService()); + publishLocalService(PowerManagerInternal.class, new LocalService()); } /** * Initialize the power manager. * Must be called before any other functions within the power manager are called. */ - public void init(Context context, LightsService ls, - ActivityManagerService am, BatteryService bs, IBatteryStats bss, - IAppOpsService appOps, DisplayManagerService dm) { - mContext = context; - mLightsService = ls; + public void init(LightsManager ls, + BatteryService bs, IBatteryStats bss, + IAppOpsService appOps) { + mLightsManager = ls; mBatteryService = bs; mBatteryStats = bss; mAppOps = appOps; - mDisplayManagerService = dm; - mHandlerThread = new HandlerThread(TAG); + mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class); + mHandlerThread = new ServiceThread(TAG, + Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/); mHandlerThread.start(); mHandler = new PowerManagerHandler(mHandlerThread.getLooper()); Watchdog.getInstance().addMonitor(this); - Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName()); - - // Forcibly turn the screen on at boot so that it is in a known power state. - // We do this in init() rather than in the constructor because setting the - // screen state requires a call into surface flinger which then needs to call back - // into the activity manager to check permissions. Unfortunately the - // activity manager is not running when the constructor is called, so we - // have to defer setting the screen state until this point. - mDisplayBlanker.unblankAllDisplays(); + Watchdog.getInstance().addThread(mHandler); } - public void setPolicy(WindowManagerPolicy policy) { + void setPolicy(WindowManagerPolicy policy) { synchronized (mLock) { mPolicy = policy; } } - public void systemReady(TwilightService twilight, DreamManagerService dreamManager) { + public void systemReady() { synchronized (mLock) { mSystemReady = true; - mDreamManager = dreamManager; + mDreamManager = LocalServices.getService(DreamManagerInternal.class); - PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting(); mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting(); mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting(); @@ -445,18 +474,15 @@ public final class PowerManagerService extends IPowerManager.Stub mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"), mScreenOnBlocker, mPolicy); - // The display power controller runs on the power manager service's - // own handler thread to ensure timely operation. - mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(), - mContext, mNotifier, mLightsService, twilight, sensorManager, - mDisplayManagerService, mDisplaySuspendBlocker, mDisplayBlanker, - mDisplayPowerControllerCallbacks, mHandler); - mWirelessChargerDetector = new WirelessChargerDetector(sensorManager, createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"), mHandler); mSettingsObserver = new SettingsObserver(mHandler); - mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION); + mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION); + + // Initialize display power management. + mDisplayManagerInternal.initPowerManagement( + mDisplayPowerCallbacks, mHandler, sensorManager); // Register for broadcasts from other components of the system. IntentFilter filter = new IntentFilter(); @@ -515,6 +541,10 @@ public final class PowerManagerService extends IPowerManager.Stub private void readConfigurationLocked() { final Resources resources = mContext.getResources(); + mDecoupleHalAutoSuspendModeFromDisplayConfig = resources.getBoolean( + com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay); + mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean( + com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay); mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean( com.android.internal.R.bool.config_unplugTurnsOnScreen); mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean( @@ -527,6 +557,14 @@ public final class PowerManagerService extends IPowerManager.Stub com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault); mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean( com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault); + mDreamsEnabledOnBatteryConfig = resources.getBoolean( + com.android.internal.R.bool.config_dreamsEnabledOnBattery); + mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger( + com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenPowered); + mDreamsBatteryLevelMinimumWhenNotPoweredConfig = resources.getInteger( + com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenNotPowered); + mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger( + com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff); } private void updateSettingsLocked() { @@ -579,41 +617,6 @@ public final class PowerManagerService extends IPowerManager.Stub updatePowerStateLocked(); } - @Override // Binder call - public void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName, - int uid) { - acquireWakeLock(lock, flags, tag, packageName, new WorkSource(uid)); - } - - @Override // Binder call - public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, - WorkSource ws) { - if (lock == null) { - throw new IllegalArgumentException("lock must not be null"); - } - if (packageName == null) { - throw new IllegalArgumentException("packageName must not be null"); - } - PowerManager.validateWakeLockParameters(flags, tag); - - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); - if (ws != null && ws.size() != 0) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.UPDATE_DEVICE_STATS, null); - } else { - ws = null; - } - - final int uid = Binder.getCallingUid(); - final int pid = Binder.getCallingPid(); - final long ident = Binder.clearCallingIdentity(); - try { - acquireWakeLockInternal(lock, flags, tag, packageName, ws, uid, pid); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName, WorkSource ws, int uid, int pid) { synchronized (mLock) { @@ -668,22 +671,6 @@ public final class PowerManagerService extends IPowerManager.Stub } } - @Override // Binder call - public void releaseWakeLock(IBinder lock, int flags) { - if (lock == null) { - throw new IllegalArgumentException("lock must not be null"); - } - - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); - - final long ident = Binder.clearCallingIdentity(); - try { - releaseWakeLockInternal(lock, flags); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void releaseWakeLockInternal(IBinder lock, int flags) { synchronized (mLock) { int index = findWakeLockIndexLocked(lock); @@ -746,43 +733,6 @@ public final class PowerManagerService extends IPowerManager.Stub } } - @Override // Binder call - public void updateWakeLockUids(IBinder lock, int[] uids) { - WorkSource ws = null; - - if (uids != null) { - ws = new WorkSource(); - // XXX should WorkSource have a way to set uids as an int[] instead of adding them - // one at a time? - for (int i = 0; i < uids.length; i++) { - ws.add(uids[i]); - } - } - updateWakeLockWorkSource(lock, ws); - } - - @Override // Binder call - public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) { - if (lock == null) { - throw new IllegalArgumentException("lock must not be null"); - } - - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); - if (ws != null && ws.size() != 0) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.UPDATE_DEVICE_STATS, null); - } else { - ws = null; - } - - final long ident = Binder.clearCallingIdentity(); - try { - updateWakeLockWorkSourceInternal(lock, ws); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void updateWakeLockWorkSourceInternal(IBinder lock, WorkSource ws) { synchronized (mLock) { int index = findWakeLockIndexLocked(lock); @@ -834,16 +784,6 @@ public final class PowerManagerService extends IPowerManager.Stub } } - @Override // Binder call - public boolean isWakeLockLevelSupported(int level) { - final long ident = Binder.clearCallingIdentity(); - try { - return isWakeLockLevelSupportedInternal(level); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - @SuppressWarnings("deprecation") private boolean isWakeLockLevelSupportedInternal(int level) { synchronized (mLock) { @@ -852,10 +792,11 @@ public final class PowerManagerService extends IPowerManager.Stub case PowerManager.SCREEN_DIM_WAKE_LOCK: case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: case PowerManager.FULL_WAKE_LOCK: + case PowerManager.DOZE_WAKE_LOCK: return true; case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: - return mSystemReady && mDisplayPowerController.isProximitySensorAvailable(); + return mSystemReady && mDisplayManagerInternal.isProximitySensorAvailable(); default: return false; @@ -863,40 +804,6 @@ public final class PowerManagerService extends IPowerManager.Stub } } - @Override // Binder call - public void userActivity(long eventTime, int event, int flags) { - final long now = SystemClock.uptimeMillis(); - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER) - != PackageManager.PERMISSION_GRANTED) { - // Once upon a time applications could call userActivity(). - // Now we require the DEVICE_POWER permission. Log a warning and ignore the - // request instead of throwing a SecurityException so we don't break old apps. - synchronized (mLock) { - if (now >= mLastWarningAboutUserActivityPermission + (5 * 60 * 1000)) { - mLastWarningAboutUserActivityPermission = now; - Slog.w(TAG, "Ignoring call to PowerManager.userActivity() because the " - + "caller does not have DEVICE_POWER permission. " - + "Please fix your app! " - + " pid=" + Binder.getCallingPid() - + " uid=" + Binder.getCallingUid()); - } - } - return; - } - - if (eventTime > SystemClock.uptimeMillis()) { - throw new IllegalArgumentException("event time must not be in the future"); - } - - final int uid = Binder.getCallingUid(); - final long ident = Binder.clearCallingIdentity(); - try { - userActivityInternal(eventTime, event, flags, uid); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - // Called from native code. private void userActivityFromNative(long eventTime, int event, int flags) { userActivityInternal(eventTime, event, flags, Process.SYSTEM_UID); @@ -918,7 +825,8 @@ public final class PowerManagerService extends IPowerManager.Stub } if (eventTime < mLastSleepTime || eventTime < mLastWakeTime - || mWakefulness == WAKEFULNESS_ASLEEP || !mBootCompleted || !mSystemReady) { + || mWakefulness == WAKEFULNESS_ASLEEP || mWakefulness == WAKEFULNESS_DOZING + || !mBootCompleted || !mSystemReady) { return false; } @@ -941,27 +849,6 @@ public final class PowerManagerService extends IPowerManager.Stub return false; } - @Override // Binder call - public void wakeUp(long eventTime) { - if (eventTime > SystemClock.uptimeMillis()) { - throw new IllegalArgumentException("event time must not be in the future"); - } - - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - final long ident = Binder.clearCallingIdentity(); - try { - wakeUpInternal(eventTime); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - // Called from native code. - private void wakeUpFromNative(long eventTime) { - wakeUpInternal(eventTime); - } - private void wakeUpInternal(long eventTime) { synchronized (mLock) { if (wakeUpNoUpdateLocked(eventTime)) { @@ -983,48 +870,25 @@ public final class PowerManagerService extends IPowerManager.Stub switch (mWakefulness) { case WAKEFULNESS_ASLEEP: Slog.i(TAG, "Waking up from sleep..."); - sendPendingNotificationsLocked(); - mNotifier.onWakeUpStarted(); - mSendWakeUpFinishedNotificationWhenReady = true; break; case WAKEFULNESS_DREAMING: Slog.i(TAG, "Waking up from dream..."); break; - case WAKEFULNESS_NAPPING: - Slog.i(TAG, "Waking up from nap..."); + case WAKEFULNESS_DOZING: + Slog.i(TAG, "Waking up from dozing..."); break; } mLastWakeTime = eventTime; - mWakefulness = WAKEFULNESS_AWAKE; mDirty |= DIRTY_WAKEFULNESS; + mWakefulness = WAKEFULNESS_AWAKE; + setInteractiveStateLocked(true, 0); userActivityNoUpdateLocked( eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); return true; } - @Override // Binder call - public void goToSleep(long eventTime, int reason) { - if (eventTime > SystemClock.uptimeMillis()) { - throw new IllegalArgumentException("event time must not be in the future"); - } - - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - final long ident = Binder.clearCallingIdentity(); - try { - goToSleepInternal(eventTime, reason); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - // Called from native code. - private void goToSleepFromNative(long eventTime, int reason) { - goToSleepInternal(eventTime, reason); - } - private void goToSleepInternal(long eventTime, int reason) { synchronized (mLock) { if (goToSleepNoUpdateLocked(eventTime, reason)) { @@ -1033,13 +897,17 @@ public final class PowerManagerService extends IPowerManager.Stub } } + // This method is called goToSleep for historical reasons but we actually start + // dozing before really going to sleep. @SuppressWarnings("deprecation") private boolean goToSleepNoUpdateLocked(long eventTime, int reason) { if (DEBUG_SPEW) { Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason); } - if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP + if (eventTime < mLastWakeTime + || mWakefulness == WAKEFULNESS_ASLEEP + || mWakefulness == WAKEFULNESS_DOZING || !mBootCompleted || !mSystemReady) { return false; } @@ -1057,13 +925,11 @@ public final class PowerManagerService extends IPowerManager.Stub break; } - sendPendingNotificationsLocked(); - mNotifier.onGoToSleepStarted(reason); - mSendGoToSleepFinishedNotificationWhenReady = true; - mLastSleepTime = eventTime; mDirty |= DIRTY_WAKEFULNESS; - mWakefulness = WAKEFULNESS_ASLEEP; + mWakefulness = WAKEFULNESS_DOZING; + mSandmanSummoned = true; + setInteractiveStateLocked(false, reason); // Report the number of wake locks that will be cleared by going to sleep. int numWakeLocksCleared = 0; @@ -1082,22 +948,6 @@ public final class PowerManagerService extends IPowerManager.Stub return true; } - @Override // Binder call - public void nap(long eventTime) { - if (eventTime > SystemClock.uptimeMillis()) { - throw new IllegalArgumentException("event time must not be in the future"); - } - - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - final long ident = Binder.clearCallingIdentity(); - try { - napInternal(eventTime); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void napInternal(long eventTime) { synchronized (mLock) { if (napNoUpdateLocked(eventTime)) { @@ -1119,10 +969,48 @@ public final class PowerManagerService extends IPowerManager.Stub Slog.i(TAG, "Nap time..."); mDirty |= DIRTY_WAKEFULNESS; - mWakefulness = WAKEFULNESS_NAPPING; + mWakefulness = WAKEFULNESS_DREAMING; + mSandmanSummoned = true; + setInteractiveStateLocked(true, 0); + return true; + } + + // Done dozing, drop everything and go to sleep. + private boolean reallyGoToSleepNoUpdateLocked(long eventTime) { + if (DEBUG_SPEW) { + Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime); + } + + if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP + || !mBootCompleted || !mSystemReady) { + return false; + } + + Slog.i(TAG, "Sleeping..."); + + mDirty |= DIRTY_WAKEFULNESS; + mWakefulness = WAKEFULNESS_ASLEEP; + setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT); return true; } + private void setInteractiveStateLocked(boolean interactive, int reason) { + if (mInteractive != interactive) { + finishInteractiveStateChangeLocked(); + + mInteractive = interactive; + mInteractiveChanging = true; + mNotifier.onInteractiveStateChangeStarted(interactive, reason); + } + } + + private void finishInteractiveStateChangeLocked() { + if (mInteractiveChanging) { + mNotifier.onInteractiveStateChangeFinished(mInteractive); + mInteractiveChanging = false; + } + } + /** * Updates the global power state based on dirty bits recorded in mDirty. * @@ -1166,7 +1054,7 @@ public final class PowerManagerService extends IPowerManager.Stub // Phase 3: Send notifications, if needed. if (mDisplayReady) { - sendPendingNotificationsLocked(); + finishInteractiveStateChangeLocked(); } // Phase 4: Update suspend blocker. @@ -1175,17 +1063,6 @@ public final class PowerManagerService extends IPowerManager.Stub updateSuspendBlockerLocked(); } - private void sendPendingNotificationsLocked() { - if (mSendWakeUpFinishedNotificationWhenReady) { - mSendWakeUpFinishedNotificationWhenReady = false; - mNotifier.onWakeUpFinished(); - } - if (mSendGoToSleepFinishedNotificationWhenReady) { - mSendGoToSleepFinishedNotificationWhenReady = false; - mNotifier.onGoToSleepFinished(); - } - } - /** * Updates the value of mIsPowered. * Sets DIRTY_IS_POWERED if a change occurred. @@ -1198,7 +1075,7 @@ public final class PowerManagerService extends IPowerManager.Stub mPlugType = mBatteryService.getPlugType(); mBatteryLevel = mBatteryService.getBatteryLevel(); - if (DEBUG) { + if (DEBUG_SPEW) { Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered + ", mIsPowered=" + mIsPowered + ", oldPlugType=" + oldPlugType @@ -1258,8 +1135,7 @@ public final class PowerManagerService extends IPowerManager.Stub } // If already dreaming and becoming powered, then don't wake. - if (mIsPowered && (mWakefulness == WAKEFULNESS_NAPPING - || mWakefulness == WAKEFULNESS_DREAMING)) { + if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) { return false; } @@ -1306,38 +1182,45 @@ public final class PowerManagerService extends IPowerManager.Stub mWakeLockSummary |= WAKE_LOCK_CPU; break; case PowerManager.FULL_WAKE_LOCK: - if (mWakefulness != WAKEFULNESS_ASLEEP) { - mWakeLockSummary |= WAKE_LOCK_CPU - | WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT; - if (mWakefulness == WAKEFULNESS_AWAKE) { - mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE; - } - } + mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT; break; case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: - if (mWakefulness != WAKEFULNESS_ASLEEP) { - mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT; - if (mWakefulness == WAKEFULNESS_AWAKE) { - mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE; - } - } + mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT; break; case PowerManager.SCREEN_DIM_WAKE_LOCK: - if (mWakefulness != WAKEFULNESS_ASLEEP) { - mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM; - if (mWakefulness == WAKEFULNESS_AWAKE) { - mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE; - } - } + mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM; break; case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: - if (mWakefulness != WAKEFULNESS_ASLEEP) { - mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF; - } + mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF; + break; + case PowerManager.DOZE_WAKE_LOCK: + mWakeLockSummary |= WAKE_LOCK_DOZE; break; } } + // Cancel wake locks that make no sense based on the current state. + if (mWakefulness != WAKEFULNESS_DOZING) { + mWakeLockSummary &= ~WAKE_LOCK_DOZE; + } + if (mWakefulness == WAKEFULNESS_ASLEEP + || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) { + mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM + | WAKE_LOCK_BUTTON_BRIGHT); + if (mWakefulness == WAKEFULNESS_ASLEEP) { + mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF; + } + } + + // Infer implied wake locks where necessary based on the current state. + if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) { + if (mWakefulness == WAKEFULNESS_AWAKE) { + mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE; + } else if (mWakefulness == WAKEFULNESS_DREAMING) { + mWakeLockSummary |= WAKE_LOCK_CPU; + } + } + if (DEBUG_SPEW) { Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness=" + wakefulnessToString(mWakefulness) @@ -1355,11 +1238,14 @@ public final class PowerManagerService extends IPowerManager.Stub */ private void updateUserActivitySummaryLocked(long now, int dirty) { // Update the status of the user activity timeout timer. - if ((dirty & (DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) { + if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY + | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) { mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT); long nextTimeout = 0; - if (mWakefulness != WAKEFULNESS_ASLEEP) { + if (mWakefulness == WAKEFULNESS_AWAKE + || mWakefulness == WAKEFULNESS_DREAMING + || mWakefulness == WAKEFULNESS_DOZING) { final int screenOffTimeout = getScreenOffTimeoutLocked(); final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout); @@ -1380,8 +1266,7 @@ public final class PowerManagerService extends IPowerManager.Stub && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) { nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout; if (now < nextTimeout - && mDisplayPowerRequest.screenState - != DisplayPowerRequest.SCREEN_STATE_OFF) { + && mDisplayPowerRequest.wantScreenOnNormal()) { mUserActivitySummary = mDisplayPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT ? USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM; @@ -1443,7 +1328,7 @@ public final class PowerManagerService extends IPowerManager.Stub /** * Updates the wakefulness of the device. * - * This is the function that decides whether the device should start napping + * This is the function that decides whether the device should start dreaming * based on the current wake locks and user activity state. It may modify mDirty * if the wakefulness changes. * @@ -1532,7 +1417,7 @@ public final class PowerManagerService extends IPowerManager.Stub } /** - * Called when the device enters or exits a napping or dreaming state. + * Called when the device enters or exits a dreaming or dozing state. * * We do this asynchronously because we must call out of the power manager to start * the dream and we don't want to hold our lock while doing so. There is a risk that @@ -1540,46 +1425,60 @@ public final class PowerManagerService extends IPowerManager.Stub */ private void handleSandman() { // runs on handler thread // Handle preconditions. - boolean startDreaming = false; + final boolean startDreaming; + final int wakefulness; synchronized (mLock) { mSandmanScheduled = false; - boolean canDream = canDreamLocked(); - if (DEBUG_SPEW) { - Slog.d(TAG, "handleSandman: canDream=" + canDream - + ", mWakefulness=" + wakefulnessToString(mWakefulness)); - } - - if (canDream && mWakefulness == WAKEFULNESS_NAPPING) { - startDreaming = true; + wakefulness = mWakefulness; + if (mSandmanSummoned) { + startDreaming = ((wakefulness == WAKEFULNESS_DREAMING && canDreamLocked()) + || wakefulness == WAKEFULNESS_DOZING); + mSandmanSummoned = false; + } else { + startDreaming = false; } } // Start dreaming if needed. // We only control the dream on the handler thread, so we don't need to worry about // concurrent attempts to start or stop the dream. - boolean isDreaming = false; + final boolean isDreaming; if (mDreamManager != null) { + // Restart the dream whenever the sandman is summoned. if (startDreaming) { - mDreamManager.startDream(); + mDreamManager.stopDream(); + mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING); } isDreaming = mDreamManager.isDreaming(); + } else { + isDreaming = false; } // Update dream state. - // We might need to stop the dream again if the preconditions changed. - boolean continueDreaming = false; synchronized (mLock) { - if (isDreaming && canDreamLocked()) { - if (mWakefulness == WAKEFULNESS_NAPPING) { - mWakefulness = WAKEFULNESS_DREAMING; - mDirty |= DIRTY_WAKEFULNESS; - mBatteryLevelWhenDreamStarted = mBatteryLevel; - updatePowerStateLocked(); - continueDreaming = true; - } else if (mWakefulness == WAKEFULNESS_DREAMING) { - if (!isBeingKeptAwakeLocked() + // Remember the initial battery level when the dream started. + if (startDreaming && isDreaming) { + mBatteryLevelWhenDreamStarted = mBatteryLevel; + if (wakefulness == WAKEFULNESS_DOZING) { + Slog.i(TAG, "Dozing..."); + } else { + Slog.i(TAG, "Dreaming..."); + } + } + + // If preconditions changed, wait for the next iteration to determine + // whether the dream should continue (or be restarted). + if (mSandmanSummoned || mWakefulness != wakefulness) { + return; // wait for next cycle + } + + // Determine whether the dream should continue. + if (wakefulness == WAKEFULNESS_DREAMING) { + if (isDreaming && canDreamLocked()) { + if (mDreamsBatteryLevelDrainCutoffConfig >= 0 && mBatteryLevel < mBatteryLevelWhenDreamStarted - - DREAM_BATTERY_LEVEL_DRAIN_CUTOFF) { + - mDreamsBatteryLevelDrainCutoffConfig + && !isBeingKeptAwakeLocked()) { // If the user activity timeout expired and the battery appears // to be draining faster than it is charging then stop dreaming // and go to sleep. @@ -1589,53 +1488,64 @@ public final class PowerManagerService extends IPowerManager.Stub + mBatteryLevelWhenDreamStarted + "%. " + "Battery level now: " + mBatteryLevel + "%."); } else { - continueDreaming = true; + return; // continue dreaming } } - } - if (!continueDreaming) { - handleDreamFinishedLocked(); + + // Dream has ended or will be stopped. Update the power state. + if (isItBedTimeYetLocked()) { + goToSleepNoUpdateLocked(SystemClock.uptimeMillis(), + PowerManager.GO_TO_SLEEP_REASON_TIMEOUT); + updatePowerStateLocked(); + } else { + wakeUpNoUpdateLocked(SystemClock.uptimeMillis()); + updatePowerStateLocked(); + } + } else if (wakefulness == WAKEFULNESS_DOZING) { + if (isDreaming) { + return; // continue dozing + } + + // Doze has ended or will be stopped. Update the power state. + reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis()); + updatePowerStateLocked(); } } - // Stop dreaming if needed. - // It's possible that something else changed to make us need to start the dream again. - // If so, then the power manager will have posted another message to the handler - // to take care of it later. - if (mDreamManager != null) { - if (!continueDreaming) { - mDreamManager.stopDream(); - } + // Stop dream. + if (isDreaming) { + mDreamManager.stopDream(); } } /** - * Returns true if the device is allowed to dream in its current state - * assuming that it is currently napping or dreaming. + * Returns true if the device is allowed to dream in its current state. + * This function is not called when dozing. */ private boolean canDreamLocked() { - return mDreamsSupportedConfig - && mDreamsEnabledSetting - && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF - && mBootCompleted - && (mIsPowered || isBeingKeptAwakeLocked()); - } - - /** - * Called when a dream is ending to figure out what to do next. - */ - private void handleDreamFinishedLocked() { - if (mWakefulness == WAKEFULNESS_NAPPING - || mWakefulness == WAKEFULNESS_DREAMING) { - if (isItBedTimeYetLocked()) { - goToSleepNoUpdateLocked(SystemClock.uptimeMillis(), - PowerManager.GO_TO_SLEEP_REASON_TIMEOUT); - updatePowerStateLocked(); - } else { - wakeUpNoUpdateLocked(SystemClock.uptimeMillis()); - updatePowerStateLocked(); + if (mWakefulness != WAKEFULNESS_DREAMING + || !mDreamsSupportedConfig + || !mDreamsEnabledSetting + || !mDisplayPowerRequest.wantScreenOnNormal() + || !mBootCompleted) { + return false; + } + if (!isBeingKeptAwakeLocked()) { + if (!mIsPowered && !mDreamsEnabledOnBatteryConfig) { + return false; + } + if (!mIsPowered + && mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0 + && mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) { + return false; + } + if (mIsPowered + && mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0 + && mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) { + return false; } } + return true; } private void handleScreenOnBlockerReleased() { @@ -1657,19 +1567,8 @@ public final class PowerManagerService extends IPowerManager.Stub if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) { - int newScreenState = getDesiredScreenPowerStateLocked(); - if (newScreenState != mDisplayPowerRequest.screenState) { - if (newScreenState == DisplayPowerRequest.SCREEN_STATE_OFF - && mDisplayPowerRequest.screenState - != DisplayPowerRequest.SCREEN_STATE_OFF) { - mLastScreenOffEventElapsedRealTime = SystemClock.elapsedRealtime(); - } - - mDisplayPowerRequest.screenState = newScreenState; - nativeSetPowerState( - newScreenState != DisplayPowerRequest.SCREEN_STATE_OFF, - newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT); - } + final int newScreenState = getDesiredScreenPowerStateLocked(); + mDisplayPowerRequest.screenState = newScreenState; int screenBrightness = mScreenBrightnessSettingDefault; float screenAutoBrightnessAdjustment = 0.0f; @@ -1707,7 +1606,7 @@ public final class PowerManagerService extends IPowerManager.Stub mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld(); - mDisplayReady = mDisplayPowerController.requestPowerState(mDisplayPowerRequest, + mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest, mRequestWaitForNegativeProximity); mRequestWaitForNegativeProximity = false; @@ -1736,6 +1635,10 @@ public final class PowerManagerService extends IPowerManager.Stub return DisplayPowerRequest.SCREEN_STATE_OFF; } + if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) { + return DisplayPowerRequest.SCREEN_STATE_DOZE; + } + if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0 || (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0 || !mBootCompleted) { @@ -1745,8 +1648,10 @@ public final class PowerManagerService extends IPowerManager.Stub return DisplayPowerRequest.SCREEN_STATE_DIM; } - private final DisplayPowerController.Callbacks mDisplayPowerControllerCallbacks = - new DisplayPowerController.Callbacks() { + private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks = + new DisplayManagerInternal.DisplayPowerCallbacks() { + private int mDisplayState = Display.STATE_UNKNOWN; + @Override public void onStateChanged() { synchronized (mLock) { @@ -1774,6 +1679,50 @@ public final class PowerManagerService extends IPowerManager.Stub updatePowerStateLocked(); } } + + @Override + public void onDisplayStateChange(int state) { + // This method is only needed to support legacy display blanking behavior + // where the display's power state is coupled to suspend or to the power HAL. + // The order of operations matters here. + synchronized (mLock) { + if (mDisplayState != state) { + mDisplayState = state; + if (state == Display.STATE_OFF) { + if (!mDecoupleHalInteractiveModeFromDisplayConfig) { + setHalInteractiveModeLocked(false); + } + if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) { + setHalAutoSuspendModeLocked(true); + } + } else { + if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) { + setHalAutoSuspendModeLocked(false); + } + if (!mDecoupleHalInteractiveModeFromDisplayConfig) { + setHalInteractiveModeLocked(true); + } + } + } + } + } + + @Override + public void acquireSuspendBlocker() { + mDisplaySuspendBlocker.acquire(); + } + + @Override + public void releaseSuspendBlocker() { + mDisplaySuspendBlocker.release(); + } + + @Override + public String toString() { + synchronized (this) { + return "state=" + Display.stateToString(mDisplayState); + } + } }; private boolean shouldUseProximitySensorLocked() { @@ -1787,7 +1736,18 @@ public final class PowerManagerService extends IPowerManager.Stub */ private void updateSuspendBlockerLocked() { final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0); - final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker(); + final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked(); + final boolean autoSuspend = !needDisplaySuspendBlocker; + + // Disable auto-suspend if needed. + if (!autoSuspend) { + if (mDecoupleHalAutoSuspendModeFromDisplayConfig) { + setHalAutoSuspendModeLocked(false); + } + if (mDecoupleHalInteractiveModeFromDisplayConfig) { + setHalInteractiveModeLocked(true); + } + } // First acquire suspend blockers if needed. if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) { @@ -1808,17 +1768,27 @@ public final class PowerManagerService extends IPowerManager.Stub mDisplaySuspendBlocker.release(); mHoldingDisplaySuspendBlocker = false; } + + // Enable auto-suspend if needed. + if (autoSuspend) { + if (mDecoupleHalInteractiveModeFromDisplayConfig) { + setHalInteractiveModeLocked(false); + } + if (mDecoupleHalAutoSuspendModeFromDisplayConfig) { + setHalAutoSuspendModeLocked(true); + } + } } /** * Return true if we must keep a suspend blocker active on behalf of the display. * We do so if the screen is on or is in transition between states. */ - private boolean needDisplaySuspendBlocker() { + private boolean needDisplaySuspendBlockerLocked() { if (!mDisplayReady) { return true; } - if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) { + if (mDisplayPowerRequest.wantScreenOnNormal()) { // If we asked for the screen to be on but it is off due to the proximity // sensor then we may suspend but only if the configuration allows it. // On some hardware it may not be safe to suspend because the proximity @@ -1828,23 +1798,33 @@ public final class PowerManagerService extends IPowerManager.Stub return true; } } + // Let the system suspend if the screen is off or dozing. return false; } - @Override // Binder call - public boolean isScreenOn() { - final long ident = Binder.clearCallingIdentity(); - try { - return isScreenOnInternal(); - } finally { - Binder.restoreCallingIdentity(ident); + private void setHalAutoSuspendModeLocked(boolean enable) { + if (enable != mHalAutoSuspendModeEnabled) { + if (DEBUG) { + Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable); + } + mHalAutoSuspendModeEnabled = enable; + nativeSetAutoSuspend(enable); } } - private boolean isScreenOnInternal() { + private void setHalInteractiveModeLocked(boolean enable) { + if (enable != mHalInteractiveModeEnabled) { + if (DEBUG) { + Slog.d(TAG, "Setting HAL interactive mode to " + enable); + } + mHalInteractiveModeEnabled = enable; + nativeSetInteractive(enable); + } + } + + private boolean isInteractiveInternal() { synchronized (mLock) { - return !mSystemReady - || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF; + return mInteractive; } } @@ -1885,43 +1865,6 @@ public final class PowerManagerService extends IPowerManager.Stub updatePowerStateLocked(); } - /** - * Reboots the device. - * - * @param confirm If true, shows a reboot confirmation dialog. - * @param reason The reason for the reboot, or null if none. - * @param wait If true, this call waits for the reboot to complete and does not return. - */ - @Override // Binder call - public void reboot(boolean confirm, String reason, boolean wait) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null); - - final long ident = Binder.clearCallingIdentity(); - try { - shutdownOrRebootInternal(false, confirm, reason, wait); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - /** - * Shuts down the device. - * - * @param confirm If true, shows a shutdown confirmation dialog. - * @param wait If true, this call waits for the shutdown to complete and does not return. - */ - @Override // Binder call - public void shutdown(boolean confirm, boolean wait) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null); - - final long ident = Binder.clearCallingIdentity(); - try { - shutdownOrRebootInternal(true, confirm, null, wait); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm, final String reason, boolean wait) { if (mHandler == null || !mSystemReady) { @@ -1959,22 +1902,6 @@ public final class PowerManagerService extends IPowerManager.Stub } } - /** - * Crash the runtime (causing a complete restart of the Android framework). - * Requires REBOOT permission. Mostly for testing. Should not return. - */ - @Override // Binder call - public void crash(String message) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null); - - final long ident = Binder.clearCallingIdentity(); - try { - crashInternal(message); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void crashInternal(final String message) { Thread t = new Thread("PowerManagerService.crash()") { @Override @@ -1990,51 +1917,11 @@ public final class PowerManagerService extends IPowerManager.Stub } } - /** - * Set the setting that determines whether the device stays on when plugged in. - * The argument is a bit string, with each bit specifying a power source that, - * when the device is connected to that source, causes the device to stay on. - * See {@link android.os.BatteryManager} for the list of power sources that - * can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC} - * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB} - * - * Used by "adb shell svc power stayon ..." - * - * @param val an {@code int} containing the bits that specify which power sources - * should cause the device to stay on. - */ - @Override // Binder call - public void setStayOnSetting(int val) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null); - - final long ident = Binder.clearCallingIdentity(); - try { - setStayOnSettingInternal(val); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void setStayOnSettingInternal(int val) { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.STAY_ON_WHILE_PLUGGED_IN, val); } - /** - * Used by device administration to set the maximum screen off timeout. - * - * This method must only be called by the device administration policy manager. - */ - @Override // Binder call - public void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs) { - final long ident = Binder.clearCallingIdentity(); - try { - setMaximumScreenOffTimeoutFromDeviceAdminInternal(timeMs); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void setMaximumScreenOffTimeoutFromDeviceAdminInternal(int timeMs) { synchronized (mLock) { mMaximumScreenOffTimeoutFromDeviceAdmin = timeMs; @@ -2048,23 +1935,8 @@ public final class PowerManagerService extends IPowerManager.Stub && mMaximumScreenOffTimeoutFromDeviceAdmin < Integer.MAX_VALUE; } - /** - * Used by the phone application to make the attention LED flash when ringing. - */ - @Override // Binder call - public void setAttentionLight(boolean on, int color) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - final long ident = Binder.clearCallingIdentity(); - try { - setAttentionLightInternal(on, color); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void setAttentionLightInternal(boolean on, int color) { - LightsService.Light light; + Light light; synchronized (mLock) { if (!mSystemReady) { return; @@ -2073,38 +1945,7 @@ public final class PowerManagerService extends IPowerManager.Stub } // Control light outside of lock. - light.setFlashing(color, LightsService.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0); - } - - /** - * Used by the Watchdog. - */ - public long timeSinceScreenWasLastOn() { - synchronized (mLock) { - if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) { - return 0; - } - return SystemClock.elapsedRealtime() - mLastScreenOffEventElapsedRealTime; - } - } - - /** - * Used by the window manager to override the screen brightness based on the - * current foreground activity. - * - * This method must only be called by the window manager. - * - * @param brightness The overridden brightness, or -1 to disable the override. - */ - public void setScreenBrightnessOverrideFromWindowManager(int brightness) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - final long ident = Binder.clearCallingIdentity(); - try { - setScreenBrightnessOverrideFromWindowManagerInternal(brightness); - } finally { - Binder.restoreCallingIdentity(ident); - } + light.setFlashing(color, Light.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0); } private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness) { @@ -2117,40 +1958,6 @@ public final class PowerManagerService extends IPowerManager.Stub } } - /** - * Used by the window manager to override the button brightness based on the - * current foreground activity. - * - * This method must only be called by the window manager. - * - * @param brightness The overridden brightness, or -1 to disable the override. - */ - public void setButtonBrightnessOverrideFromWindowManager(int brightness) { - // Do nothing. - // Button lights are not currently supported in the new implementation. - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - } - - /** - * Used by the window manager to override the user activity timeout based on the - * current foreground activity. It can only be used to make the timeout shorter - * than usual, not longer. - * - * This method must only be called by the window manager. - * - * @param timeoutMillis The overridden timeout, or -1 to disable the override. - */ - public void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - final long ident = Binder.clearCallingIdentity(); - try { - setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void setUserActivityTimeoutOverrideFromWindowManagerInternal(long timeoutMillis) { synchronized (mLock) { if (mUserActivityTimeoutOverrideFromWindowManager != timeoutMillis) { @@ -2161,30 +1968,6 @@ public final class PowerManagerService extends IPowerManager.Stub } } - /** - * Used by the settings application and brightness control widgets to - * temporarily override the current screen brightness setting so that the - * user can observe the effect of an intended settings change without applying - * it immediately. - * - * The override will be canceled when the setting value is next updated. - * - * @param brightness The overridden brightness. - * - * @see android.provider.Settings.System#SCREEN_BRIGHTNESS - */ - @Override // Binder call - public void setTemporaryScreenBrightnessSettingOverride(int brightness) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - final long ident = Binder.clearCallingIdentity(); - try { - setTemporaryScreenBrightnessSettingOverrideInternal(brightness); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void setTemporaryScreenBrightnessSettingOverrideInternal(int brightness) { synchronized (mLock) { if (mTemporaryScreenBrightnessSettingOverride != brightness) { @@ -2195,30 +1978,6 @@ public final class PowerManagerService extends IPowerManager.Stub } } - /** - * Used by the settings application and brightness control widgets to - * temporarily override the current screen auto-brightness adjustment setting so that the - * user can observe the effect of an intended settings change without applying - * it immediately. - * - * The override will be canceled when the setting value is next updated. - * - * @param adj The overridden brightness, or Float.NaN to disable the override. - * - * @see Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ - */ - @Override // Binder call - public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - final long ident = Binder.clearCallingIdentity(); - try { - setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(adj); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(float adj) { synchronized (mLock) { // Note: This condition handles NaN because NaN is not equal to any other @@ -2265,24 +2024,15 @@ public final class PowerManagerService extends IPowerManager.Stub } } - @Override // Binder call - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump PowerManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - + private void dumpInternal(PrintWriter pw) { pw.println("POWER MANAGER (dumpsys power)\n"); - final DisplayPowerController dpc; final WirelessChargerDetector wcd; synchronized (mLock) { pw.println("Power Manager State:"); pw.println(" mDirty=0x" + Integer.toHexString(mDirty)); pw.println(" mWakefulness=" + wakefulnessToString(mWakefulness)); + pw.println(" mInteractive=" + mInteractive); pw.println(" mIsPowered=" + mIsPowered); pw.println(" mPlugType=" + mPlugType); pw.println(" mBatteryLevel=" + mBatteryLevel); @@ -2292,16 +2042,15 @@ public final class PowerManagerService extends IPowerManager.Stub pw.println(" mProximityPositive=" + mProximityPositive); pw.println(" mBootCompleted=" + mBootCompleted); pw.println(" mSystemReady=" + mSystemReady); + pw.println(" mHalAutoSuspendModeEnabled=" + mHalAutoSuspendModeEnabled); + pw.println(" mHalInteractiveModeEnabled=" + mHalInteractiveModeEnabled); pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)); pw.println(" mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)); pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity); pw.println(" mSandmanScheduled=" + mSandmanScheduled); + pw.println(" mSandmanSummoned=" + mSandmanSummoned); pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime)); pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime)); - pw.println(" mSendWakeUpFinishedNotificationWhenReady=" - + mSendWakeUpFinishedNotificationWhenReady); - pw.println(" mSendGoToSleepFinishedNotificationWhenReady=" - + mSendGoToSleepFinishedNotificationWhenReady); pw.println(" mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime)); pw.println(" mLastUserActivityTimeNoChangeLights=" + TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights)); @@ -2311,6 +2060,10 @@ public final class PowerManagerService extends IPowerManager.Stub pw.println(); pw.println("Settings and Configuration:"); + pw.println(" mDecoupleHalAutoSuspendModeFromDisplayConfig=" + + mDecoupleHalAutoSuspendModeFromDisplayConfig); + pw.println(" mDecoupleHalInteractiveModeFromDisplayConfig=" + + mDecoupleHalInteractiveModeFromDisplayConfig); pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig=" + mWakeUpWhenPluggedOrUnpluggedConfig); pw.println(" mSuspendWhenScreenOffDueToProximityConfig=" @@ -2321,6 +2074,14 @@ public final class PowerManagerService extends IPowerManager.Stub + mDreamsActivatedOnSleepByDefaultConfig); pw.println(" mDreamsActivatedOnDockByDefaultConfig=" + mDreamsActivatedOnDockByDefaultConfig); + pw.println(" mDreamsEnabledOnBatteryConfig=" + + mDreamsEnabledOnBatteryConfig); + pw.println(" mDreamsBatteryLevelMinimumWhenPoweredConfig=" + + mDreamsBatteryLevelMinimumWhenPoweredConfig); + pw.println(" mDreamsBatteryLevelMinimumWhenNotPoweredConfig=" + + mDreamsBatteryLevelMinimumWhenNotPoweredConfig); + pw.println(" mDreamsBatteryLevelDrainCutoffConfig=" + + mDreamsBatteryLevelDrainCutoffConfig); pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting); pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting); pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting); @@ -2367,16 +2128,11 @@ public final class PowerManagerService extends IPowerManager.Stub pw.println("Screen On Blocker: " + mScreenOnBlocker); pw.println(); - pw.println("Display Blanker: " + mDisplayBlanker); + pw.println("Display Power: " + mDisplayPowerCallbacks); - dpc = mDisplayPowerController; wcd = mWirelessChargerDetector; } - if (dpc != null) { - dpc.dump(pw); - } - if (wcd != null) { wcd.dump(pw); } @@ -2396,8 +2152,8 @@ public final class PowerManagerService extends IPowerManager.Stub return "Awake"; case WAKEFULNESS_DREAMING: return "Dreaming"; - case WAKEFULNESS_NAPPING: - return "Napping"; + case WAKEFULNESS_DOZING: + return "Dozing"; default: return Integer.toString(wakefulness); } @@ -2574,6 +2330,7 @@ public final class PowerManagerService extends IPowerManager.Stub + " (uid=" + mOwnerUid + ", pid=" + mOwnerPid + ", ws=" + mWorkSource + ")"; } + @SuppressWarnings("deprecation") private String getLockLevelString() { switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) { case PowerManager.FULL_WAKE_LOCK: @@ -2586,6 +2343,8 @@ public final class PowerManagerService extends IPowerManager.Stub return "PARTIAL_WAKE_LOCK "; case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: return "PROXIMITY_SCREEN_OFF_WAKE_LOCK"; + case PowerManager.DOZE_WAKE_LOCK: + return "DOZE_WAKE_LOCK "; default: return "??? "; } @@ -2708,34 +2467,443 @@ public final class PowerManagerService extends IPowerManager.Stub } } - private final class DisplayBlankerImpl implements DisplayBlanker { - private boolean mBlanked; + private final class BinderService extends IPowerManager.Stub { + @Override // Binder call + public void acquireWakeLockWithUid(IBinder lock, int flags, String tag, + String packageName, int uid) { + acquireWakeLock(lock, flags, tag, packageName, new WorkSource(uid)); + } - @Override - public void blankAllDisplays() { - synchronized (this) { - mBlanked = true; - mDisplayManagerService.blankAllDisplaysFromPowerManager(); - nativeSetInteractive(false); - nativeSetAutoSuspend(true); + @Override // Binder call + public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, + WorkSource ws) { + if (lock == null) { + throw new IllegalArgumentException("lock must not be null"); + } + if (packageName == null) { + throw new IllegalArgumentException("packageName must not be null"); + } + PowerManager.validateWakeLockParameters(flags, tag); + + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); + if (ws != null && ws.size() != 0) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.UPDATE_DEVICE_STATS, null); + } else { + ws = null; + } + + final int uid = Binder.getCallingUid(); + final int pid = Binder.getCallingPid(); + final long ident = Binder.clearCallingIdentity(); + try { + acquireWakeLockInternal(lock, flags, tag, packageName, ws, uid, pid); + } finally { + Binder.restoreCallingIdentity(ident); } } + @Override // Binder call + public void releaseWakeLock(IBinder lock, int flags) { + if (lock == null) { + throw new IllegalArgumentException("lock must not be null"); + } + + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); + + final long ident = Binder.clearCallingIdentity(); + try { + releaseWakeLockInternal(lock, flags); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void updateWakeLockUids(IBinder lock, int[] uids) { + WorkSource ws = null; + + if (uids != null) { + ws = new WorkSource(); + // XXX should WorkSource have a way to set uids as an int[] instead of adding them + // one at a time? + for (int i = 0; i < uids.length; i++) { + ws.add(uids[i]); + } + } + updateWakeLockWorkSource(lock, ws); + } + + @Override // Binder call + public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) { + if (lock == null) { + throw new IllegalArgumentException("lock must not be null"); + } + + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); + if (ws != null && ws.size() != 0) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.UPDATE_DEVICE_STATS, null); + } else { + ws = null; + } + + final long ident = Binder.clearCallingIdentity(); + try { + updateWakeLockWorkSourceInternal(lock, ws); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public boolean isWakeLockLevelSupported(int level) { + final long ident = Binder.clearCallingIdentity(); + try { + return isWakeLockLevelSupportedInternal(level); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void userActivity(long eventTime, int event, int flags) { + final long now = SystemClock.uptimeMillis(); + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER) + != PackageManager.PERMISSION_GRANTED) { + // Once upon a time applications could call userActivity(). + // Now we require the DEVICE_POWER permission. Log a warning and ignore the + // request instead of throwing a SecurityException so we don't break old apps. + synchronized (mLock) { + if (now >= mLastWarningAboutUserActivityPermission + (5 * 60 * 1000)) { + mLastWarningAboutUserActivityPermission = now; + Slog.w(TAG, "Ignoring call to PowerManager.userActivity() because the " + + "caller does not have DEVICE_POWER permission. " + + "Please fix your app! " + + " pid=" + Binder.getCallingPid() + + " uid=" + Binder.getCallingUid()); + } + } + return; + } + + if (eventTime > SystemClock.uptimeMillis()) { + throw new IllegalArgumentException("event time must not be in the future"); + } + + final int uid = Binder.getCallingUid(); + final long ident = Binder.clearCallingIdentity(); + try { + userActivityInternal(eventTime, event, flags, uid); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void wakeUp(long eventTime) { + if (eventTime > SystemClock.uptimeMillis()) { + throw new IllegalArgumentException("event time must not be in the future"); + } + + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + + final long ident = Binder.clearCallingIdentity(); + try { + wakeUpInternal(eventTime); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void goToSleep(long eventTime, int reason) { + if (eventTime > SystemClock.uptimeMillis()) { + throw new IllegalArgumentException("event time must not be in the future"); + } + + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + + final long ident = Binder.clearCallingIdentity(); + try { + goToSleepInternal(eventTime, reason); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void nap(long eventTime) { + if (eventTime > SystemClock.uptimeMillis()) { + throw new IllegalArgumentException("event time must not be in the future"); + } + + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + + final long ident = Binder.clearCallingIdentity(); + try { + napInternal(eventTime); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public boolean isInteractive() { + final long ident = Binder.clearCallingIdentity(); + try { + return isInteractiveInternal(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Reboots the device. + * + * @param confirm If true, shows a reboot confirmation dialog. + * @param reason The reason for the reboot, or null if none. + * @param wait If true, this call waits for the reboot to complete and does not return. + */ + @Override // Binder call + public void reboot(boolean confirm, String reason, boolean wait) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null); + + final long ident = Binder.clearCallingIdentity(); + try { + shutdownOrRebootInternal(false, confirm, reason, wait); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Shuts down the device. + * + * @param confirm If true, shows a shutdown confirmation dialog. + * @param wait If true, this call waits for the shutdown to complete and does not return. + */ + @Override // Binder call + public void shutdown(boolean confirm, boolean wait) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null); + + final long ident = Binder.clearCallingIdentity(); + try { + shutdownOrRebootInternal(true, confirm, null, wait); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Crash the runtime (causing a complete restart of the Android framework). + * Requires REBOOT permission. Mostly for testing. Should not return. + */ + @Override // Binder call + public void crash(String message) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null); + + final long ident = Binder.clearCallingIdentity(); + try { + crashInternal(message); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Set the setting that determines whether the device stays on when plugged in. + * The argument is a bit string, with each bit specifying a power source that, + * when the device is connected to that source, causes the device to stay on. + * See {@link android.os.BatteryManager} for the list of power sources that + * can be specified. Current values include + * {@link android.os.BatteryManager#BATTERY_PLUGGED_AC} + * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB} + * + * Used by "adb shell svc power stayon ..." + * + * @param val an {@code int} containing the bits that specify which power sources + * should cause the device to stay on. + */ + @Override // Binder call + public void setStayOnSetting(int val) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.WRITE_SETTINGS, null); + + final long ident = Binder.clearCallingIdentity(); + try { + setStayOnSettingInternal(val); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Used by device administration to set the maximum screen off timeout. + * + * This method must only be called by the device administration policy manager. + */ + @Override // Binder call + public void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs) { + final long ident = Binder.clearCallingIdentity(); + try { + setMaximumScreenOffTimeoutFromDeviceAdminInternal(timeMs); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Used by the settings application and brightness control widgets to + * temporarily override the current screen brightness setting so that the + * user can observe the effect of an intended settings change without applying + * it immediately. + * + * The override will be canceled when the setting value is next updated. + * + * @param brightness The overridden brightness. + * + * @see android.provider.Settings.System#SCREEN_BRIGHTNESS + */ + @Override // Binder call + public void setTemporaryScreenBrightnessSettingOverride(int brightness) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + + final long ident = Binder.clearCallingIdentity(); + try { + setTemporaryScreenBrightnessSettingOverrideInternal(brightness); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Used by the settings application and brightness control widgets to + * temporarily override the current screen auto-brightness adjustment setting so that the + * user can observe the effect of an intended settings change without applying + * it immediately. + * + * The override will be canceled when the setting value is next updated. + * + * @param adj The overridden brightness, or Float.NaN to disable the override. + * + * @see android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ + */ + @Override // Binder call + public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + + final long ident = Binder.clearCallingIdentity(); + try { + setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(adj); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Used by the phone application to make the attention LED flash when ringing. + */ + @Override // Binder call + public void setAttentionLight(boolean on, int color) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + + final long ident = Binder.clearCallingIdentity(); + try { + setAttentionLightInternal(on, color); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump PowerManager from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + final long ident = Binder.clearCallingIdentity(); + try { + dumpInternal(pw); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + private final class LocalService extends PowerManagerInternal { + /** + * Used by the window manager to override the screen brightness based on the + * current foreground activity. + * + * This method must only be called by the window manager. + * + * @param brightness The overridden brightness, or -1 to disable the override. + */ @Override - public void unblankAllDisplays() { - synchronized (this) { - nativeSetAutoSuspend(false); - nativeSetInteractive(true); - mDisplayManagerService.unblankAllDisplaysFromPowerManager(); - mBlanked = false; + public void setScreenBrightnessOverrideFromWindowManager(int brightness) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + + final long ident = Binder.clearCallingIdentity(); + try { + setScreenBrightnessOverrideFromWindowManagerInternal(brightness); + } finally { + Binder.restoreCallingIdentity(ident); } } + /** + * Used by the window manager to override the button brightness based on the + * current foreground activity. + * + * This method must only be called by the window manager. + * + * @param brightness The overridden brightness, or -1 to disable the override. + */ @Override - public String toString() { - synchronized (this) { - return "blanked=" + mBlanked; + public void setButtonBrightnessOverrideFromWindowManager(int brightness) { + // Do nothing. + // Button lights are not currently supported in the new implementation. + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + } + + /** + * Used by the window manager to override the user activity timeout based on the + * current foreground activity. It can only be used to make the timeout shorter + * than usual, not longer. + * + * This method must only be called by the window manager. + * + * @param timeoutMillis The overridden timeout, or -1 to disable the override. + */ + @Override + public void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.DEVICE_POWER, null); + + final long ident = Binder.clearCallingIdentity(); + try { + setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis); + } finally { + Binder.restoreCallingIdentity(ident); } } + + @Override + public void setPolicy(WindowManagerPolicy policy) { + PowerManagerService.this.setPolicy(policy); + } } } diff --git a/services/java/com/android/server/power/ScreenOnBlocker.java b/services/core/java/com/android/server/power/ScreenOnBlocker.java index dbbbc6d..dbbbc6d 100644 --- a/services/java/com/android/server/power/ScreenOnBlocker.java +++ b/services/core/java/com/android/server/power/ScreenOnBlocker.java diff --git a/services/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 88a27f5..88a27f5 100644 --- a/services/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java diff --git a/services/java/com/android/server/power/SuspendBlocker.java b/services/core/java/com/android/server/power/SuspendBlocker.java index 70b278a..70b278a 100644 --- a/services/java/com/android/server/power/SuspendBlocker.java +++ b/services/core/java/com/android/server/power/SuspendBlocker.java diff --git a/services/java/com/android/server/power/WirelessChargerDetector.java b/services/core/java/com/android/server/power/WirelessChargerDetector.java index 38f5d77..38f5d77 100644 --- a/services/java/com/android/server/power/WirelessChargerDetector.java +++ b/services/core/java/com/android/server/power/WirelessChargerDetector.java diff --git a/services/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java index b5d81d1..b5d81d1 100644 --- a/services/java/com/android/server/search/SearchManagerService.java +++ b/services/core/java/com/android/server/search/SearchManagerService.java diff --git a/services/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java index 0ffbb7d..0ffbb7d 100644 --- a/services/java/com/android/server/search/Searchables.java +++ b/services/core/java/com/android/server/search/Searchables.java diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java new file mode 100644 index 0000000..4f75189 --- /dev/null +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -0,0 +1,29 @@ +/** + * 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.server.statusbar; + +import com.android.server.notification.NotificationDelegate; + +import android.os.IBinder; +import android.service.notification.StatusBarNotification; + +public interface StatusBarManagerInternal { + void setNotificationDelegate(NotificationDelegate delegate); + IBinder addNotification(StatusBarNotification notification); + void updateNotification(IBinder key, StatusBarNotification notification); + void removeNotification(IBinder key); +} diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index f207c08..2ae467e 100644 --- a/services/java/com/android/server/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -14,26 +14,28 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.statusbar; import android.app.StatusBarManager; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.os.Binder; -import android.os.Handler; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.UserHandle; import android.util.Slog; import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.statusbar.StatusBarIconList; +import com.android.server.LocalServices; +import com.android.server.notification.NotificationDelegate; import com.android.server.wm.WindowManagerService; import java.io.FileDescriptor; @@ -51,31 +53,31 @@ import java.util.Map; public class StatusBarManagerService extends IStatusBarService.Stub implements WindowManagerService.OnHardKeyboardStatusChangeListener { - static final String TAG = "StatusBarManagerService"; - static final boolean SPEW = false; - - final Context mContext; - final WindowManagerService mWindowManager; - Handler mHandler = new Handler(); - NotificationCallbacks mNotificationCallbacks; - volatile IStatusBar mBar; - StatusBarIconList mIcons = new StatusBarIconList(); - HashMap<IBinder,StatusBarNotification> mNotifications + private static final String TAG = "StatusBarManagerService"; + private static final boolean SPEW = false; + + private final Context mContext; + private final WindowManagerService mWindowManager; + private Handler mHandler = new Handler(); + private NotificationDelegate mNotificationDelegate; + private volatile IStatusBar mBar; + private StatusBarIconList mIcons = new StatusBarIconList(); + private HashMap<IBinder,StatusBarNotification> mNotifications = new HashMap<IBinder,StatusBarNotification>(); // for disabling the status bar - final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>(); - IBinder mSysUiVisToken = new Binder(); - int mDisabled = 0; + private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>(); + private IBinder mSysUiVisToken = new Binder(); + private int mDisabled = 0; - Object mLock = new Object(); + private Object mLock = new Object(); // encompasses lights-out mode and other flags defined on View - int mSystemUiVisibility = 0; - boolean mMenuVisible = false; - int mImeWindowVis = 0; - int mImeBackDisposition; - IBinder mImeToken = null; - int mCurrentUserId; + private int mSystemUiVisibility = 0; + private boolean mMenuVisible = false; + private int mImeWindowVis = 0; + private int mImeBackDisposition; + private IBinder mImeToken = null; + private int mCurrentUserId; private class DisableRecord implements IBinder.DeathRecipient { int userId; @@ -90,16 +92,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } - public interface NotificationCallbacks { - void onSetDisabled(int status); - void onClearAll(); - void onNotificationClick(String pkg, String tag, int id); - void onNotificationClear(String pkg, String tag, int id); - void onPanelRevealed(); - void onNotificationError(String pkg, String tag, int id, - int uid, int initialPid, String message); - } - /** * Construct the service, add the status bar view to the window manager */ @@ -110,15 +102,74 @@ public class StatusBarManagerService extends IStatusBarService.Stub final Resources res = context.getResources(); mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons)); - } - public void setNotificationCallbacks(NotificationCallbacks listener) { - mNotificationCallbacks = listener; + LocalServices.addService(StatusBarManagerInternal.class, mInternalService); } + /** + * Private API used by NotificationManagerService. + */ + private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() { + @Override + public void setNotificationDelegate(NotificationDelegate delegate) { + synchronized (mNotifications) { + mNotificationDelegate = delegate; + } + } + + @Override + public IBinder addNotification(StatusBarNotification notification) { + synchronized (mNotifications) { + IBinder key = new Binder(); + mNotifications.put(key, notification); + if (mBar != null) { + try { + mBar.addNotification(key, notification); + } catch (RemoteException ex) { + } + } + return key; + } + } + + @Override + public void updateNotification(IBinder key, StatusBarNotification notification) { + synchronized (mNotifications) { + if (!mNotifications.containsKey(key)) { + throw new IllegalArgumentException("updateNotification key not found: " + key); + } + mNotifications.put(key, notification); + if (mBar != null) { + try { + mBar.updateNotification(key, notification); + } catch (RemoteException ex) { + } + } + } + } + + @Override + public void removeNotification(IBinder key) { + synchronized (mNotifications) { + final StatusBarNotification n = mNotifications.remove(key); + if (n == null) { + Slog.e(TAG, "removeNotification key not found: " + key); + return; + } + if (mBar != null) { + try { + mBar.removeNotification(key); + } catch (RemoteException ex) { + } + } + } + } + }; + // ================================================================================ // From IStatusBarService // ================================================================================ + @Override public void expandNotificationsPanel() { enforceExpandStatusBar(); @@ -130,6 +181,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void collapsePanels() { enforceExpandStatusBar(); @@ -141,6 +193,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void expandSettingsPanel() { enforceExpandStatusBar(); @@ -152,6 +205,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void disable(int what, IBinder token, String pkg) { disableInternal(mCurrentUserId, what, token, pkg); } @@ -177,7 +231,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub mDisabled = net; mHandler.post(new Runnable() { public void run() { - mNotificationCallbacks.onSetDisabled(net); + mNotificationDelegate.onSetDisabled(net); } }); if (mBar != null) { @@ -189,6 +243,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription) { enforceStatusBar(); @@ -214,6 +269,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void setIconVisibility(String slot, boolean visible) { enforceStatusBar(); @@ -241,6 +297,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void removeIcon(String slot) { enforceStatusBar(); @@ -265,6 +322,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub * Hide or show the on-screen Menu key. Only call this from the window manager, typically in * response to a window with FLAG_NEEDS_MENU_KEY set. */ + @Override public void topAppWindowChanged(final boolean menuVisible) { enforceStatusBar(); @@ -285,6 +343,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition) { enforceStatusBar(); @@ -312,6 +371,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void setSystemUiVisibility(int vis, int mask) { // also allows calls from window manager which is in this process. enforceStatusBarService(); @@ -344,6 +404,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void setHardKeyboardEnabled(final boolean enabled) { mHandler.post(new Runnable() { public void run() { @@ -426,6 +487,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub // ================================================================================ // Callbacks from the status bar service. // ================================================================================ + @Override public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList, List<IBinder> notificationKeys, List<StatusBarNotification> notifications, int switches[], List<IBinder> binders) { @@ -458,86 +520,64 @@ public class StatusBarManagerService extends IStatusBarService.Stub * The status bar service should call this each time the user brings the panel from * invisible to visible in order to clear the notification light. */ + @Override public void onPanelRevealed() { enforceStatusBarService(); - - // tell the notification manager to turn off the lights. - mNotificationCallbacks.onPanelRevealed(); + long identity = Binder.clearCallingIdentity(); + try { + // tell the notification manager to turn off the lights. + mNotificationDelegate.onPanelRevealed(); + } finally { + Binder.restoreCallingIdentity(identity); + } } + @Override public void onNotificationClick(String pkg, String tag, int id) { enforceStatusBarService(); - - mNotificationCallbacks.onNotificationClick(pkg, tag, id); + long identity = Binder.clearCallingIdentity(); + try { + mNotificationDelegate.onNotificationClick(pkg, tag, id); + } finally { + Binder.restoreCallingIdentity(identity); + } } + @Override public void onNotificationError(String pkg, String tag, int id, int uid, int initialPid, String message) { enforceStatusBarService(); - - // WARNING: this will call back into us to do the remove. Don't hold any locks. - mNotificationCallbacks.onNotificationError(pkg, tag, id, uid, initialPid, message); + long identity = Binder.clearCallingIdentity(); + try { + // WARNING: this will call back into us to do the remove. Don't hold any locks. + mNotificationDelegate.onNotificationError(pkg, tag, id, uid, initialPid, message); + } finally { + Binder.restoreCallingIdentity(identity); + } } + @Override public void onNotificationClear(String pkg, String tag, int id) { enforceStatusBarService(); - - mNotificationCallbacks.onNotificationClear(pkg, tag, id); + long identity = Binder.clearCallingIdentity(); + try { + mNotificationDelegate.onNotificationClear(pkg, tag, id); + } finally { + Binder.restoreCallingIdentity(identity); + } } + @Override public void onClearAllNotifications() { enforceStatusBarService(); - - mNotificationCallbacks.onClearAll(); - } - - // ================================================================================ - // Callbacks for NotificationManagerService. - // ================================================================================ - public IBinder addNotification(StatusBarNotification notification) { - synchronized (mNotifications) { - IBinder key = new Binder(); - mNotifications.put(key, notification); - if (mBar != null) { - try { - mBar.addNotification(key, notification); - } catch (RemoteException ex) { - } - } - return key; + long identity = Binder.clearCallingIdentity(); + try { + mNotificationDelegate.onClearAll(); + } finally { + Binder.restoreCallingIdentity(identity); } } - public void updateNotification(IBinder key, StatusBarNotification notification) { - synchronized (mNotifications) { - if (!mNotifications.containsKey(key)) { - throw new IllegalArgumentException("updateNotification key not found: " + key); - } - mNotifications.put(key, notification); - if (mBar != null) { - try { - mBar.updateNotification(key, notification); - } catch (RemoteException ex) { - } - } - } - } - - public void removeNotification(IBinder key) { - synchronized (mNotifications) { - final StatusBarNotification n = mNotifications.remove(key); - if (n == null) { - Slog.e(TAG, "removeNotification key not found: " + key); - return; - } - if (mBar != null) { - try { - mBar.removeNotification(key); - } catch (RemoteException ex) { - } - } - } - } // ================================================================================ // Can be called from any thread diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorInternal.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorInternal.java new file mode 100644 index 0000000..a91a81b --- /dev/null +++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorInternal.java @@ -0,0 +1,24 @@ +/** + * 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.server.storage; + +public interface DeviceStorageMonitorInternal { + boolean isMemoryLow(); + long getMemoryLowThreshold(); + void checkMemory(); +} + diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java index 016c561..43a99e0 100644 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java @@ -14,7 +14,10 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.storage; + +import com.android.server.EventLogTags; +import com.android.server.SystemService; import android.app.Notification; import android.app.NotificationManager; @@ -29,8 +32,8 @@ import android.os.Binder; import android.os.Environment; import android.os.FileObserver; import android.os.Handler; +import android.os.IBinder; import android.os.Message; -import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StatFs; @@ -66,13 +69,13 @@ import java.io.PrintWriter; * settings parameter with a default value of 2MB), the free memory is * logged to the event log. */ -public class DeviceStorageMonitorService extends Binder { - private static final String TAG = "DeviceStorageMonitorService"; +public class DeviceStorageMonitorService extends SystemService { + static final String TAG = "DeviceStorageMonitorService"; - private static final boolean DEBUG = false; - private static final boolean localLOGV = false; + static final boolean DEBUG = false; + static final boolean localLOGV = false; - private static final int DEVICE_MEMORY_WHAT = 1; + static final int DEVICE_MEMORY_WHAT = 1; private static final int MONITOR_INTERVAL = 1; //in minutes private static final int LOW_MEMORY_NOTIFICATION_ID = 1; @@ -84,33 +87,32 @@ public class DeviceStorageMonitorService extends Binder { private long mFreeMemAfterLastCacheClear; // on /data private long mLastReportedFreeMem; private long mLastReportedFreeMemTime; - private boolean mLowMemFlag=false; + boolean mLowMemFlag=false; private boolean mMemFullFlag=false; - private Context mContext; - private ContentResolver mResolver; - private long mTotalMemory; // on /data - private StatFs mDataFileStats; - private StatFs mSystemFileStats; - private StatFs mCacheFileStats; + private final ContentResolver mResolver; + private final long mTotalMemory; // on /data + private final StatFs mDataFileStats; + private final StatFs mSystemFileStats; + private final StatFs mCacheFileStats; private static final File DATA_PATH = Environment.getDataDirectory(); private static final File SYSTEM_PATH = Environment.getRootDirectory(); private static final File CACHE_PATH = Environment.getDownloadCacheDirectory(); private long mThreadStartTime = -1; - private boolean mClearSucceeded = false; - private boolean mClearingCache; - private Intent mStorageLowIntent; - private Intent mStorageOkIntent; - private Intent mStorageFullIntent; - private Intent mStorageNotFullIntent; + boolean mClearSucceeded = false; + boolean mClearingCache; + private final Intent mStorageLowIntent; + private final Intent mStorageOkIntent; + private final Intent mStorageFullIntent; + private final Intent mStorageNotFullIntent; private CachePackageDataObserver mClearCacheObserver; - private final CacheFileDeletedObserver mCacheFileDeletedObserver; + private CacheFileDeletedObserver mCacheFileDeletedObserver; private static final int _TRUE = 1; private static final int _FALSE = 0; // This is the raw threshold that has been set at which we consider // storage to be low. - private long mMemLowThreshold; + long mMemLowThreshold; // This is the threshold at which we start trying to flush caches // to get below the low threshold limit. It is less than the low // threshold; we will allow storage to get a bit beyond the limit @@ -126,13 +128,13 @@ public class DeviceStorageMonitorService extends Binder { /** * This string is used for ServiceManager access to this class. */ - public static final String SERVICE = "devicestoragemonitor"; + static final String SERVICE = "devicestoragemonitor"; /** * Handler that checks the amount of disk space on the device and sends a * notification if the device runs low on disk space */ - Handler mHandler = new Handler() { + private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { //don't handle an invalid message @@ -144,7 +146,7 @@ public class DeviceStorageMonitorService extends Binder { } }; - class CachePackageDataObserver extends IPackageDataObserver.Stub { + private class CachePackageDataObserver extends IPackageDataObserver.Stub { public void onRemoveCompleted(String packageName, boolean succeeded) { mClearSucceeded = succeeded; mClearingCache = false; @@ -154,7 +156,7 @@ public class DeviceStorageMonitorService extends Binder { } } - private final void restatDataDir() { + private void restatDataDir() { try { mDataFileStats.restat(DATA_PATH.getAbsolutePath()); mFreeMem = (long) mDataFileStats.getAvailableBlocks() * @@ -206,7 +208,7 @@ public class DeviceStorageMonitorService extends Binder { } } - private final void clearCache() { + private void clearCache() { if (mClearCacheObserver == null) { // Lazy instantiation mClearCacheObserver = new CachePackageDataObserver(); @@ -223,7 +225,7 @@ public class DeviceStorageMonitorService extends Binder { } } - private final void checkMemory(boolean checkCache) { + void checkMemory(boolean checkCache) { //if the thread that was started to clear cache is still running do nothing till its //finished clearing cache. Ideally this flag could be modified by clearCache // and should be accessed via a lock but even if it does this test will fail now and @@ -300,7 +302,7 @@ public class DeviceStorageMonitorService extends Binder { postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL); } - private void postCheckMemoryMsg(boolean clearCache, long delay) { + void postCheckMemoryMsg(boolean clearCache, long delay) { // Remove queued messages mHandler.removeMessages(DEVICE_MEMORY_WHAT); mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT, @@ -308,14 +310,10 @@ public class DeviceStorageMonitorService extends Binder { delay); } - /** - * Constructor to run service. initializes the disk space threshold value - * and posts an empty message to kickstart the process. - */ public DeviceStorageMonitorService(Context context) { + super(context); mLastReportedFreeMemTime = 0; - mContext = context; - mResolver = mContext.getContentResolver(); + mResolver = context.getContentResolver(); //create StatFs object mDataFileStats = new StatFs(DATA_PATH.getAbsolutePath()); mSystemFileStats = new StatFs(SYSTEM_PATH.getAbsolutePath()); @@ -331,9 +329,16 @@ public class DeviceStorageMonitorService extends Binder { mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL); mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + } + /** + * Initializes the disk space threshold value and posts an empty message to + * kickstart the process. + */ + @Override + public void onStart() { // cache storage thresholds - final StorageManager sm = StorageManager.from(context); + final StorageManager sm = StorageManager.from(getContext()); mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH); mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH); @@ -345,6 +350,78 @@ public class DeviceStorageMonitorService extends Binder { mCacheFileDeletedObserver = new CacheFileDeletedObserver(); mCacheFileDeletedObserver.startWatching(); + + publishBinderService(SERVICE, mRemoteService); + publishLocalService(DeviceStorageMonitorInternal.class, mLocalService); + } + + private final DeviceStorageMonitorInternal mLocalService = new DeviceStorageMonitorInternal() { + @Override + public void checkMemory() { + // force an early check + postCheckMemoryMsg(true, 0); + } + + @Override + public boolean isMemoryLow() { + return mLowMemFlag; + } + + @Override + public long getMemoryLowThreshold() { + return mMemLowThreshold; + } + }; + + private final IBinder mRemoteService = new Binder() { + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + + pw.println("Permission Denial: can't dump " + SERVICE + " from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + dumpImpl(pw); + } + }; + + void dumpImpl(PrintWriter pw) { + final Context context = getContext(); + + pw.println("Current DeviceStorageMonitor state:"); + + pw.print(" mFreeMem="); pw.print(Formatter.formatFileSize(context, mFreeMem)); + pw.print(" mTotalMemory="); + pw.println(Formatter.formatFileSize(context, mTotalMemory)); + + pw.print(" mFreeMemAfterLastCacheClear="); + pw.println(Formatter.formatFileSize(context, mFreeMemAfterLastCacheClear)); + + pw.print(" mLastReportedFreeMem="); + pw.print(Formatter.formatFileSize(context, mLastReportedFreeMem)); + pw.print(" mLastReportedFreeMemTime="); + TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw); + pw.println(); + + pw.print(" mLowMemFlag="); pw.print(mLowMemFlag); + pw.print(" mMemFullFlag="); pw.println(mMemFullFlag); + + pw.print(" mClearSucceeded="); pw.print(mClearSucceeded); + pw.print(" mClearingCache="); pw.println(mClearingCache); + + pw.print(" mMemLowThreshold="); + pw.print(Formatter.formatFileSize(context, mMemLowThreshold)); + pw.print(" mMemFullThreshold="); + pw.println(Formatter.formatFileSize(context, mMemFullThreshold)); + + pw.print(" mMemCacheStartTrimThreshold="); + pw.print(Formatter.formatFileSize(context, mMemCacheStartTrimThreshold)); + pw.print(" mMemCacheTrimToThreshold="); + pw.println(Formatter.formatFileSize(context, mMemCacheTrimToThreshold)); } /** @@ -352,7 +429,8 @@ public class DeviceStorageMonitorService extends Binder { * an error dialog indicating low disk space and launch the Installer * application */ - private final void sendNotification() { + private void sendNotification() { + final Context context = getContext(); if(localLOGV) Slog.i(TAG, "Sending low memory notification"); //log the event to event log with the amount of free storage(in bytes) left on the device EventLog.writeEvent(EventLogTags.LOW_STORAGE, mFreeMem); @@ -363,86 +441,58 @@ public class DeviceStorageMonitorService extends Binder { lowMemIntent.putExtra("memory", mFreeMem); lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); NotificationManager mNotificationMgr = - (NotificationManager)mContext.getSystemService( + (NotificationManager)context.getSystemService( Context.NOTIFICATION_SERVICE); - CharSequence title = mContext.getText( + CharSequence title = context.getText( com.android.internal.R.string.low_internal_storage_view_title); - CharSequence details = mContext.getText( + CharSequence details = context.getText( com.android.internal.R.string.low_internal_storage_view_text); - PendingIntent intent = PendingIntent.getActivityAsUser(mContext, 0, lowMemIntent, 0, + PendingIntent intent = PendingIntent.getActivityAsUser(context, 0, lowMemIntent, 0, null, UserHandle.CURRENT); Notification notification = new Notification(); notification.icon = com.android.internal.R.drawable.stat_notify_disk_full; notification.tickerText = title; notification.flags |= Notification.FLAG_NO_CLEAR; - notification.setLatestEventInfo(mContext, title, details, intent); + notification.setLatestEventInfo(context, title, details, intent); mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification, UserHandle.ALL); - mContext.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL); + context.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL); } /** * Cancels low storage notification and sends OK intent. */ - private final void cancelNotification() { + private void cancelNotification() { + final Context context = getContext(); if(localLOGV) Slog.i(TAG, "Canceling low memory notification"); NotificationManager mNotificationMgr = - (NotificationManager)mContext.getSystemService( + (NotificationManager)context.getSystemService( Context.NOTIFICATION_SERVICE); //cancel notification since memory has been freed mNotificationMgr.cancelAsUser(null, LOW_MEMORY_NOTIFICATION_ID, UserHandle.ALL); - mContext.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL); - mContext.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL); + context.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL); + context.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL); } /** * Send a notification when storage is full. */ - private final void sendFullNotification() { + private void sendFullNotification() { if(localLOGV) Slog.i(TAG, "Sending memory full notification"); - mContext.sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL); + getContext().sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL); } /** * Cancels memory full notification and sends "not full" intent. */ - private final void cancelFullNotification() { + private void cancelFullNotification() { if(localLOGV) Slog.i(TAG, "Canceling memory full notification"); - mContext.removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL); - mContext.sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL); - } - - public void updateMemory() { - int callingUid = getCallingUid(); - if(callingUid != Process.SYSTEM_UID) { - return; - } - // force an early check - postCheckMemoryMsg(true, 0); - } - - /** - * Callable from other things in the system service to obtain the low memory - * threshold. - * - * @return low memory threshold in bytes - */ - public long getMemoryLowThreshold() { - return mMemLowThreshold; + getContext().removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL); + getContext().sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL); } - /** - * Callable from other things in the system process to check whether memory - * is low. - * - * @return true is memory is low - */ - public boolean isMemoryLow() { - return mLowMemFlag; - } - - public static class CacheFileDeletedObserver extends FileObserver { + private static class CacheFileDeletedObserver extends FileObserver { public CacheFileDeletedObserver() { super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE); } @@ -452,40 +502,4 @@ public class DeviceStorageMonitorService extends Binder { EventLogTags.writeCacheFileDeleted(path); } } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - - pw.println("Permission Denial: can't dump " + SERVICE + " from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - pw.println("Current DeviceStorageMonitor state:"); - pw.print(" mFreeMem="); pw.print(Formatter.formatFileSize(mContext, mFreeMem)); - pw.print(" mTotalMemory="); - pw.println(Formatter.formatFileSize(mContext, mTotalMemory)); - pw.print(" mFreeMemAfterLastCacheClear="); - pw.println(Formatter.formatFileSize(mContext, mFreeMemAfterLastCacheClear)); - pw.print(" mLastReportedFreeMem="); - pw.print(Formatter.formatFileSize(mContext, mLastReportedFreeMem)); - pw.print(" mLastReportedFreeMemTime="); - TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw); - pw.println(); - pw.print(" mLowMemFlag="); pw.print(mLowMemFlag); - pw.print(" mMemFullFlag="); pw.println(mMemFullFlag); - pw.print(" mClearSucceeded="); pw.print(mClearSucceeded); - pw.print(" mClearingCache="); pw.println(mClearingCache); - pw.print(" mMemLowThreshold="); - pw.print(Formatter.formatFileSize(mContext, mMemLowThreshold)); - pw.print(" mMemFullThreshold="); - pw.println(Formatter.formatFileSize(mContext, mMemFullThreshold)); - pw.print(" mMemCacheStartTrimThreshold="); - pw.print(Formatter.formatFileSize(mContext, mMemCacheStartTrimThreshold)); - pw.print(" mMemCacheTrimToThreshold="); - pw.println(Formatter.formatFileSize(mContext, mMemCacheTrimToThreshold)); - } } diff --git a/services/core/java/com/android/server/twilight/TwilightListener.java b/services/core/java/com/android/server/twilight/TwilightListener.java new file mode 100644 index 0000000..29ead44 --- /dev/null +++ b/services/core/java/com/android/server/twilight/TwilightListener.java @@ -0,0 +1,21 @@ +/* + * 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.server.twilight; + +public interface TwilightListener { + void onTwilightStateChanged(); +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/twilight/TwilightManager.java b/services/core/java/com/android/server/twilight/TwilightManager.java new file mode 100644 index 0000000..b3de58b --- /dev/null +++ b/services/core/java/com/android/server/twilight/TwilightManager.java @@ -0,0 +1,24 @@ +/* + * 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.server.twilight; + +import android.os.Handler; + +public interface TwilightManager { + void registerListener(TwilightListener listener, Handler handler); + TwilightState getCurrentState(); +} diff --git a/services/java/com/android/server/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java index 0356faa..a71961c 100644 --- a/services/java/com/android/server/TwilightService.java +++ b/services/core/java/com/android/server/twilight/TwilightService.java @@ -14,7 +14,10 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.twilight; + +import com.android.server.SystemService; +import com.android.server.TwilightCalculator; import android.app.AlarmManager; import android.app.PendingIntent; @@ -34,9 +37,7 @@ import android.text.format.DateUtils; import android.text.format.Time; import android.util.Slog; -import java.text.DateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.Iterator; import libcore.util.Objects; @@ -47,78 +48,92 @@ import libcore.util.Objects; * Used by the UI mode manager and other components to adjust night mode * effects based on sunrise and sunset. */ -public final class TwilightService { - private static final String TAG = "TwilightService"; - - private static final boolean DEBUG = false; - - private static final String ACTION_UPDATE_TWILIGHT_STATE = +public final class TwilightService extends SystemService { + static final String TAG = "TwilightService"; + static final boolean DEBUG = false; + static final String ACTION_UPDATE_TWILIGHT_STATE = "com.android.server.action.UPDATE_TWILIGHT_STATE"; - private final Context mContext; - private final AlarmManager mAlarmManager; - private final LocationManager mLocationManager; - private final LocationHandler mLocationHandler; + final Object mLock = new Object(); - private final Object mLock = new Object(); + AlarmManager mAlarmManager; + LocationManager mLocationManager; + LocationHandler mLocationHandler; - private final ArrayList<TwilightListenerRecord> mListeners = + final ArrayList<TwilightListenerRecord> mListeners = new ArrayList<TwilightListenerRecord>(); - private boolean mSystemReady; - - private TwilightState mTwilightState; + TwilightState mTwilightState; public TwilightService(Context context) { - mContext = context; + super(context); + } - mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE); + @Override + public void onStart() { + mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); + mLocationManager = (LocationManager) getContext().getSystemService( + Context.LOCATION_SERVICE); mLocationHandler = new LocationHandler(); + + IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); + filter.addAction(Intent.ACTION_TIME_CHANGED); + filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); + filter.addAction(ACTION_UPDATE_TWILIGHT_STATE); + getContext().registerReceiver(mUpdateLocationReceiver, filter); + + publishLocalService(TwilightManager.class, mService); } - void systemReady() { - synchronized (mLock) { - mSystemReady = true; + private static class TwilightListenerRecord implements Runnable { + private final TwilightListener mListener; + private final Handler mHandler; - IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); - filter.addAction(Intent.ACTION_TIME_CHANGED); - filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - filter.addAction(ACTION_UPDATE_TWILIGHT_STATE); - mContext.registerReceiver(mUpdateLocationReceiver, filter); + public TwilightListenerRecord(TwilightListener listener, Handler handler) { + mListener = listener; + mHandler = handler; + } - if (!mListeners.isEmpty()) { - mLocationHandler.enableLocationUpdates(); - } + public void postUpdate() { + mHandler.post(this); } - } - /** - * Gets the current twilight state. - * - * @return The current twilight state, or null if no information is available. - */ - public TwilightState getCurrentState() { - synchronized (mLock) { - return mTwilightState; + @Override + public void run() { + mListener.onTwilightStateChanged(); } + } - /** - * Listens for twilight time. - * - * @param listener The listener. - * @param handler The handler on which to post calls into the listener. - */ - public void registerListener(TwilightListener listener, Handler handler) { - synchronized (mLock) { - mListeners.add(new TwilightListenerRecord(listener, handler)); + private final TwilightManager mService = new TwilightManager() { + /** + * Gets the current twilight state. + * + * @return The current twilight state, or null if no information is available. + */ + @Override + public TwilightState getCurrentState() { + synchronized (mLock) { + return mTwilightState; + } + } + + /** + * Listens for twilight time. + * + * @param listener The listener. + */ + @Override + public void registerListener(TwilightListener listener, Handler handler) { + synchronized (mLock) { + mListeners.add(new TwilightListenerRecord(listener, handler)); - if (mSystemReady && mListeners.size() == 1) { - mLocationHandler.enableLocationUpdates(); + if (mListeners.size() == 1) { + mLocationHandler.enableLocationUpdates(); + } } } - } + }; private void setTwilightState(TwilightState state) { synchronized (mLock) { @@ -128,9 +143,10 @@ public final class TwilightService { } mTwilightState = state; - int count = mListeners.size(); - for (int i = 0; i < count; i++) { - mListeners.get(i).post(); + + final int listenerLen = mListeners.size(); + for (int i = 0; i < listenerLen; i++) { + mListeners.get(i).postUpdate(); } } } @@ -162,124 +178,6 @@ public final class TwilightService { return distance >= totalAccuracy; } - /** - * Describes whether it is day or night. - * This object is immutable. - */ - public static final class TwilightState { - private final boolean mIsNight; - private final long mYesterdaySunset; - private final long mTodaySunrise; - private final long mTodaySunset; - private final long mTomorrowSunrise; - - TwilightState(boolean isNight, - long yesterdaySunset, - long todaySunrise, long todaySunset, - long tomorrowSunrise) { - mIsNight = isNight; - mYesterdaySunset = yesterdaySunset; - mTodaySunrise = todaySunrise; - mTodaySunset = todaySunset; - mTomorrowSunrise = tomorrowSunrise; - } - - /** - * Returns true if it is currently night time. - */ - public boolean isNight() { - return mIsNight; - } - - /** - * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase, - * or -1 if the sun never sets. - */ - public long getYesterdaySunset() { - return mYesterdaySunset; - } - - /** - * Returns the time of today's sunrise in the System.currentTimeMillis() timebase, - * or -1 if the sun never rises. - */ - public long getTodaySunrise() { - return mTodaySunrise; - } - - /** - * Returns the time of today's sunset in the System.currentTimeMillis() timebase, - * or -1 if the sun never sets. - */ - public long getTodaySunset() { - return mTodaySunset; - } - - /** - * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase, - * or -1 if the sun never rises. - */ - public long getTomorrowSunrise() { - return mTomorrowSunrise; - } - - @Override - public boolean equals(Object o) { - return o instanceof TwilightState && equals((TwilightState)o); - } - - public boolean equals(TwilightState other) { - return other != null - && mIsNight == other.mIsNight - && mYesterdaySunset == other.mYesterdaySunset - && mTodaySunrise == other.mTodaySunrise - && mTodaySunset == other.mTodaySunset - && mTomorrowSunrise == other.mTomorrowSunrise; - } - - @Override - public int hashCode() { - return 0; // don't care - } - - @Override - public String toString() { - DateFormat f = DateFormat.getDateTimeInstance(); - return "{TwilightState: isNight=" + mIsNight - + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset)) - + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise)) - + ", mTodaySunset=" + f.format(new Date(mTodaySunset)) - + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise)) - + "}"; - } - } - - /** - * Listener for changes in twilight state. - */ - public interface TwilightListener { - public void onTwilightStateChanged(); - } - - private static final class TwilightListenerRecord implements Runnable { - private final TwilightListener mListener; - private final Handler mHandler; - - public TwilightListenerRecord(TwilightListener listener, Handler handler) { - mListener = listener; - mHandler = handler; - } - - public void post() { - mHandler.post(this); - } - - @Override - public void run() { - mListener.onTwilightStateChanged(); - } - } - private final class LocationHandler extends Handler { private static final int MSG_ENABLE_LOCATION_UPDATES = 1; private static final int MSG_GET_NEW_LOCATION_UPDATE = 2; @@ -518,11 +416,12 @@ public final class TwilightService { } Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE); - PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, updateIntent, 0); + PendingIntent pendingIntent = PendingIntent.getBroadcast( + getContext(), 0, updateIntent, 0); mAlarmManager.cancel(pendingIntent); mAlarmManager.setExact(AlarmManager.RTC, nextUpdate, pendingIntent); } - }; + } private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() { @Override diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java new file mode 100644 index 0000000..91e24d7 --- /dev/null +++ b/services/core/java/com/android/server/twilight/TwilightState.java @@ -0,0 +1,112 @@ +/* + * 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.server.twilight; + +import java.text.DateFormat; +import java.util.Date; + +/** + * Describes whether it is day or night. + * This object is immutable. + */ +public class TwilightState { + private final boolean mIsNight; + private final long mYesterdaySunset; + private final long mTodaySunrise; + private final long mTodaySunset; + private final long mTomorrowSunrise; + + TwilightState(boolean isNight, + long yesterdaySunset, + long todaySunrise, long todaySunset, + long tomorrowSunrise) { + mIsNight = isNight; + mYesterdaySunset = yesterdaySunset; + mTodaySunrise = todaySunrise; + mTodaySunset = todaySunset; + mTomorrowSunrise = tomorrowSunrise; + } + + /** + * Returns true if it is currently night time. + */ + public boolean isNight() { + return mIsNight; + } + + /** + * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase, + * or -1 if the sun never sets. + */ + public long getYesterdaySunset() { + return mYesterdaySunset; + } + + /** + * Returns the time of today's sunrise in the System.currentTimeMillis() timebase, + * or -1 if the sun never rises. + */ + public long getTodaySunrise() { + return mTodaySunrise; + } + + /** + * Returns the time of today's sunset in the System.currentTimeMillis() timebase, + * or -1 if the sun never sets. + */ + public long getTodaySunset() { + return mTodaySunset; + } + + /** + * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase, + * or -1 if the sun never rises. + */ + public long getTomorrowSunrise() { + return mTomorrowSunrise; + } + + @Override + public boolean equals(Object o) { + return o instanceof TwilightState && equals((TwilightState)o); + } + + public boolean equals(TwilightState other) { + return other != null + && mIsNight == other.mIsNight + && mYesterdaySunset == other.mYesterdaySunset + && mTodaySunrise == other.mTodaySunrise + && mTodaySunset == other.mTodaySunset + && mTomorrowSunrise == other.mTomorrowSunrise; + } + + @Override + public int hashCode() { + return 0; // don't care + } + + @Override + public String toString() { + DateFormat f = DateFormat.getDateTimeInstance(); + return "{TwilightState: isNight=" + mIsNight + + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset)) + + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise)) + + ", mTodaySunset=" + f.format(new Date(mTodaySunset)) + + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise)) + + "}"; + } +} diff --git a/services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java b/services/core/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java index b53fb65..b53fb65 100644 --- a/services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java +++ b/services/core/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java diff --git a/services/java/com/android/server/updates/CertPinInstallReceiver.java b/services/core/java/com/android/server/updates/CertPinInstallReceiver.java index c03fbc3..c03fbc3 100644 --- a/services/java/com/android/server/updates/CertPinInstallReceiver.java +++ b/services/core/java/com/android/server/updates/CertPinInstallReceiver.java diff --git a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java index 9601e9a..9601e9a 100644 --- a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java +++ b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java diff --git a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java b/services/core/java/com/android/server/updates/IntentFirewallInstallReceiver.java index 0b54f92..0b54f92 100644 --- a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java +++ b/services/core/java/com/android/server/updates/IntentFirewallInstallReceiver.java diff --git a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java index 5dd30f1..e430814 100644 --- a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java +++ b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java @@ -125,25 +125,11 @@ public class SELinuxPolicyInstallReceiver extends ConfigUpdateInstallReceiver { SystemProperties.set("selinux.reload_policy", "1"); } - private void setEnforcingMode(Context context) { - String mode = Settings.Global.getString(context.getContentResolver(), - Settings.Global.SELINUX_STATUS); - if ("1".equals(mode)) { - Slog.i(TAG, "Setting enforcing mode"); - SystemProperties.set("persist.selinux.enforcing", mode); - } else if ("0".equals(mode)) { - Slog.i(TAG, "Tried to set permissive mode, ignoring"); - } else { - Slog.e(TAG, "Got invalid enforcing mode: " + mode); - } - } - @Override protected void postInstall(Context context, Intent intent) { try { unpackBundle(); applyUpdate(); - setEnforcingMode(context); } catch (IllegalArgumentException e) { Slog.e(TAG, "SELinux policy update malformed: ", e); } catch (IOException e) { diff --git a/services/java/com/android/server/updates/SmsShortCodesInstallReceiver.java b/services/core/java/com/android/server/updates/SmsShortCodesInstallReceiver.java index 0f14f57..0f14f57 100644 --- a/services/java/com/android/server/updates/SmsShortCodesInstallReceiver.java +++ b/services/core/java/com/android/server/updates/SmsShortCodesInstallReceiver.java diff --git a/services/java/com/android/server/updates/TZInfoInstallReceiver.java b/services/core/java/com/android/server/updates/TZInfoInstallReceiver.java index 83adbdb..83adbdb 100644 --- a/services/java/com/android/server/updates/TZInfoInstallReceiver.java +++ b/services/core/java/com/android/server/updates/TZInfoInstallReceiver.java diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index e6b6b93..97ea52c 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.wallpaper; import static android.os.ParcelFileDescriptor.*; @@ -85,8 +85,8 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; -class WallpaperManagerService extends IWallpaperManager.Stub { - static final String TAG = "WallpaperService"; +public class WallpaperManagerService extends IWallpaperManager.Stub { + static final String TAG = "WallpaperManagerService"; static final boolean DEBUG = false; final Object mLock = new Object[0]; @@ -98,7 +98,6 @@ class WallpaperManagerService extends IWallpaperManager.Stub { static final long MIN_WALLPAPER_CRASH_TIME = 10000; static final String WALLPAPER = "wallpaper"; static final String WALLPAPER_INFO = "wallpaper_info.xml"; - /** * Name of the component used to display bitmap wallpapers from either the gallery or * built-in wallpapers. @@ -505,7 +504,12 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } } - String getName() { + /** Called by SystemBackupAgent */ + public String getName() { + // Verify caller is the system + if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { + throw new RuntimeException("getName() can only be called from the system process"); + } synchronized (mLock) { return mWallpaperMap.get(0).name; } @@ -1175,7 +1179,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } // Called by SystemBackupAgent after files are restored to disk. - void settingsRestored() { + public void settingsRestored() { + // Verify caller is the system + if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { + throw new RuntimeException("settingsRestored() can only be called from the system process"); + } // TODO: If necessary, make it work for secondary users as well. This currently assumes // restores only to the primary user if (DEBUG) Slog.v(TAG, "settingsRestored"); diff --git a/services/java/com/android/server/wifi/README.txt b/services/core/java/com/android/server/wifi/README.txt index 39e1475..39e1475 100644 --- a/services/java/com/android/server/wifi/README.txt +++ b/services/core/java/com/android/server/wifi/README.txt diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/core/java/com/android/server/wifi/WifiController.java index bdb0a5e..bdb0a5e 100644 --- a/services/java/com/android/server/wifi/WifiController.java +++ b/services/core/java/com/android/server/wifi/WifiController.java diff --git a/services/java/com/android/server/wifi/WifiNotificationController.java b/services/core/java/com/android/server/wifi/WifiNotificationController.java index a9206e0..a9206e0 100644 --- a/services/java/com/android/server/wifi/WifiNotificationController.java +++ b/services/core/java/com/android/server/wifi/WifiNotificationController.java diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/core/java/com/android/server/wifi/WifiService.java index aecf9ae..aecf9ae 100644 --- a/services/java/com/android/server/wifi/WifiService.java +++ b/services/core/java/com/android/server/wifi/WifiService.java diff --git a/services/java/com/android/server/wifi/WifiSettingsStore.java b/services/core/java/com/android/server/wifi/WifiSettingsStore.java index 3ff8061..3ff8061 100644 --- a/services/java/com/android/server/wifi/WifiSettingsStore.java +++ b/services/core/java/com/android/server/wifi/WifiSettingsStore.java diff --git a/services/java/com/android/server/wifi/WifiTrafficPoller.java b/services/core/java/com/android/server/wifi/WifiTrafficPoller.java index b498550..b498550 100644 --- a/services/java/com/android/server/wifi/WifiTrafficPoller.java +++ b/services/core/java/com/android/server/wifi/WifiTrafficPoller.java diff --git a/services/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 756e06a..756e06a 100644 --- a/services/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java index 3cccf1d..7fe895b 100644 --- a/services/java/com/android/server/wm/AppWindowAnimator.java +++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java @@ -1,4 +1,18 @@ -// Copyright 2012 Google Inc. All Rights Reserved. +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.android.server.wm; diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index e98014b..ca4ad8a 100644 --- a/services/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -105,6 +105,8 @@ class AppWindowToken extends WindowToken { // Input application handle used by the input dispatcher. final InputApplicationHandle mInputApplicationHandle; + boolean mDeferRemoval; + AppWindowToken(WindowManagerService _service, IApplicationToken _token) { super(_service, _token.asBinder(), WindowManager.LayoutParams.TYPE_APPLICATION, true); diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java index 5aa266d..5aa266d 100644 --- a/services/java/com/android/server/wm/BlackFrame.java +++ b/services/core/java/com/android/server/wm/BlackFrame.java diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java new file mode 100644 index 0000000..35d19c1 --- /dev/null +++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.view.Display; +import android.view.Surface; +import android.view.Surface.OutOfResourcesException; +import android.view.SurfaceControl; +import android.view.SurfaceSession; + +class CircularDisplayMask { + private static final String TAG = "CircularDisplayMask"; + + private static final int STROKE_WIDTH = 2; + + private final SurfaceControl mSurfaceControl; + private final Surface mSurface = new Surface(); + private int mLastDW; + private int mLastDH; + private boolean mDrawNeeded; + private Paint mPaint; + private int mRotation; + + public CircularDisplayMask(Display display, SurfaceSession session, int zOrder) { + SurfaceControl ctrl = null; + try { + ctrl = new SurfaceControl(session, "CircularDisplayMask", + 320, 290, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN); + ctrl.setLayerStack(display.getLayerStack()); + ctrl.setLayer(zOrder); + ctrl.setPosition(0, 0); + ctrl.show(); + mSurface.copyFrom(ctrl); + } catch (OutOfResourcesException e) { + } + mSurfaceControl = ctrl; + mDrawNeeded = true; + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setColor(Color.BLACK); + mPaint.setStrokeWidth(STROKE_WIDTH); + } + + private void drawIfNeeded() { + if (!mDrawNeeded) { + return; + } + mDrawNeeded = false; + + Rect dirty = new Rect(0, 0, mLastDW, mLastDH); + Canvas c = null; + try { + c = mSurface.lockCanvas(dirty); + } catch (IllegalArgumentException e) { + } catch (Surface.OutOfResourcesException e) { + } + if (c == null) { + return; + } + int cx = 160; + int cy = 160; + switch (mRotation) { + case Surface.ROTATION_0: + case Surface.ROTATION_90: + // chin bottom or right + cx = 160; + cy = 160; + break; + case Surface.ROTATION_180: + // chin top + cx = 160; + cy = 145; + break; + case Surface.ROTATION_270: + cx = 145; + cy = 160; + break; + } + c.drawCircle(cx, cy, 160, mPaint); + + mSurface.unlockCanvasAndPost(c); + } + + // Note: caller responsible for being inside + // Surface.openTransaction() / closeTransaction() + public void setVisibility(boolean on) { + if (mSurfaceControl == null) { + return; + } + drawIfNeeded(); + if (on) { + mSurfaceControl.show(); + } else { + mSurfaceControl.hide(); + } + } + + void positionSurface(int dw, int dh, int rotation) { + if (mLastDW == dw && mLastDH == dh) { + return; + } + mLastDW = dw; + mLastDH = dh; + mSurfaceControl.setSize(dw, dh); + mDrawNeeded = true; + mRotation = rotation; + } + +} diff --git a/services/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java index c189ddd..c09ea5c 100644 --- a/services/java/com/android/server/wm/DimLayer.java +++ b/services/core/java/com/android/server/wm/DimLayer.java @@ -1,4 +1,18 @@ -// Copyright 2012 Google Inc. All Rights Reserved. +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.android.server.wm; @@ -51,9 +65,9 @@ public class DimLayer { /** Owning stack */ final TaskStack mStack; - DimLayer(WindowManagerService service, TaskStack stack) { + DimLayer(WindowManagerService service, TaskStack stack, DisplayContent displayContent) { mStack = stack; - mDisplayContent = stack.getDisplayContent(); + mDisplayContent = displayContent; final int displayId = mDisplayContent.getDisplayId(); if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId); SurfaceControl.openTransaction(); @@ -125,8 +139,54 @@ public class DimLayer { } } + /** + * @param layer The new layer value. + * @param inTransaction Whether the call is made within a surface transaction. + */ + void adjustSurface(int layer, boolean inTransaction) { + final int dw, dh; + final float xPos, yPos; + if (!mStack.isFullscreen()) { + dw = mBounds.width(); + dh = mBounds.height(); + xPos = mBounds.left; + yPos = mBounds.top; + } else { + // Set surface size to screen size. + final DisplayInfo info = mDisplayContent.getDisplayInfo(); + // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose + // a corner. + dw = (int) (info.logicalWidth * 1.5); + dh = (int) (info.logicalHeight * 1.5); + // back off position so 1/4 of Surface is before and 1/4 is after. + xPos = -1 * dw / 6; + yPos = -1 * dh / 6; + } + + try { + if (!inTransaction) { + SurfaceControl.openTransaction(); + } + mDimSurface.setPosition(xPos, yPos); + mDimSurface.setSize(dw, dh); + mDimSurface.setLayer(layer); + } catch (RuntimeException e) { + Slog.w(TAG, "Failure setting size or layer", e); + } finally { + if (!inTransaction) { + SurfaceControl.closeTransaction(); + } + } + mLastBounds.set(mBounds); + mLayer = layer; + } + + // Assumes that surface transactions are currently closed. void setBounds(Rect bounds) { mBounds.set(bounds); + if (isDimming() && !mLastBounds.equals(bounds)) { + adjustSurface(mLayer, false); + } } /** @@ -164,35 +224,8 @@ public class DimLayer { return; } - final int dw, dh; - final float xPos, yPos; - if (mStack.hasSibling()) { - dw = mBounds.width(); - dh = mBounds.height(); - xPos = mBounds.left; - yPos = mBounds.right; - } else { - // Set surface size to screen size. - final DisplayInfo info = mDisplayContent.getDisplayInfo(); - // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a - // corner. - dw = (int) (info.logicalWidth * 1.5); - dh = (int) (info.logicalHeight * 1.5); - // back off position so 1/4 of Surface is before and 1/4 is after. - xPos = -1 * dw / 6; - yPos = -1 * dh / 6; - } - if (!mLastBounds.equals(mBounds) || mLayer != layer) { - try { - mDimSurface.setPosition(xPos, yPos); - mDimSurface.setSize(dw, dh); - mDimSurface.setLayer(layer); - } catch (RuntimeException e) { - Slog.w(TAG, "Failure setting size or layer", e); - } - mLastBounds.set(mBounds); - mLayer = layer; + adjustSurface(layer, true); } long curTime = SystemClock.uptimeMillis(); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java new file mode 100644 index 0000000..d4bcd5c --- /dev/null +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -0,0 +1,415 @@ +/* + * Copyright (C) 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. + */ + +package com.android.server.wm; + +import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; +import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; +import static com.android.server.wm.WindowManagerService.TAG; + +import android.graphics.Rect; +import android.graphics.Region; +import android.util.Slog; +import android.view.Display; +import android.view.DisplayInfo; +import android.view.Surface; + +import java.io.PrintWriter; +import java.util.ArrayList; + +class DisplayContentList extends ArrayList<DisplayContent> { +} + +/** + * Utility class for keeping track of the WindowStates and other pertinent contents of a + * particular Display. + * + * IMPORTANT: No method from this class should ever be used without holding + * WindowManagerService.mWindowMap. + */ +class DisplayContent { + + /** Unique identifier of this stack. */ + private final int mDisplayId; + + /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element + * from mDisplayWindows; */ + private final WindowList mWindows = new WindowList(); + + // This protects the following display size properties, so that + // getDisplaySize() doesn't need to acquire the global lock. This is + // needed because the window manager sometimes needs to use ActivityThread + // while it has its global state locked (for example to load animation + // resources), but the ActivityThread also needs get the current display + // size sometimes when it has its package lock held. + // + // These will only be modified with both mWindowMap and mDisplaySizeLock + // held (in that order) so the window manager doesn't need to acquire this + // lock when needing these values in its normal operation. + final Object mDisplaySizeLock = new Object(); + int mInitialDisplayWidth = 0; + int mInitialDisplayHeight = 0; + int mInitialDisplayDensity = 0; + int mBaseDisplayWidth = 0; + int mBaseDisplayHeight = 0; + int mBaseDisplayDensity = 0; + private final DisplayInfo mDisplayInfo = new DisplayInfo(); + private final Display mDisplay; + + Rect mBaseDisplayRect = new Rect(); + Rect mContentRect = new Rect(); + + // Accessed directly by all users. + boolean layoutNeeded; + int pendingLayoutChanges; + final boolean isDefaultDisplay; + + /** Window tokens that are in the process of exiting, but still on screen for animations. */ + final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>(); + + /** Array containing all TaskStacks on this display. Array + * is stored in display order with the current bottom stack at 0. */ + private final ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>(); + + /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack + * (except a future lockscreen TaskStack) moves to the top. */ + private TaskStack mHomeStack = null; + + /** Detect user tapping outside of current focused stack bounds .*/ + StackTapPointerEventListener mTapDetector; + + /** Detect user tapping outside of current focused stack bounds .*/ + Region mTouchExcludeRegion = new Region(); + + /** Save allocating when calculating rects */ + Rect mTmpRect = new Rect(); + + /** For gathering Task objects in order. */ + final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>(); + + final WindowManagerService mService; + + /** Remove this display when animation on it has completed. */ + boolean mDeferredRemoval; + + /** + * @param display May not be null. + * @param service You know. + */ + DisplayContent(Display display, WindowManagerService service) { + mDisplay = display; + mDisplayId = display.getDisplayId(); + display.getDisplayInfo(mDisplayInfo); + isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY; + mService = service; + } + + int getDisplayId() { + return mDisplayId; + } + + WindowList getWindowList() { + return mWindows; + } + + Display getDisplay() { + return mDisplay; + } + + DisplayInfo getDisplayInfo() { + return mDisplayInfo; + } + + /** + * Returns true if the specified UID has access to this display. + */ + public boolean hasAccess(int uid) { + return mDisplay.hasAccess(uid); + } + + public boolean isPrivate() { + return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0; + } + + ArrayList<TaskStack> getStacks() { + return mStacks; + } + + /** + * Retrieve the tasks on this display in stack order from the bottommost TaskStack up. + * @return All the Tasks, in order, on this display. + */ + ArrayList<Task> getTasks() { + mTmpTaskHistory.clear(); + final int numStacks = mStacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + mTmpTaskHistory.addAll(mStacks.get(stackNdx).getTasks()); + } + return mTmpTaskHistory; + } + + TaskStack getHomeStack() { + if (mHomeStack == null) { + Slog.e(TAG, "getHomeStack: Returning null from this=" + this); + } + return mHomeStack; + } + + void updateDisplayInfo() { + mDisplay.getDisplayInfo(mDisplayInfo); + for (int i = mStacks.size() - 1; i >= 0; --i) { + mStacks.get(i).updateDisplayInfo(); + } + } + + void getLogicalDisplayRect(Rect out) { + // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked. + final int orientation = mDisplayInfo.rotation; + boolean rotated = (orientation == Surface.ROTATION_90 + || orientation == Surface.ROTATION_270); + final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; + final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; + int width = mDisplayInfo.logicalWidth; + int left = (physWidth - width) / 2; + int height = mDisplayInfo.logicalHeight; + int top = (physHeight - height) / 2; + out.set(left, top, left + width, top + height); + } + + /** Refer to {@link WindowManagerService#attachStack(int, int)} */ + void attachStack(TaskStack stack) { + if (stack.mStackId == HOME_STACK_ID) { + if (mHomeStack != null) { + throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first."); + } + mHomeStack = stack; + } + mStacks.add(stack); + layoutNeeded = true; + } + + void moveStack(TaskStack stack, boolean toTop) { + mStacks.remove(stack); + mStacks.add(toTop ? mStacks.size() : 0, stack); + } + + void detachStack(TaskStack stack) { + mStacks.remove(stack); + } + + /** + * Propagate the new bounds to all child stacks. + * @param contentRect The bounds to apply at the top level. + */ + void resize(Rect contentRect) { + mContentRect.set(contentRect); + } + + int stackIdFromPoint(int x, int y) { + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = mStacks.get(stackNdx); + stack.getBounds(mTmpRect); + if (mTmpRect.contains(x, y)) { + return stack.mStackId; + } + } + return -1; + } + + void setTouchExcludeRegion(TaskStack focusedStack) { + mTouchExcludeRegion.set(mBaseDisplayRect); + WindowList windows = getWindowList(); + for (int i = windows.size() - 1; i >= 0; --i) { + final WindowState win = windows.get(i); + final TaskStack stack = win.getStack(); + if (win.isVisibleLw() && stack != null && stack != focusedStack) { + mTmpRect.set(win.mVisibleFrame); + mTmpRect.intersect(win.mVisibleInsets); + mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE); + } + } + } + + void switchUserStacks(int newUserId) { + final WindowList windows = getWindowList(); + for (int i = 0; i < windows.size(); i++) { + final WindowState win = windows.get(i); + if (win.isHiddenFromUserLocked()) { + if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding " + + win + ", attrs=" + win.mAttrs.type + ", belonging to " + + win.mOwnerUid); + win.hideLw(false); + } + } + + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + mStacks.get(stackNdx).switchUser(newUserId); + } + } + + void resetAnimationBackgroundAnimator() { + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + mStacks.get(stackNdx).resetAnimationBackgroundAnimator(); + } + } + + boolean animateDimLayers() { + boolean result = false; + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + result |= mStacks.get(stackNdx).animateDimLayers(); + } + return result; + } + + void resetDimming() { + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + mStacks.get(stackNdx).resetDimmingTag(); + } + } + + boolean isDimming() { + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + if (mStacks.get(stackNdx).isDimming()) { + return true; + } + } + return false; + } + + void stopDimmingIfNeeded() { + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + mStacks.get(stackNdx).stopDimmingIfNeeded(); + } + } + + void close() { + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + mStacks.get(stackNdx).close(); + } + } + + boolean isAnimating() { + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = mStacks.get(stackNdx); + if (stack.isAnimating()) { + return true; + } + } + return false; + } + + void checkForDeferredActions() { + boolean animating = false; + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = mStacks.get(stackNdx); + if (stack.isAnimating()) { + animating = true; + } else { + if (stack.mDeferDetach) { + mService.detachStackLocked(this, stack); + } + final ArrayList<Task> tasks = stack.getTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + final Task task = tasks.get(taskNdx); + AppTokenList tokens = task.mAppTokens; + for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { + AppWindowToken wtoken = tokens.get(tokenNdx); + if (wtoken.mDeferRemoval) { + wtoken.mDeferRemoval = false; + mService.removeAppFromTaskLocked(wtoken); + } + } + if (task.mDeferRemoval) { + task.mDeferRemoval = false; + mService.removeTaskLocked(task); + } + } + } + } + if (!animating && mDeferredRemoval) { + mService.onDisplayRemoved(mDisplayId); + } + } + + public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId); + final String subPrefix = " " + prefix; + pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x"); + pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity); + pw.print("dpi"); + if (mInitialDisplayWidth != mBaseDisplayWidth + || mInitialDisplayHeight != mBaseDisplayHeight + || mInitialDisplayDensity != mBaseDisplayDensity) { + pw.print(" base="); + pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight); + pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi"); + } + pw.print(" cur="); + pw.print(mDisplayInfo.logicalWidth); + pw.print("x"); pw.print(mDisplayInfo.logicalHeight); + pw.print(" app="); + pw.print(mDisplayInfo.appWidth); + pw.print("x"); pw.print(mDisplayInfo.appHeight); + pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth); + pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight); + pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth); + pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight); + pw.print(subPrefix); pw.print("deferred="); pw.print(mDeferredRemoval); + pw.print(" layoutNeeded="); pw.println(layoutNeeded); + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = mStacks.get(stackNdx); + pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId); + stack.dump(prefix + " ", pw); + } + pw.println(); + pw.println(" Application tokens in bottom up Z order:"); + int ndx = 0; + final int numStacks = mStacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + AppTokenList tokens = tasks.get(taskNdx).mAppTokens; + for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { + final AppWindowToken wtoken = tokens.get(tokenNdx); + pw.print(" App #"); pw.print(ndx++); + pw.print(' '); pw.print(wtoken); pw.println(":"); + wtoken.dump(pw, " "); + } + } + } + if (ndx == 0) { + pw.println(" None"); + } + pw.println(); + if (!mExitingTokens.isEmpty()) { + pw.println(); + pw.println(" Exiting tokens:"); + for (int i=mExitingTokens.size()-1; i>=0; i--) { + WindowToken token = mExitingTokens.get(i); + pw.print(" Exiting #"); pw.print(i); + pw.print(' '); pw.print(token); + pw.println(':'); + token.dump(pw, " "); + } + } + pw.println(); + } + + @Override + public String toString() { + return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks; + } +} diff --git a/services/java/com/android/server/wm/DisplayMagnifier.java b/services/core/java/com/android/server/wm/DisplayMagnifier.java index 382d7b4..382d7b4 100644 --- a/services/java/com/android/server/wm/DisplayMagnifier.java +++ b/services/core/java/com/android/server/wm/DisplayMagnifier.java diff --git a/services/java/com/android/server/wm/DisplaySettings.java b/services/core/java/com/android/server/wm/DisplaySettings.java index 34d1a64..34d1a64 100644 --- a/services/java/com/android/server/wm/DisplaySettings.java +++ b/services/core/java/com/android/server/wm/DisplaySettings.java diff --git a/services/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index a737939..a737939 100644 --- a/services/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java diff --git a/services/java/com/android/server/wm/FakeWindowImpl.java b/services/core/java/com/android/server/wm/FakeWindowImpl.java index 5a3471b..5a3471b 100644 --- a/services/java/com/android/server/wm/FakeWindowImpl.java +++ b/services/core/java/com/android/server/wm/FakeWindowImpl.java diff --git a/services/java/com/android/server/wm/FocusedStackFrame.java b/services/core/java/com/android/server/wm/FocusedStackFrame.java index cc48b86..f1f5fe8 100644 --- a/services/java/com/android/server/wm/FocusedStackFrame.java +++ b/services/core/java/com/android/server/wm/FocusedStackFrame.java @@ -41,7 +41,7 @@ class FocusedStackFrame { private final SurfaceControl mSurfaceControl; private final Surface mSurface = new Surface(); private final Rect mLastBounds = new Rect(); - private final Rect mBounds = new Rect(); + final Rect mBounds = new Rect(); private final Rect mTmpDrawRect = new Rect(); public FocusedStackFrame(Display display, SurfaceSession session) { @@ -131,9 +131,9 @@ class FocusedStackFrame { } } - public void setBounds(Rect bounds) { - if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + bounds); - mBounds.set(bounds); + public void setBounds(TaskStack stack) { + stack.getBounds(mBounds); + if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + mBounds); } public void setLayer(int layer) { diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 3d2ec45..b27c8d6 100644 --- a/services/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -58,6 +58,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { private final Object mInputDevicesReadyMonitor = new Object(); private boolean mInputDevicesReady; + Rect mTmpRect = new Rect(); + public InputMonitor(WindowManagerService service) { mService = service; } @@ -175,7 +177,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { if (modal && child.mAppToken != null) { // Limit the outer touch to the activity stack region. flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; - inputWindowHandle.touchableRegion.set(child.getStackBounds()); + child.getStackBounds(mTmpRect); + inputWindowHandle.touchableRegion.set(mTmpRect); } else { // Not modal or full screen modal child.getTouchableRegion(inputWindowHandle.touchableRegion); @@ -352,17 +355,16 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { /* Provides an opportunity for the window manager policy to intercept early key * processing as soon as the key has been read from the device. */ @Override - public int interceptKeyBeforeQueueing( - KeyEvent event, int policyFlags, boolean isScreenOn) { - return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn); + public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { + return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags); } /* Provides an opportunity for the window manager policy to intercept early * motion event processing when the screen is off since these events are normally * dropped. */ @Override - public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { - return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); + public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) { + return mService.mPolicy.interceptWakeMotionBeforeQueueing(whenNanos, policyFlags); } /* Provides an opportunity for the window manager policy to process a key before diff --git a/services/java/com/android/server/wm/KeyguardDisableHandler.java b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java index 859df51..859df51 100644 --- a/services/java/com/android/server/wm/KeyguardDisableHandler.java +++ b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java diff --git a/services/java/com/android/server/wm/PointerEventDispatcher.java b/services/core/java/com/android/server/wm/PointerEventDispatcher.java index 6b0e4c9..6b0e4c9 100644 --- a/services/java/com/android/server/wm/PointerEventDispatcher.java +++ b/services/core/java/com/android/server/wm/PointerEventDispatcher.java diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index e630737..e630737 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java diff --git a/services/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 87cabc9..ca9076f 100644 --- a/services/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -293,7 +293,11 @@ final class Session extends IWindowSession.Stub // !!! FIXME: put all this heavy stuff onto the mH looper, as well as // the actual drag event dispatch stuff in the dragstate - Display display = callingWin.mDisplayContent.getDisplay(); + final DisplayContent displayContent = callingWin.getDisplayContent(); + if (displayContent == null) { + return false; + } + Display display = displayContent.getDisplay(); mService.mDragState.register(display); mService.mInputMonitor.updateInputWindowsLw(true /*force*/); if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel, diff --git a/services/java/com/android/server/wm/StackTapPointerEventListener.java b/services/core/java/com/android/server/wm/StackTapPointerEventListener.java index 19d8ab3..19d8ab3 100644 --- a/services/java/com/android/server/wm/StackTapPointerEventListener.java +++ b/services/core/java/com/android/server/wm/StackTapPointerEventListener.java diff --git a/services/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java index 7115b0f..7115b0f 100644 --- a/services/java/com/android/server/wm/StartingData.java +++ b/services/core/java/com/android/server/wm/StartingData.java diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java index fb5876b..fb5876b 100644 --- a/services/java/com/android/server/wm/StrictModeFlash.java +++ b/services/core/java/com/android/server/wm/StrictModeFlash.java diff --git a/services/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 13fdbc8..09c4e20 100644 --- a/services/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -16,15 +16,17 @@ package com.android.server.wm; +import static com.android.server.wm.WindowManagerService.TAG; + import android.util.EventLog; -import com.android.server.EventLogTags; +import android.util.Slog; class Task { -// private final String TAG = "TaskGroup"; TaskStack mStack; final AppTokenList mAppTokens = new AppTokenList(); final int taskId; final int mUserId; + boolean mDeferRemoval = false; Task(AppWindowToken wtoken, TaskStack stack, int userId) { taskId = wtoken.groupId; @@ -38,18 +40,24 @@ class Task { } void addAppToken(int addPos, AppWindowToken wtoken) { + final int lastPos = mAppTokens.size(); + if (addPos > lastPos) { + // We lost an app token. Don't crash though. + Slog.e(TAG, "Task.addAppToken: Out of bounds attempt token=" + wtoken + " addPos=" + + addPos + " lastPos=" + lastPos); + addPos = lastPos; + } mAppTokens.add(addPos, wtoken); + mDeferRemoval = false; } boolean removeAppToken(AppWindowToken wtoken) { - mAppTokens.remove(wtoken); + boolean removed = mAppTokens.remove(wtoken); if (mAppTokens.size() == 0) { EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, taskId, "removeAppToken: last token"); - mStack.removeTask(this); - return true; } - return false; + return removed; } @Override diff --git a/services/java/com/android/server/wm/TaskGroup.java b/services/core/java/com/android/server/wm/TaskGroup.java index 1f1dd58..1f1dd58 100644 --- a/services/java/com/android/server/wm/TaskGroup.java +++ b/services/core/java/com/android/server/wm/TaskGroup.java diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index cb29df4..81db8b3 100644 --- a/services/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -26,8 +26,6 @@ import android.util.Slog; import android.util.TypedValue; import com.android.server.EventLogTags; -import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; - import java.io.PrintWriter; import java.util.ArrayList; @@ -43,23 +41,29 @@ public class TaskStack { private final WindowManagerService mService; /** The display this stack sits under. */ - private final DisplayContent mDisplayContent; + private DisplayContent mDisplayContent; /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match * mTaskHistory in the ActivityStack with the same mStackId */ private final ArrayList<Task> mTasks = new ArrayList<Task>(); - /** The StackBox this sits in. */ - StackBox mStackBox; + /** For comparison with DisplayContent bounds. */ + private Rect mTmpRect = new Rect(); + + /** Content limits relative to the DisplayContent this sits in. */ + private Rect mBounds = new Rect(); + + /** Whether mBounds is fullscreen */ + private boolean mFullscreen = true; /** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */ - final DimLayer mDimLayer; + private DimLayer mDimLayer; /** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */ WindowStateAnimator mDimWinAnimator; /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */ - final DimLayer mAnimationBackgroundSurface; + DimLayer mAnimationBackgroundSurface; /** The particular window with an Animation with non-zero background color. */ WindowStateAnimator mAnimationBackgroundAnimator; @@ -68,12 +72,18 @@ public class TaskStack { * then stop any dimming. */ boolean mDimmingTag; - TaskStack(WindowManagerService service, int stackId, DisplayContent displayContent) { + /** Application tokens that are exiting, but still on screen for animations. */ + final AppTokenList mExitingAppTokens = new AppTokenList(); + + /** Detach this stack from its display when animation completes. */ + boolean mDeferDetach; + + TaskStack(WindowManagerService service, int stackId) { mService = service; mStackId = stackId; - mDisplayContent = displayContent; - mDimLayer = new DimLayer(service, this); - mAnimationBackgroundSurface = new DimLayer(service, this); + // TODO: remove bounds from log, they are always 0. + EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top, + mBounds.right, mBounds.bottom); } DisplayContent getDisplayContent() { @@ -84,12 +94,73 @@ public class TaskStack { return mTasks; } - boolean isHomeStack() { - return mStackId == HOME_STACK_ID; + void resizeWindows() { + final boolean underStatusBar = mBounds.top == 0; + + final ArrayList<WindowState> resizingWindows = mService.mResizingWindows; + for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { + final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; + for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { + final WindowState win = windows.get(winNdx); + if (!resizingWindows.contains(win)) { + if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG, + "setBounds: Resizing " + win); + resizingWindows.add(win); + } + win.mUnderStatusBar = underStatusBar; + } + } + } } - boolean hasSibling() { - return mStackBox.mParent != null; + boolean setBounds(Rect bounds) { + boolean oldFullscreen = mFullscreen; + if (mDisplayContent != null) { + mDisplayContent.getLogicalDisplayRect(mTmpRect); + mFullscreen = mTmpRect.equals(bounds); + } + + if (mBounds.equals(bounds) && oldFullscreen == mFullscreen) { + return false; + } + + mDimLayer.setBounds(bounds); + mAnimationBackgroundSurface.setBounds(bounds); + mBounds.set(bounds); + + return true; + } + + void getBounds(Rect out) { + out.set(mBounds); + } + + void updateDisplayInfo() { + if (mFullscreen && mDisplayContent != null) { + mDisplayContent.getLogicalDisplayRect(mTmpRect); + setBounds(mTmpRect); + } + } + + boolean isFullscreen() { + return mFullscreen; + } + + boolean isAnimating() { + for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { + final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; + for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { + if (windows.get(winNdx).mWinAnimator.isAnimating()) { + return true; + } + } + } + } + return false; } /** @@ -97,9 +168,7 @@ public class TaskStack { * @param task The task to add. * @param toTop Whether to add it to the top or bottom. */ - boolean addTask(Task task, boolean toTop) { - mStackBox.makeDirty(); - + void addTask(Task task, boolean toTop) { int stackNdx; if (!toTop) { stackNdx = 0; @@ -121,40 +190,60 @@ public class TaskStack { mTasks.add(stackNdx, task); task.mStack = this; - mDisplayContent.addTask(task, toTop); - return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID); + mDisplayContent.moveStack(this, true); + EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, stackNdx); } - boolean moveTaskToTop(Task task) { + void moveTaskToTop(Task task) { if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers=" + Debug.getCallers(6)); mTasks.remove(task); - return addTask(task, true); + addTask(task, true); } - boolean moveTaskToBottom(Task task) { + void moveTaskToBottom(Task task) { if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task); mTasks.remove(task); - return addTask(task, false); + addTask(task, false); } /** - * Delete a Task from this stack. If it is the last Task in the stack, remove this stack from - * its parent StackBox and merge the parent. + * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the + * back. * @param task The Task to delete. */ void removeTask(Task task) { if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task); - mStackBox.makeDirty(); mTasks.remove(task); - mDisplayContent.removeTask(task); + if (mDisplayContent != null) { + if (mTasks.isEmpty()) { + mDisplayContent.moveStack(this, false); + } + mDisplayContent.layoutNeeded = true; + } + } + + void attachDisplayContent(DisplayContent displayContent) { + if (mDisplayContent != null) { + throw new IllegalStateException("attachDisplayContent: Already attached"); + } + + mDisplayContent = displayContent; + mDimLayer = new DimLayer(mService, this, displayContent); + mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent); + updateDisplayInfo(); } - int remove() { + void detachDisplay() { + EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); + for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { + mService.tmpRemoveTaskWindowsLocked(mTasks.get(taskNdx)); + } mAnimationBackgroundSurface.destroySurface(); + mAnimationBackgroundSurface = null; mDimLayer.destroySurface(); - EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); - return mStackBox.remove(); + mDimLayer = null; + mDisplayContent = null; } void resetAnimationBackgroundAnimator() { @@ -259,28 +348,6 @@ public class TaskStack { } } - void setBounds(Rect bounds, boolean underStatusBar) { - mDimLayer.setBounds(bounds); - mAnimationBackgroundSurface.setBounds(bounds); - - final ArrayList<WindowState> resizingWindows = mService.mResizingWindows; - for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { - final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; - for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { - final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; - for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { - final WindowState win = windows.get(winNdx); - if (!resizingWindows.contains(win)) { - if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG, - "setBounds: Resizing " + win); - resizingWindows.add(win); - } - win.mUnderStatusBar = underStatusBar; - } - } - } - } - void switchUser(int userId) { int top = mTasks.size(); for (int taskNdx = 0; taskNdx < top; ++taskNdx) { @@ -293,8 +360,14 @@ public class TaskStack { } } + void close() { + mDimLayer.mDimSurface.destroy(); + mAnimationBackgroundSurface.mDimSurface.destroy(); + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mStackId="); pw.println(mStackId); + pw.print(prefix); pw.print("mDeferDetach="); pw.println(mDeferDetach); for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) { pw.print(prefix); pw.println(mTasks.get(taskNdx)); } @@ -307,6 +380,17 @@ public class TaskStack { mDimLayer.printTo(prefix, pw); pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator); } + if (!mExitingAppTokens.isEmpty()) { + pw.println(); + pw.println(" Exiting application tokens:"); + for (int i=mExitingAppTokens.size()-1; i>=0; i--) { + WindowToken token = mExitingAppTokens.get(i); + pw.print(" Exiting App #"); pw.print(i); + pw.print(' '); pw.print(token); + pw.println(':'); + token.dump(pw, " "); + } + } } @Override diff --git a/services/java/com/android/server/wm/ViewServer.java b/services/core/java/com/android/server/wm/ViewServer.java index a763e2c..a763e2c 100644 --- a/services/java/com/android/server/wm/ViewServer.java +++ b/services/core/java/com/android/server/wm/ViewServer.java diff --git a/services/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java index e226e3d..e226e3d 100644 --- a/services/java/com/android/server/wm/Watermark.java +++ b/services/core/java/com/android/server/wm/Watermark.java diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 91f15f3..0c68258 100644 --- a/services/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -1,4 +1,18 @@ -// Copyright 2012 Google Inc. All Rights Reserved. +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.android.server.wm; @@ -64,7 +78,7 @@ public class WindowAnimator { Object mLastWindowFreezeSource; SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = - new SparseArray<WindowAnimator.DisplayContentsAnimator>(2); + new SparseArray<DisplayContentsAnimator>(2); boolean mInitialized = false; @@ -151,14 +165,33 @@ public class WindowAnimator { } private void updateAppWindowsLocked(int displayId) { - final DisplayContent displayContent = mService.getDisplayContentLocked(displayId); - final ArrayList<Task> tasks = displayContent.getTasks(); - final int numTasks = tasks.size(); - for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) { - final AppTokenList tokens = tasks.get(taskNdx).mAppTokens; - final int numTokens = tokens.size(); - for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) { - final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator; + ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks(); + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = stacks.get(stackNdx); + final ArrayList<Task> tasks = stack.getTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + final AppTokenList tokens = tasks.get(taskNdx).mAppTokens; + for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { + final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator; + final boolean wasAnimating = appAnimator.animation != null + && appAnimator.animation != AppWindowAnimator.sDummyAnimation; + if (appAnimator.stepAnimationLocked(mCurrentTime)) { + mAnimating = true; + } else if (wasAnimating) { + // stopped animating, do one more pass through the layout + setAppLayoutChanges(appAnimator, + WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER, + "appToken " + appAnimator.mAppToken + " done"); + if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG, + "updateWindowsApps...: done animating " + appAnimator.mAppToken); + } + } + } + + final AppTokenList exitingAppTokens = stack.mExitingAppTokens; + final int NEAT = exitingAppTokens.size(); + for (int i = 0; i < NEAT; i++) { + final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator; final boolean wasAnimating = appAnimator.animation != null && appAnimator.animation != AppWindowAnimator.sDummyAnimation; if (appAnimator.stepAnimationLocked(mCurrentTime)) { @@ -166,29 +199,12 @@ public class WindowAnimator { } else if (wasAnimating) { // stopped animating, do one more pass through the layout setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER, - "appToken " + appAnimator.mAppToken + " done"); + "exiting appToken " + appAnimator.mAppToken + " done"); if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG, - "updateWindowsApps...: done animating " + appAnimator.mAppToken); + "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken); } } } - - final AppTokenList exitingAppTokens = displayContent.mExitingAppTokens; - final int NEAT = exitingAppTokens.size(); - for (int i = 0; i < NEAT; i++) { - final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator; - final boolean wasAnimating = appAnimator.animation != null - && appAnimator.animation != AppWindowAnimator.sDummyAnimation; - if (appAnimator.stepAnimationLocked(mCurrentTime)) { - mAnimating = true; - } else if (wasAnimating) { - // stopped animating, do one more pass through the layout - setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER, - "exiting appToken " + appAnimator.mAppToken + " done"); - if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG, - "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken); - } - } } private void updateWindowsLocked(final int displayId) { @@ -449,11 +465,6 @@ public class WindowAnimator { } } - private void performAnimationsLocked(final int displayId) { - updateWindowsLocked(displayId); - updateWallpaperLocked(displayId); - } - /** Locked on mService.mWindowMap. */ private void animateLocked() { @@ -494,7 +505,8 @@ public class WindowAnimator { // Update animations of all applications, including those // associated with exiting/removed apps - performAnimationsLocked(displayId); + updateWindowsLocked(displayId); + updateWallpaperLocked(displayId); final WindowList windows = mService.getWindowListLocked(displayId); final int N = windows.size(); @@ -642,11 +654,16 @@ public class WindowAnimator { } int getPendingLayoutChanges(final int displayId) { + if (displayId < 0) { + return 0; + } return mService.getDisplayContentLocked(displayId).pendingLayoutChanges; } void setPendingLayoutChanges(final int displayId, final int changes) { - mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes; + if (displayId >= 0) { + mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes; + } } void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) { @@ -655,7 +672,7 @@ public class WindowAnimator { WindowList windows = appAnimator.mAppToken.allAppWindows; for (int i = windows.size() - 1; i >= 0; i--) { final int displayId = windows.get(i).getDisplayId(); - if (displays.indexOfKey(displayId) < 0) { + if (displayId >= 0 && displays.indexOfKey(displayId) < 0) { setPendingLayoutChanges(displayId, changes); if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { mService.debugLayoutRepeats(s, getPendingLayoutChanges(displayId)); @@ -676,10 +693,15 @@ public class WindowAnimator { } void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) { - getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation; + if (displayId >= 0) { + getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation; + } } ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) { + if (displayId < 0) { + return null; + } return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation; } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 737f384..081cffd 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -18,11 +18,10 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.*; -import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; - import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import android.app.AppOpsManager; +import android.util.ArraySet; import android.util.TimeUtils; import android.view.IWindowId; @@ -35,17 +34,16 @@ import com.android.internal.view.IInputMethodClient; import com.android.internal.view.IInputMethodManager; import com.android.internal.view.WindowManagerPolicyThread; import com.android.server.AttributeCache; +import com.android.server.DisplayThread; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.UiThread; import com.android.server.Watchdog; import com.android.server.am.BatteryStatsService; -import com.android.server.display.DisplayManagerService; import com.android.server.input.InputManagerService; -import com.android.server.power.PowerManagerService; import com.android.server.power.ShutdownThread; import android.Manifest; -import android.app.ActivityManager.StackBoxInfo; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.StatusBarManager; @@ -69,6 +67,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManagerInternal; import android.os.Binder; import android.os.Bundle; import android.os.Debug; @@ -80,6 +79,7 @@ import android.os.Message; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.PowerManager; +import android.os.PowerManagerInternal; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -117,6 +117,7 @@ import android.view.InputEventReceiver; import android.view.KeyEvent; import android.view.MagnificationSpec; import android.view.MotionEvent; +import android.view.WindowManagerInternal; import android.view.Surface.OutOfResourcesException; import android.view.Surface; import android.view.SurfaceControl; @@ -155,8 +156,7 @@ import java.util.List; /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub - implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs, - DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener { + implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { static final String TAG = "WindowManager"; static final boolean DEBUG = false; static final boolean DEBUG_ADD_REMOVE = false; @@ -188,6 +188,7 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean DEBUG_WINDOW_TRACE = false; static final boolean DEBUG_TASK_MOVEMENT = false; static final boolean DEBUG_STACK = false; + static final boolean DEBUG_DISPLAY = false; static final boolean SHOW_SURFACE_ALLOC = false; static final boolean SHOW_TRANSACTIONS = false; static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS; @@ -272,10 +273,10 @@ public class WindowManagerService extends IWindowManager.Stub // Default input dispatching timeout in nanoseconds. static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L; - /** Minimum value for createStack and resizeStack weight value */ + /** Minimum value for attachStack and resizeStack weight value */ public static final float STACK_WEIGHT_MIN = 0.2f; - /** Maximum value for createStack and resizeStack weight value */ + /** Maximum value for attachStack and resizeStack weight value */ public static final float STACK_WEIGHT_MAX = 0.8f; static final int UPDATE_FOCUS_NORMAL = 0; @@ -293,8 +294,6 @@ public class WindowManagerService extends IWindowManager.Stub final private KeyguardDisableHandler mKeyguardDisableHandler; - private final boolean mHeadless; - final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -369,6 +368,11 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>(); /** + * Stacks whose animations have ended and whose tasks, apps, selves may now be removed. + */ + final ArraySet<TaskStack> mPendingStacksRemove = new ArraySet<TaskStack>(); + + /** * Used when processing mPendingRemove to avoid working on the original array. */ WindowState[] mPendingRemoveTmp = new WindowState[20]; @@ -415,6 +419,7 @@ public class WindowManagerService extends IWindowManager.Stub final SurfaceSession mFxSession; Watermark mWatermark; StrictModeFlash mStrictModeFlash; + CircularDisplayMask mCircularDisplayMask; FocusedStackFrame mFocusedStackFrame; int mFocusedStackLayer; @@ -541,14 +546,15 @@ public class WindowManagerService extends IWindowManager.Stub AppWindowToken mFocusedApp = null; - PowerManagerService mPowerManager; + PowerManager mPowerManager; + PowerManagerInternal mPowerManagerInternal; float mWindowAnimationScale = 1.0f; float mTransitionAnimationScale = 1.0f; float mAnimatorDurationScale = 1.0f; final InputManagerService mInputManager; - final DisplayManagerService mDisplayManagerService; + final DisplayManagerInternal mDisplayManagerInternal; final DisplayManager mDisplayManager; // Who is holding the screen on. @@ -607,6 +613,9 @@ public class WindowManagerService extends IWindowManager.Stub final WindowAnimator mAnimator; SparseArray<Task> mTaskIdToTask = new SparseArray<Task>(); + + /** All of the TaskStacks in the window manager, unordered. For an ordered list call + * DisplayContent.getStacks(). */ SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>(); private final PointerEventDispatcher mPointerEventDispatcher; @@ -701,23 +710,22 @@ public class WindowManagerService extends IWindowManager.Stub final boolean mOnlyCore; public static WindowManagerService main(final Context context, - final PowerManagerService pm, final DisplayManagerService dm, - final InputManagerService im, final Handler wmHandler, + final InputManagerService im, final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore) { final WindowManagerService[] holder = new WindowManagerService[1]; - wmHandler.runWithScissors(new Runnable() { + DisplayThread.getHandler().runWithScissors(new Runnable() { @Override public void run() { - holder[0] = new WindowManagerService(context, pm, dm, im, + holder[0] = new WindowManagerService(context, im, haveInputMethods, showBootMsgs, onlyCore); } }, 0); return holder[0]; } - private void initPolicy(Handler uiHandler) { - uiHandler.runWithScissors(new Runnable() { + private void initPolicy() { + UiThread.getHandler().runWithScissors(new Runnable() { @Override public void run() { WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper()); @@ -730,8 +738,7 @@ public class WindowManagerService extends IWindowManager.Stub }, 0); } - private WindowManagerService(Context context, PowerManagerService pm, - DisplayManagerService displayManager, InputManagerService inputManager, + private WindowManagerService(Context context, InputManagerService inputManager, boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) { mContext = context; mHaveInputMethods = haveInputMethods; @@ -740,8 +747,7 @@ public class WindowManagerService extends IWindowManager.Stub mLimitedAlphaCompositing = context.getResources().getBoolean( com.android.internal.R.bool.config_sf_limitedAlpha); mInputManager = inputManager; // Must be before createDisplayContentLocked. - mDisplayManagerService = displayManager; - mHeadless = displayManager.isHeadless(); + mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mDisplaySettings = new DisplaySettings(context); mDisplaySettings.readSettingsLocked(); @@ -749,7 +755,6 @@ public class WindowManagerService extends IWindowManager.Stub mFxSession = new SurfaceSession(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); - mDisplayManager.registerDisplayListener(this, null); Display[] displays = mDisplayManager.getDisplays(); for (Display display : displays) { createDisplayContentLocked(display); @@ -757,10 +762,11 @@ public class WindowManagerService extends IWindowManager.Stub mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy); - mPowerManager = pm; - mPowerManager.setPolicy(mPolicy); - PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN"); + mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); + mPowerManagerInternal.setPolicy(mPolicy); // TODO: register as local service instead + mScreenFrozenLock = mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN"); mScreenFrozenLock.setReferenceCounted(false); mAppTransition = new AppTransition(context, mH); @@ -790,13 +796,13 @@ public class WindowManagerService extends IWindowManager.Stub filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); mContext.registerReceiver(mBroadcastReceiver, filter); - mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK - | PowerManager.ON_AFTER_RELEASE, TAG); + mHoldingScreenWakeLock = mPowerManager.newWakeLock( + PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG); mHoldingScreenWakeLock.setReferenceCounted(false); mAnimator = new WindowAnimator(this); - initPolicy(UiThread.getHandler()); + initPolicy(); // Add ourself to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); @@ -809,6 +815,9 @@ public class WindowManagerService extends IWindowManager.Stub } finally { SurfaceControl.closeTransaction(); } + + LocalServices.addService(WindowManagerInternal.class, new LocalService()); + showCircularDisplayMaskIfNeeded(); } public InputMonitor getInputMonitor() { @@ -878,7 +887,7 @@ public class WindowManagerService extends IWindowManager.Stub final int count = token.windows.size(); for (int i = 0; i < count; i++) { final WindowState win = token.windows.get(i); - if (win.mDisplayContent == displayContent) { + if (win.getDisplayContent() == displayContent) { windowList.add(win); } } @@ -909,7 +918,11 @@ public class WindowManagerService extends IWindowManager.Stub private int addAppWindowToListLocked(final WindowState win) { final IWindow client = win.mClient; final WindowToken token = win.mToken; - final DisplayContent displayContent = win.mDisplayContent; + final DisplayContent displayContent = win.getDisplayContent(); + if (displayContent == null) { + // It doesn't matter this display is going away. + return 0; + } final WindowList windows = win.getWindowList(); final int N = windows.size(); @@ -1086,7 +1099,10 @@ public class WindowManagerService extends IWindowManager.Stub private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) { final WindowToken token = win.mToken; - final DisplayContent displayContent = win.mDisplayContent; + final DisplayContent displayContent = win.getDisplayContent(); + if (displayContent == null) { + return; + } final WindowState attached = win.mAttachedWindow; WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent); @@ -2020,7 +2036,10 @@ public class WindowManagerService extends IWindowManager.Stub } void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) { - final DisplayContent displayContent = changingTarget.mDisplayContent; + final DisplayContent displayContent = changingTarget.getDisplayContent(); + if (displayContent == null) { + return; + } final DisplayInfo displayInfo = displayContent.getDisplayInfo(); final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; @@ -2080,7 +2099,10 @@ public class WindowManagerService extends IWindowManager.Stub void updateWallpaperVisibilityLocked() { final boolean visible = isWallpaperVisible(mWallpaperTarget); - final DisplayContent displayContent = mWallpaperTarget.mDisplayContent; + final DisplayContent displayContent = mWallpaperTarget.getDisplayContent(); + if (displayContent == null) { + return; + } final DisplayInfo displayInfo = displayContent.getDisplayInfo(); final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; @@ -2238,6 +2260,11 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerGlobal.ADD_APP_EXITING; } + if (win.getDisplayContent() == null) { + Slog.w(TAG, "Adding window to Display that has been removed."); + return WindowManagerGlobal.ADD_INVALID_DISPLAY; + } + mPolicy.adjustWindowParamsLw(win.mAttrs); win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs)); @@ -2380,11 +2407,6 @@ public class WindowManagerService extends IWindowManager.Stub } public void removeWindowLocked(Session session, WindowState win) { - removeWindowLocked(session, win, false); - } - - private void removeWindowLocked(Session session, WindowState win, - boolean forceRemove) { if (win.mAttrs.type == TYPE_APPLICATION_STARTING) { if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Starting window removed " + win); removeStartingWindowTimeout(win.mAppToken); @@ -2435,12 +2457,15 @@ public class WindowManagerService extends IWindowManager.Stub mDisplayMagnifier.onWindowTransitionLocked(win, transit); } } - if (!forceRemove && (win.mExiting || win.mWinAnimator.isAnimating())) { + if (win.mExiting || win.mWinAnimator.isAnimating()) { // The exit animation is running... wait for it! //Slog.i(TAG, "*** Running exit animation..."); win.mExiting = true; win.mRemoveOnExit = true; - win.mDisplayContent.layoutNeeded = true; + final DisplayContent displayContent = win.getDisplayContent(); + if (displayContent != null) { + displayContent.layoutNeeded = true; + } updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/); performLayoutAndPlaceSurfacesLocked(); @@ -2497,8 +2522,6 @@ public class WindowManagerService extends IWindowManager.Stub mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage()); } - final WindowList windows = win.getWindowList(); - windows.remove(win); mPendingRemove.remove(win); mResizingWindows.remove(win); mWindowsChanged = true; @@ -2554,12 +2577,19 @@ public class WindowManagerService extends IWindowManager.Stub WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; } - if (!mInLayout) { - assignLayersLocked(windows); - win.mDisplayContent.layoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - if (win.mAppToken != null) { - win.mAppToken.updateReportedVisibilityLocked(); + final WindowList windows = win.getWindowList(); + if (windows != null) { + windows.remove(win); + if (!mInLayout) { + assignLayersLocked(windows); + final DisplayContent displayContent = win.getDisplayContent(); + if (displayContent != null) { + displayContent.layoutNeeded = true; + } + performLayoutAndPlaceSurfacesLocked(); + if (win.mAppToken != null) { + win.mAppToken.updateReportedVisibilityLocked(); + } } } @@ -2634,7 +2664,10 @@ public class WindowManagerService extends IWindowManager.Stub w.mGivenVisibleInsets.scale(w.mGlobalScale); w.mGivenTouchableRegion.scale(w.mGlobalScale); } - w.mDisplayContent.layoutNeeded = true; + final DisplayContent displayContent = w.getDisplayContent(); + if (displayContent != null) { + displayContent.layoutNeeded = true; + } performLayoutAndPlaceSurfacesLocked(); } } @@ -2720,7 +2753,12 @@ public class WindowManagerService extends IWindowManager.Stub mTmpFloats[Matrix.MSKEW_X] = dsdy; mTmpFloats[Matrix.MSCALE_Y] = dtdy; matrix.setValues(mTmpFloats); - final DisplayInfo displayInfo = window.mDisplayContent.getDisplayInfo(); + final DisplayContent displayContent = window.getDisplayContent(); + if (displayContent == null) { + return; + } + + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); final RectF dispRect = new RectF(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); matrix.mapRect(dispRect); @@ -2729,7 +2767,7 @@ public class WindowManagerService extends IWindowManager.Stub window.mGivenTouchableRegion.op((int)dispRect.left, (int)dispRect.top, (int)dispRect.right, (int)dispRect.bottom, Region.Op.DIFFERENCE); window.mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; - window.mDisplayContent.layoutNeeded = true; + displayContent.layoutNeeded = true; performLayoutAndPlaceSurfacesLocked(); } @@ -3010,7 +3048,10 @@ public class WindowManagerService extends IWindowManager.Stub WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; } - win.mDisplayContent.layoutNeeded = true; + final DisplayContent displayContent = win.getDisplayContent(); + if (displayContent != null) { + displayContent.layoutNeeded = true; + } win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; configChanged = updateOrientationFromAppTokensLocked(false); performLayoutAndPlaceSurfacesLocked(); @@ -3104,7 +3145,10 @@ public class WindowManagerService extends IWindowManager.Stub getDefaultDisplayContentLocked().pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; } - win.mDisplayContent.layoutNeeded = true; + final DisplayContent displayContent = win.getDisplayContent(); + if (displayContent != null) { + displayContent.layoutNeeded = true; + } requestTraversalLocked(); } } @@ -3362,7 +3406,7 @@ public class WindowManagerService extends IWindowManager.Stub for (int i=0; i<N; i++) { WindowState win = wtoken.windows.get(i); - displayContent = win.mDisplayContent; + displayContent = win.getDisplayContent(); if (win.mWinAnimator.isAnimating()) { delayed = true; @@ -3377,7 +3421,9 @@ public class WindowManagerService extends IWindowManager.Stub WindowManagerPolicy.TRANSIT_EXIT); } changed = true; - displayContent.layoutNeeded = true; + if (displayContent != null) { + displayContent.layoutNeeded = true; + } } } @@ -3390,7 +3436,9 @@ public class WindowManagerService extends IWindowManager.Stub } if (delayed) { - displayContent.mExitingTokens.add(wtoken); + if (displayContent != null) { + displayContent.mExitingTokens.add(wtoken); + } } else if (wtoken.windowType == TYPE_WALLPAPER) { mWallpaperTokens.remove(wtoken); } @@ -3405,6 +3453,8 @@ public class WindowManagerService extends IWindowManager.Stub } private Task createTask(int taskId, int stackId, int userId, AppWindowToken atoken) { + if (DEBUG_STACK) Slog.i(TAG, "createTask: taskId=" + taskId + " stackId=" + stackId + + " atoken=" + atoken); final TaskStack stack = mStackIdToStack.get(stackId); if (stack == null) { throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId); @@ -3458,7 +3508,7 @@ public class WindowManagerService extends IWindowManager.Stub Task task = mTaskIdToTask.get(taskId); if (task == null) { - task = createTask(taskId, stackId, userId, atoken); + createTask(taskId, stackId, userId, atoken); } else { task.addAppToken(addPos, atoken); } @@ -3486,8 +3536,8 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token); return; } - Task oldTask = mTaskIdToTask.get(atoken.groupId); - oldTask.removeAppToken(atoken); + final Task oldTask = mTaskIdToTask.get(atoken.groupId); + removeAppFromTaskLocked(atoken); atoken.groupId = groupId; Task newTask = mTaskIdToTask.get(groupId); @@ -3638,7 +3688,7 @@ public class WindowManagerService extends IWindowManager.Stub if (freezeThisOneIfNeeded != null) { AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded); if (atoken != null) { - startAppFreezingScreenLocked(atoken, ActivityInfo.CONFIG_ORIENTATION); + startAppFreezingScreenLocked(atoken); } } config = computeNewConfigurationLocked(); @@ -3780,7 +3830,10 @@ public class WindowManagerService extends IWindowManager.Stub if (mFocusedApp != null) { Task task = mTaskIdToTask.get(mFocusedApp.groupId); stack = task.mStack; - task.getDisplayContent().setTouchExcludeRegion(stack); + final DisplayContent displayContent = task.getDisplayContent(); + if (displayContent != null) { + displayContent.setTouchExcludeRegion(stack); + } } else { stack = null; } @@ -3790,10 +3843,8 @@ public class WindowManagerService extends IWindowManager.Stub if (stack == null) { mFocusedStackFrame.setVisibility(false); } else { - final StackBox box = stack.mStackBox; - final Rect bounds = box.mBounds; - final boolean multipleStacks = box.mParent != null; - mFocusedStackFrame.setBounds(bounds); + mFocusedStackFrame.setBounds(stack); + final boolean multipleStacks = !stack.isFullscreen(); mFocusedStackFrame.setVisibility(multipleStacks); } } finally { @@ -3810,27 +3861,23 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized(mWindowMap) { - boolean changed = false; + final AppWindowToken newFocus; if (token == null) { if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp); - changed = mFocusedApp != null; - mFocusedApp = null; - if (changed) { - mInputMonitor.setFocusedAppLw(null); - } + newFocus = null; } else { - AppWindowToken newFocus = findAppWindowToken(token); + newFocus = findAppWindowToken(token); if (newFocus == null) { Slog.w(TAG, "Attempted to set focus to non-existing app token: " + token); - return; } - changed = mFocusedApp != newFocus; if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Set focused app to: " + newFocus + " old focus=" + mFocusedApp + " moveFocusNow=" + moveFocusNow); + } + + final boolean changed = mFocusedApp != newFocus; + if (changed) { mFocusedApp = newFocus; - if (changed) { - mInputMonitor.setFocusedAppLw(newFocus); - } + mInputMonitor.setFocusedAppLw(null); } if (moveFocusNow && changed) { @@ -4171,10 +4218,25 @@ public class WindowManagerService extends IWindowManager.Stub AppWindowToken atoken = findAppWindowToken(token); if (atoken != null) { atoken.appFullscreen = toOpaque; + // When making translucent, wait until windows below have been drawn. + if (toOpaque) { + // Making opaque so do it now. + setWindowOpaque(token, true); + } requestTraversal(); } } + public void setWindowOpaque(IBinder token, boolean isOpaque) { + AppWindowToken wtoken = findAppWindowToken(token); + if (wtoken != null) { + WindowState win = wtoken.findMainWindow(); + if (win != null) { + win.mWinAnimator.setOpaque(isOpaque); + } + } + } + boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp, boolean visible, int transit, boolean performLayout) { boolean delayed = false; @@ -4231,7 +4293,10 @@ public class WindowManagerService extends IWindowManager.Stub } } changed = true; - win.mDisplayContent.layoutNeeded = true; + final DisplayContent displayContent = win.getDisplayContent(); + if (displayContent != null) { + displayContent.layoutNeeded = true; + } } } else if (win.isVisibleNow()) { if (!runningAppAnimation) { @@ -4245,7 +4310,10 @@ public class WindowManagerService extends IWindowManager.Stub } } changed = true; - win.mDisplayContent.layoutNeeded = true; + final DisplayContent displayContent = win.getDisplayContent(); + if (displayContent != null) { + displayContent.layoutNeeded = true; + } } } @@ -4393,7 +4461,10 @@ public class WindowManagerService extends IWindowManager.Stub } w.mLastFreezeDuration = 0; unfrozeWindows = true; - w.mDisplayContent.layoutNeeded = true; + final DisplayContent displayContent = w.getDisplayContent(); + if (displayContent != null) { + displayContent.layoutNeeded = true; + } } } if (force || unfrozeWindows) { @@ -4413,8 +4484,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void startAppFreezingScreenLocked(AppWindowToken wtoken, - int configChanges) { + private void startAppFreezingScreenLocked(AppWindowToken wtoken) { if (DEBUG_ORIENTATION) { RuntimeException e = null; if (!HIDE_STACK_CRAWLS) { @@ -4463,7 +4533,7 @@ public class WindowManagerService extends IWindowManager.Stub return; } final long origId = Binder.clearCallingIdentity(); - startAppFreezingScreenLocked(wtoken, configChanges); + startAppFreezingScreenLocked(wtoken); Binder.restoreCallingIdentity(origId); } } @@ -4488,6 +4558,15 @@ public class WindowManagerService extends IWindowManager.Stub } } + void removeAppFromTaskLocked(AppWindowToken wtoken) { + final Task task = mTaskIdToTask.get(wtoken.groupId); + if (task != null) { + if (!task.removeAppToken(wtoken)) { + Slog.e(TAG, "removeAppFromTaskLocked: token=" + wtoken + " not found."); + } + } + } + @Override public void removeAppToken(IBinder token) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, @@ -4520,26 +4599,24 @@ public class WindowManagerService extends IWindowManager.Stub TAG, "Removing app " + wtoken + " delayed=" + delayed + " animation=" + wtoken.mAppAnimator.animation + " animating=" + wtoken.mAppAnimator.animating); - final Task task = mTaskIdToTask.get(wtoken.groupId); - DisplayContent displayContent = task.getDisplayContent(); + if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "removeAppToken: " + + wtoken + " delayed=" + delayed + " Callers=" + Debug.getCallers(4)); + final TaskStack stack = mTaskIdToTask.get(wtoken.groupId).mStack; if (delayed) { // set the token aside because it has an active animation to be finished if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "removeAppToken make exiting: " + wtoken); - displayContent.mExitingAppTokens.add(wtoken); + stack.mExitingAppTokens.add(wtoken); + wtoken.mDeferRemoval = true; } else { // Make sure there is no animation running on this token, // so any windows associated with it will be removed as // soon as their animations are complete wtoken.mAppAnimator.clearAnimation(); wtoken.mAppAnimator.animating = false; + removeAppFromTaskLocked(wtoken); } - if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, - "removeAppToken: " + wtoken); - if (task.removeAppToken(wtoken)) { - mTaskIdToTask.delete(wtoken.groupId); - } wtoken.removed = true; if (wtoken.startingData != null) { startingToken = wtoken; @@ -4584,13 +4661,15 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendMessage(m); } } + private boolean tmpRemoveAppWindowsLocked(WindowToken token) { - final int NW = token.windows.size(); + WindowList windows = token.windows; + final int NW = windows.size(); if (NW > 0) { mWindowsChanged = true; } - for (int i=0; i<NW; i++) { - WindowState win = token.windows.get(i); + for (int i = 0; i < NW; i++) { + WindowState win = windows.get(i); if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win); win.getWindowList().remove(win); int j = win.mChildWindows.size(); @@ -4606,29 +4685,32 @@ public class WindowManagerService extends IWindowManager.Stub } void dumpAppTokensLocked() { - final int numDisplays = mDisplayContents.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); - Slog.v(TAG, " Display " + displayContent.getDisplayId()); - final ArrayList<Task> tasks = displayContent.getTasks(); - int i = displayContent.numTokens(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { - AppTokenList tokens = tasks.get(taskNdx).mAppTokens; - for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { - final AppWindowToken wtoken = tokens.get(tokenNdx); - Slog.v(TAG, " #" + --i + ": " + wtoken.token); + final int numStacks = mStackIdToStack.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final TaskStack stack = mStackIdToStack.valueAt(stackNdx); + Slog.v(TAG, " Stack #" + stack.mStackId + " tasks from bottom to top:"); + final ArrayList<Task> tasks = stack.getTasks(); + final int numTasks = tasks.size(); + for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) { + final Task task = tasks.get(taskNdx); + Slog.v(TAG, " Task #" + task.taskId + " activities from bottom to top:"); + AppTokenList tokens = task.mAppTokens; + final int numTokens = tokens.size(); + for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) { + Slog.v(TAG, " activity #" + tokenNdx + ": " + tokens.get(tokenNdx).token); } } } } void dumpWindowsLocked() { - int i = 0; final int numDisplays = mDisplayContents.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); + final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); + Slog.v(TAG, " Display #" + displayContent.getDisplayId()); + final WindowList windows = displayContent.getWindowList(); for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { - Slog.v(TAG, " #" + i++ + ": " + windows.get(winNdx)); + Slog.v(TAG, " #" + winNdx + ": " + windows.get(winNdx)); } } } @@ -4740,23 +4822,28 @@ public class WindowManagerService extends IWindowManager.Stub final int NW = token.windows.size(); for (int i=0; i<NW; i++) { final WindowState win = token.windows.get(i); - if (win.mDisplayContent == displayContent) { + final DisplayContent winDisplayContent = win.getDisplayContent(); + if (winDisplayContent == displayContent || winDisplayContent == null) { + win.mDisplayContent = displayContent; index = reAddWindowLocked(index, win); } } return index; } + void tmpRemoveTaskWindowsLocked(Task task) { + AppTokenList tokens = task.mAppTokens; + for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { + tmpRemoveAppWindowsLocked(tokens.get(tokenNdx)); + } + } + void moveStackWindowsLocked(DisplayContent displayContent) { // First remove all of the windows from the list. final ArrayList<Task> tasks = displayContent.getTasks(); final int numTasks = tasks.size(); for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) { - AppTokenList tokens = tasks.get(taskNdx).mAppTokens; - final int numTokens = tokens.size(); - for (int tokenNdx = numTokens - 1; tokenNdx >= 0; --tokenNdx) { - tmpRemoveAppWindowsLocked(tokens.get(tokenNdx)); - } + tmpRemoveTaskWindowsLocked(tasks.get(taskNdx)); } // And now add them back at the correct place. @@ -4800,10 +4887,14 @@ public class WindowManagerService extends IWindowManager.Stub } final TaskStack stack = task.mStack; final DisplayContent displayContent = task.getDisplayContent(); - final boolean isHomeStackTask = stack.isHomeStack(); - if (isHomeStackTask != displayContent.homeOnTop()) { - // First move the stack itself. - displayContent.moveHomeStackBox(isHomeStackTask); + displayContent.moveStack(stack, true); + if (displayContent.isDefaultDisplay) { + final TaskStack homeStack = displayContent.getHomeStack(); + if (homeStack != stack) { + // When a non-home stack moves to the top, the home stack moves to the + // bottom. + displayContent.moveStack(homeStack, false); + } } stack.moveTaskToTop(task); } @@ -4832,54 +4923,74 @@ public class WindowManagerService extends IWindowManager.Stub } /** - * Create a new TaskStack and place it next to an existing stack. + * Create a new TaskStack and place it on a DisplayContent. * @param stackId The unique identifier of the new stack. - * @param relativeStackBoxId The existing stack that this stack goes before or after. - * @param position One of: - * {@link StackBox#TASK_STACK_GOES_BEFORE} - * {@link StackBox#TASK_STACK_GOES_AFTER} - * {@link StackBox#TASK_STACK_GOES_ABOVE} - * {@link StackBox#TASK_STACK_GOES_BELOW} - * {@link StackBox#TASK_STACK_GOES_UNDER} - * {@link StackBox#TASK_STACK_GOES_OVER} - * @param weight Relative weight for determining how big to make the new TaskStack. + * @param displayId The unique identifier of the DisplayContent. */ - public void createStack(int stackId, int relativeStackBoxId, int position, float weight) { - synchronized (mWindowMap) { - if (position <= StackBox.TASK_STACK_GOES_BELOW && - (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX)) { - throw new IllegalArgumentException( - "createStack: weight must be between " + STACK_WEIGHT_MIN + " and " + - STACK_WEIGHT_MAX + ", weight=" + weight); - } - final int numDisplays = mDisplayContents.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); - TaskStack stack = displayContent.createStack(stackId, relativeStackBoxId, position, - weight); - if (stack != null) { - mStackIdToStack.put(stackId, stack); - performLayoutAndPlaceSurfacesLocked(); - return; + public void attachStack(int stackId, int displayId) { + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mWindowMap) { + final DisplayContent displayContent = mDisplayContents.get(displayId); + if (displayContent != null) { + TaskStack stack = mStackIdToStack.get(stackId); + if (stack == null) { + if (DEBUG_STACK) Slog.d(TAG, "attachStack: stackId=" + stackId); + stack = new TaskStack(this, stackId); + mStackIdToStack.put(stackId, stack); + } + stack.attachDisplayContent(displayContent); + displayContent.attachStack(stack); + moveStackWindowsLocked(displayContent); + final WindowList windows = displayContent.getWindowList(); + for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { + windows.get(winNdx).reportResized(); + } } } - Slog.e(TAG, "createStack: Unable to find relativeStackBoxId=" + relativeStackBoxId); + } finally { + Binder.restoreCallingIdentity(origId); } } - public int removeStack(int stackId) { + void detachStackLocked(DisplayContent displayContent, TaskStack stack) { + displayContent.detachStack(stack); + stack.detachDisplay(); + } + + public void detachStack(int stackId) { synchronized (mWindowMap) { - final TaskStack stack = mStackIdToStack.get(stackId); + TaskStack stack = mStackIdToStack.get(stackId); if (stack != null) { - mStackIdToStack.delete(stackId); - int nextStackId = stack.remove(); - stack.getDisplayContent().layoutNeeded = true; - requestTraversalLocked(); - return nextStackId; + final DisplayContent displayContent = stack.getDisplayContent(); + if (displayContent != null) { + if (stack.isAnimating()) { + stack.mDeferDetach = true; + return; + } + detachStackLocked(displayContent, stack); + } } - if (DEBUG_STACK) Slog.i(TAG, "removeStack: could not find stackId=" + stackId); } - return HOME_STACK_ID; + } + + public void removeStack(int stackId) { + mStackIdToStack.remove(stackId); + } + + void removeTaskLocked(Task task) { + final int taskId = task.taskId; + final TaskStack stack = task.mStack; + if (stack.isAnimating()) { + if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + taskId); + task.mDeferRemoval = true; + return; + } + if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + taskId); + EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask"); + task.mDeferRemoval = false; + task.mStack.removeTask(task); + mTaskIdToTask.delete(task.taskId); } public void removeTask(int taskId) { @@ -4889,15 +5000,14 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_STACK) Slog.i(TAG, "removeTask: could not find taskId=" + taskId); return; } - final TaskStack stack = task.mStack; - EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask"); - stack.removeTask(task); - stack.getDisplayContent().layoutNeeded = true; + removeTaskLocked(task); } } public void addTask(int taskId, int stackId, boolean toTop) { synchronized (mWindowMap) { + if (DEBUG_STACK) Slog.i(TAG, "addTask: adding taskId=" + taskId + + " to " + (toTop ? "top" : "bottom")); Task task = mTaskIdToTask.get(taskId); if (task == null) { return; @@ -4910,40 +5020,28 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void resizeStackBox(int stackBoxId, float weight) { - if (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX) { - throw new IllegalArgumentException( - "resizeStack: weight must be between " + STACK_WEIGHT_MIN + " and " + - STACK_WEIGHT_MAX + ", weight=" + weight); - } + public void resizeStack(int stackId, Rect bounds) { synchronized (mWindowMap) { - final int numDisplays = mDisplayContents.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - if (mDisplayContents.valueAt(displayNdx).resizeStack(stackBoxId, weight)) { - performLayoutAndPlaceSurfacesLocked(); - return; - } + final TaskStack stack = mStackIdToStack.get(stackId); + if (stack == null) { + throw new IllegalArgumentException("resizeStack: stackId " + stackId + + " not found."); + } + if (stack.setBounds(bounds)) { + stack.resizeWindows(); + stack.getDisplayContent().layoutNeeded = true; + performLayoutAndPlaceSurfacesLocked(); } - } - throw new IllegalArgumentException("resizeStack: stackBoxId " + stackBoxId - + " not found."); - } - - public ArrayList<StackBoxInfo> getStackBoxInfos() { - synchronized(mWindowMap) { - return getDefaultDisplayContentLocked().getStackBoxInfos(); } } - public Rect getStackBounds(int stackId) { - final int numDisplays = mDisplayContents.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - Rect bounds = mDisplayContents.valueAt(displayNdx).getStackBounds(stackId); - if (bounds != null) { - return bounds; - } + public void getStackBounds(int stackId, Rect bounds) { + final TaskStack stack = mStackIdToStack.get(stackId); + if (stack != null) { + stack.getBounds(bounds); + return; } - return null; + bounds.setEmpty(); } // ------------------------------------------------------------- @@ -5219,7 +5317,7 @@ public class WindowManagerService extends IWindowManager.Stub final int numDisplays = mDisplayContents.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); - displayContent.switchUserStacks(oldUserId, newUserId); + displayContent.switchUserStacks(newUserId); rebuildAppWindowListLocked(displayContent); } performLayoutAndPlaceSurfacesLocked(); @@ -5271,7 +5369,7 @@ public class WindowManagerService extends IWindowManager.Stub public void performBootTimeout() { synchronized(mWindowMap) { - if (mDisplayEnabled || mHeadless) { + if (mDisplayEnabled) { return; } Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled"); @@ -5451,11 +5549,43 @@ public class WindowManagerService extends IWindowManager.Stub } } + public void showCircularDisplayMaskIfNeeded() { + // we're fullscreen and not hosted in an ActivityView + if (mContext.getResources().getBoolean( + com.android.internal.R.bool.config_windowIsRound)) { + mH.sendMessage(mH.obtainMessage(H.SHOW_DISPLAY_MASK)); + } + } + + public void showCircularMask() { + synchronized(mWindowMap) { + + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + ">>> OPEN TRANSACTION showDisplayMask"); + SurfaceControl.openTransaction(); + try { + // TODO(multi-display): support multiple displays + if (mCircularDisplayMask == null) { + mCircularDisplayMask = new CircularDisplayMask( + getDefaultDisplayContentLocked().getDisplay(), + mFxSession, + mPolicy.windowTypeToLayerLw( + WindowManager.LayoutParams.TYPE_POINTER) + * TYPE_LAYER_MULTIPLIER + 10); + } + mCircularDisplayMask.setVisibility(true); + } finally { + SurfaceControl.closeTransaction(); + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + "<<< CLOSE TRANSACTION showDisplayMask"); + } + } + } + // TODO: more accounting of which pid(s) turned it on, keep count, // only allow disables from pids which have count on, etc. @Override public void showStrictModeViolation(boolean on) { - if (mHeadless) return; int pid = Binder.getCallingPid(); mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid)); } @@ -5601,14 +5731,13 @@ public class WindowManagerService extends IWindowManager.Stub continue; } appWin = ws; - stackBounds.set(ws.getStackBounds()); + ws.getStackBounds(stackBounds); } } // We keep on including windows until we go past a full-screen // window. - boolean fullscreen = ws.isFullscreen(dw, dh); - including = !ws.mIsImWindow && !fullscreen; + including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh); final WindowStateAnimator winAnim = ws.mWinAnimator; if (maxLayer < winAnim.mSurfaceLayer) { @@ -5634,11 +5763,6 @@ public class WindowManagerService extends IWindowManager.Stub ws.isDisplayedLw()) { screenshotReady = true; } - - if (fullscreen) { - // No point in continuing down through windows. - break; - } } if (appToken != null && appWin == null) { @@ -5982,7 +6106,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - mDisplayManagerService.performTraversalInTransactionFromWindowManager(); + mDisplayManagerInternal.performTraversalInTransactionFromWindowManager(); } finally { if (!inTransaction) { SurfaceControl.closeTransaction(); @@ -6680,7 +6804,7 @@ public class WindowManagerService extends IWindowManager.Stub displayInfo.getLogicalMetrics(mRealDisplayMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); displayInfo.getAppMetrics(mDisplayMetrics); - mDisplayManagerService.setDisplayInfoOverrideFromWindowManager( + mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager( displayContent.getDisplayId(), displayInfo); } if (false) { @@ -6914,7 +7038,6 @@ public class WindowManagerService extends IWindowManager.Stub if (mDisplayEnabled) { mInputMonitor.setEventDispatchingLw(enabled); } - sendScreenStatusToClientsLocked(); } } @@ -7013,7 +7136,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized(displayContent.mDisplaySizeLock) { // Bootstrap the default logical display from the display manager. final DisplayInfo displayInfo = displayContent.getDisplayInfo(); - DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId); + DisplayInfo newDisplayInfo = mDisplayManagerInternal.getDisplayInfo(displayId); if (newDisplayInfo != null) { displayInfo.copyFrom(newDisplayInfo); } @@ -7034,23 +7157,6 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.systemReady(); } - // TODO(multidisplay): Call isScreenOn for each display. - private void sendScreenStatusToClientsLocked() { - final boolean on = mPowerManager.isScreenOn(); - final int numDisplays = mDisplayContents.size(); - for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); - final int numWindows = windows.size(); - for (int winNdx = 0; winNdx < numWindows; ++winNdx) { - try { - windows.get(winNdx).mClient.dispatchScreenState(on); - } catch (RemoteException e) { - // Ignored - } - } - } - } - // ------------------------------------------------------------- // Async Handler // ------------------------------------------------------------- @@ -7091,6 +7197,8 @@ public class WindowManagerService extends IWindowManager.Stub public static final int REMOVE_STARTING_TIMEOUT = 33; + public static final int SHOW_DISPLAY_MASK = 34; + @Override public void handleMessage(Message msg) { if (DEBUG_WINDOW_TRACE) { @@ -7383,15 +7491,18 @@ public class WindowManagerService extends IWindowManager.Stub case APP_FREEZE_TIMEOUT: { synchronized (mWindowMap) { Slog.w(TAG, "App freeze timeout expired."); - DisplayContent displayContent = getDefaultDisplayContentLocked(); - final ArrayList<Task> tasks = displayContent.getTasks(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { - AppTokenList tokens = tasks.get(taskNdx).mAppTokens; - for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { - AppWindowToken tok = tokens.get(tokenNdx); - if (tok.mAppAnimator.freezingScreen) { - Slog.w(TAG, "Force clearing freeze: " + tok); - unsetAppFreezingScreenLocked(tok, true, true); + final int numStacks = mStackIdToStack.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final TaskStack stack = mStackIdToStack.valueAt(stackNdx); + final ArrayList<Task> tasks = stack.getTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + AppTokenList tokens = tasks.get(taskNdx).mAppTokens; + for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { + AppWindowToken tok = tokens.get(tokenNdx); + if (tok.mAppAnimator.freezingScreen) { + Slog.w(TAG, "Force clearing freeze: " + tok); + unsetAppFreezingScreenLocked(tok, true, true); + } } } } @@ -7489,6 +7600,11 @@ public class WindowManagerService extends IWindowManager.Stub break; } + case SHOW_DISPLAY_MASK: { + showCircularMask(); + break; + } + case DO_ANIMATION_CALLBACK: { try { ((IRemoteCallback)msg.obj).sendResult(null); @@ -7498,9 +7614,7 @@ public class WindowManagerService extends IWindowManager.Stub } case DO_DISPLAY_ADDED: - synchronized (mWindowMap) { - handleDisplayAddedLocked(msg.arg1); - } + handleDisplayAdded(msg.arg1); break; case DO_DISPLAY_REMOVED: @@ -7959,7 +8073,6 @@ public class WindowManagerService extends IWindowManager.Stub } final void rebuildAppWindowListLocked() { - // TODO: Multidisplay, when ActivityStacks and tasks exist on more than one display. rebuildAppWindowListLocked(getDefaultDisplayContentLocked()); } @@ -8004,27 +8117,37 @@ public class WindowManagerService extends IWindowManager.Stub // in the main app list, but still have windows shown. We put them // in the back because now that the animation is over we no longer // will care about them. - AppTokenList exitingAppTokens = displayContent.mExitingAppTokens; - int NT = exitingAppTokens.size(); - for (int j=0; j<NT; j++) { - i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j)); + final ArrayList<TaskStack> stacks = displayContent.getStacks(); + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + AppTokenList exitingAppTokens = stacks.get(stackNdx).mExitingAppTokens; + int NT = exitingAppTokens.size(); + for (int j = 0; j < NT; j++) { + i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j)); + } } // And add in the still active app tokens in Z order. - final ArrayList<Task> tasks = displayContent.getTasks(); - final int numTasks = tasks.size(); - for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) { - final AppTokenList tokens = tasks.get(taskNdx).mAppTokens; - final int numTokens = tokens.size(); - for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) { - final AppWindowToken wtoken = tokens.get(tokenNdx); - i = reAddAppWindowsLocked(displayContent, i, wtoken); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks(); + final int numTasks = tasks.size(); + for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) { + final AppTokenList tokens = tasks.get(taskNdx).mAppTokens; + final int numTokens = tokens.size(); + for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) { + final AppWindowToken wtoken = tokens.get(tokenNdx); + if (wtoken.mDeferRemoval) { + continue; + } + i = reAddAppWindowsLocked(displayContent, i, wtoken); + } } } i -= lastBelow; if (i != numRemoved) { - Slog.w(TAG, "Rebuild removed " + numRemoved + " windows but added " + i, + Slog.w(TAG, "On display=" + displayContent.getDisplayId() + " Rebuild removed " + + numRemoved + " windows but added " + i, new RuntimeException("here").fillInStackTrace()); for (i=0; i<numRemoved; i++) { WindowState ws = mRebuildTmp[i]; @@ -8240,7 +8363,7 @@ public class WindowManagerService extends IWindowManager.Stub } mPolicy.getContentRectLw(mTmpContentRect); - displayContent.setStackBoxSize(mTmpContentRect); + displayContent.resize(mTmpContentRect); int seq = mLayoutSeq+1; if (seq < 0) seq = 0; @@ -8384,8 +8507,7 @@ public class WindowManagerService extends IWindowManager.Stub // it frozen/off until this window draws at its new // orientation. if (!okToDisplay()) { - if (DEBUG_ORIENTATION) Slog.v(TAG, - "Changing surface while display frozen: " + w); + if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w); w.mOrientationChanging = true; w.mLastFreezeDuration = 0; mInnerFields.mOrientationChangeComplete = false; @@ -8693,15 +8815,14 @@ public class WindowManagerService extends IWindowManager.Stub mAppTransition.setIdle(); // Restore window app tokens to the ActivityManager views - final DisplayContent displayContent = getDefaultDisplayContentLocked(); - final ArrayList<Task> tasks = displayContent.getTasks(); - final int numTasks = tasks.size(); - for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) { - final AppTokenList tokens = tasks.get(taskNdx).mAppTokens; - final int numTokens = tokens.size(); - for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) { - final AppWindowToken wtoken = tokens.get(tokenNdx); - wtoken.sendingToBottom = false; + ArrayList<TaskStack> stacks = getDefaultDisplayContentLocked().getStacks(); + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + final AppTokenList tokens = tasks.get(taskNdx).mAppTokens; + for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { + tokens.get(tokenNdx).sendingToBottom = false; + } } } rebuildAppWindowListLocked(); @@ -8835,7 +8956,8 @@ public class WindowManagerService extends IWindowManager.Stub if (canBeSeen) { // This function assumes that the contents of the default display are // processed first before secondary displays. - if (w.mDisplayContent.isDefaultDisplay) { + final DisplayContent displayContent = w.getDisplayContent(); + if (displayContent != null && displayContent.isDefaultDisplay) { // While a dream or keyguard is showing, obscure ordinary application // content on secondary displays (by forcibly enabling mirroring unless // there is other content we want to show) but still allow opaque @@ -8844,8 +8966,9 @@ public class WindowManagerService extends IWindowManager.Stub mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true; } mInnerFields.mDisplayHasContent = true; - } else if (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays - || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG)) { + } else if (displayContent != null && + (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays + || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG))) { // Allow full screen keyguard presentation dialogs to be seen. mInnerFields.mDisplayHasContent = true; } @@ -8853,7 +8976,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - private void handleFlagDimBehind(WindowState w, int innerDw, int innerDh) { + private void handleFlagDimBehind(WindowState w) { final WindowManager.LayoutParams attrs = w.mAttrs; if ((attrs.flags & FLAG_DIM_BEHIND) != 0 && w.isDisplayedLw() @@ -8871,22 +8994,23 @@ public class WindowManagerService extends IWindowManager.Stub private void updateAllDrawnLocked(DisplayContent displayContent) { // See if any windows have been drawn, so they (and others // associated with them) can now be shown. - final ArrayList<Task> tasks = displayContent.getTasks(); - final int numTasks = tasks.size(); - for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) { - final AppTokenList tokens = tasks.get(taskNdx).mAppTokens; - final int numTokens = tokens.size(); - for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) { - final AppWindowToken wtoken = tokens.get(tokenNdx); - if (!wtoken.allDrawn) { - int numInteresting = wtoken.numInterestingWindows; - if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { - if (DEBUG_VISIBILITY) Slog.v(TAG, - "allDrawn: " + wtoken - + " interesting=" + numInteresting - + " drawn=" + wtoken.numDrawnWindows); - wtoken.allDrawn = true; - mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget(); + ArrayList<TaskStack> stacks = displayContent.getStacks(); + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + final AppTokenList tokens = tasks.get(taskNdx).mAppTokens; + for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { + final AppWindowToken wtoken = tokens.get(tokenNdx); + if (!wtoken.allDrawn) { + int numInteresting = wtoken.numInterestingWindows; + if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { + if (DEBUG_VISIBILITY) Slog.v(TAG, + "allDrawn: " + wtoken + + " interesting=" + numInteresting + + " drawn=" + wtoken.numDrawnWindows); + wtoken.allDrawn = true; + mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget(); + } } } } @@ -8917,10 +9041,14 @@ public class WindowManagerService extends IWindowManager.Stub for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) { displayContent.mExitingTokens.get(i).hasVisible = false; } + } + for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) { // Initialize state of exiting applications. - for (i=displayContent.mExitingAppTokens.size()-1; i>=0; i--) { - displayContent.mExitingAppTokens.get(i).hasVisible = false; + final AppTokenList exitingAppTokens = + mStackIdToStack.valueAt(stackNdx).mExitingAppTokens; + for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) { + exitingAppTokens.get(tokenNdx).hasVisible = false; } } @@ -8948,6 +9076,9 @@ public class WindowManagerService extends IWindowManager.Stub if (mStrictModeFlash != null) { mStrictModeFlash.positionSurface(defaultDw, defaultDh); } + if (mCircularDisplayMask != null) { + mCircularDisplayMask.positionSurface(defaultDw, defaultDh, mRotation); + } boolean focusDisplayed = false; @@ -9039,6 +9170,10 @@ public class WindowManagerService extends IWindowManager.Stub final int N = windows.size(); for (i=N-1; i>=0; i--) { WindowState w = windows.get(i); + final TaskStack stack = w.getStack(); + if (stack == null) { + continue; + } final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured; @@ -9048,8 +9183,8 @@ public class WindowManagerService extends IWindowManager.Stub handleNotObscuredLocked(w, currentTime, innerDw, innerDh); } - if (!w.getStack().testDimmingTag()) { - handleFlagDimBehind(w, innerDw, innerDh); + if (!stack.testDimmingTag()) { + handleFlagDimBehind(w); } if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w) @@ -9173,7 +9308,7 @@ public class WindowManagerService extends IWindowManager.Stub updateResizingWindows(w); } - mDisplayManagerService.setDisplayHasContent(displayId, + mDisplayManagerInternal.setDisplayHasContent(displayId, mInnerFields.mDisplayHasContent, true /* inTraversal, must call performTraversalInTrans... below */); @@ -9190,7 +9325,7 @@ public class WindowManagerService extends IWindowManager.Stub // Give the display manager a chance to adjust properties // like display rotation if it needs to. - mDisplayManagerService.performTraversalInTransactionFromWindowManager(); + mDisplayManagerInternal.performTraversalInTransactionFromWindowManager(); } catch (RuntimeException e) { Log.wtf(TAG, "Unhandled exception in Window Manager", e); @@ -9265,57 +9400,7 @@ public class WindowManagerService extends IWindowManager.Stub // Don't remove this window until rotation has completed. continue; } - final WindowStateAnimator winAnimator = win.mWinAnimator; - try { - if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, - "Reporting new frame to " + win + ": " + win.mCompatFrame); - int diff = 0; - boolean configChanged = win.isConfigChanged(); - if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) - && configChanged) { - Slog.i(TAG, "Sending new config to window " + win + ": " - + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH - + " / " + mCurConfiguration + " / 0x" - + Integer.toHexString(diff)); - } - win.setConfiguration(mCurConfiguration); - if (DEBUG_ORIENTATION && - winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i( - TAG, "Resizing " + win + " WITH DRAW PENDING"); - final IWindow client = win.mClient; - final Rect frame = win.mFrame; - final Rect overscanInsets = win.mLastOverscanInsets; - final Rect contentInsets = win.mLastContentInsets; - final Rect visibleInsets = win.mLastVisibleInsets; - final boolean reportDraw - = winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING; - final Configuration newConfig = configChanged ? win.mConfiguration : null; - if (win.mClient instanceof IWindow.Stub) { - // To prevent deadlock simulate one-way call if win.mClient is a local object. - mH.post(new Runnable() { - @Override - public void run() { - try { - client.resized(frame, overscanInsets, contentInsets, - visibleInsets, reportDraw, newConfig); - } catch (RemoteException e) { - // Not a remote call, RemoteException won't be raised. - } - } - }); - } else { - client.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw, - newConfig); - } - win.mOverscanInsetsChanged = false; - win.mContentInsetsChanged = false; - win.mVisibleInsetsChanged = false; - winAnimator.mSurfaceResized = false; - } catch (RemoteException e) { - win.mOrientationChanging = false; - win.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime() - - mDisplayFreezeTime); - } + win.reportResized(); mResizingWindows.remove(i); } @@ -9363,12 +9448,16 @@ public class WindowManagerService extends IWindowManager.Stub } } } + } - // Time to remove any exiting applications? - AppTokenList exitingAppTokens = displayContent.mExitingAppTokens; + // Time to remove any exiting applications? + for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) { + // Initialize state of exiting applications. + final AppTokenList exitingAppTokens = + mStackIdToStack.valueAt(stackNdx).mExitingAppTokens; for (i = exitingAppTokens.size() - 1; i >= 0; i--) { AppWindowToken token = exitingAppTokens.get(i); - if (!token.hasVisible && !mClosingApps.contains(token)) { + if (!token.hasVisible && !mClosingApps.contains(token) && !token.mDeferRemoval) { // Make sure there is no animation running on this token, // so any windows associated with it will be removed as // soon as their animations are complete @@ -9376,10 +9465,7 @@ public class WindowManagerService extends IWindowManager.Stub token.mAppAnimator.animating = false; if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "performLayout: App token exiting now removed" + token); - final Task task = mTaskIdToTask.get(token.groupId); - if (task != null && task.removeAppToken(token)) { - mTaskIdToTask.delete(token.groupId); - } + removeAppFromTaskLocked(token); exitingAppTokens.remove(i); } } @@ -9414,18 +9500,18 @@ public class WindowManagerService extends IWindowManager.Stub setHoldScreenLocked(mInnerFields.mHoldScreen); if (!mDisplayFrozen) { if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) { - mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1); + mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1); } else { - mPowerManager.setScreenBrightnessOverrideFromWindowManager( + mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager( toBrightnessOverride(mInnerFields.mScreenBrightness)); } if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) { - mPowerManager.setButtonBrightnessOverrideFromWindowManager(-1); + mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1); } else { - mPowerManager.setButtonBrightnessOverrideFromWindowManager( + mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager( toBrightnessOverride(mInnerFields.mButtonBrightness)); } - mPowerManager.setUserActivityTimeoutOverrideFromWindowManager( + mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager( mInnerFields.mUserActivityTimeout); } @@ -9460,8 +9546,9 @@ public class WindowManagerService extends IWindowManager.Stub for (i = 0; i < N; i++) { WindowState w = mPendingRemoveTmp[i]; removeWindowInnerLocked(w.mSession, w); - if (!displayList.contains(w.mDisplayContent)) { - displayList.add(w.mDisplayContent); + final DisplayContent displayContent = w.getDisplayContent(); + if (displayContent != null && !displayList.contains(displayContent)) { + displayList.add(displayContent); } } @@ -9471,6 +9558,11 @@ public class WindowManagerService extends IWindowManager.Stub } } + // Remove all deferred displays stacks, tasks, and activities. + for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) { + mDisplayContents.valueAt(displayNdx).checkForDeferredActions(); + } + setFocusedStackFrame(); // Check to see if we are now in a state where the screen should @@ -9559,8 +9651,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - @Override - public void requestTraversal() { + void requestTraversal() { synchronized (mWindowMap) { requestTraversalLocked(); } @@ -9938,6 +10029,7 @@ public class WindowManagerService extends IWindowManager.Stub } // TODO(multidisplay): rotation on main screen only. + displayContent.updateDisplayInfo(); screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent, mFxSession, inTransaction, mPolicy.isDefaultOrientationForced()); mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation); @@ -10747,6 +10839,7 @@ public class WindowManagerService extends IWindowManager.Stub private DisplayContent newDisplayContentLocked(final Display display) { DisplayContent displayContent = new DisplayContent(display, this); final int displayId = display.getDisplayId(); + if (DEBUG_DISPLAY) Slog.v(TAG, "Adding display=" + display); mDisplayContents.put(displayId, displayContent); DisplayInfo displayInfo = displayContent.getDisplayInfo(); @@ -10757,7 +10850,7 @@ public class WindowManagerService extends IWindowManager.Stub displayInfo.overscanTop = rect.top; displayInfo.overscanRight = rect.right; displayInfo.overscanBottom = rect.bottom; - mDisplayManagerService.setDisplayInfoOverrideFromWindowManager( + mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager( displayId, displayInfo); } configureDisplayPolicyLocked(displayContent); @@ -10827,20 +10920,20 @@ public class WindowManagerService extends IWindowManager.Stub return displayContent != null ? displayContent.getWindowList() : null; } - @Override public void onDisplayAdded(int displayId) { mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0)); } - private void handleDisplayAddedLocked(int displayId) { - final Display display = mDisplayManager.getDisplay(displayId); - if (display != null) { - createDisplayContentLocked(display); - displayReady(displayId); + public void handleDisplayAdded(int displayId) { + synchronized (mWindowMap) { + final Display display = mDisplayManager.getDisplay(displayId); + if (display != null) { + createDisplayContentLocked(display); + displayReady(displayId); + } } } - @Override public void onDisplayRemoved(int displayId) { mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0)); } @@ -10848,21 +10941,20 @@ public class WindowManagerService extends IWindowManager.Stub private void handleDisplayRemovedLocked(int displayId) { final DisplayContent displayContent = getDisplayContentLocked(displayId); if (displayContent != null) { + if (displayContent.isAnimating()) { + displayContent.mDeferredRemoval = true; + return; + } + if (DEBUG_DISPLAY) Slog.v(TAG, "Removing display=" + displayContent); mDisplayContents.delete(displayId); displayContent.close(); if (displayId == Display.DEFAULT_DISPLAY) { unregisterPointerEventListener(displayContent.mTapDetector); } - WindowList windows = displayContent.getWindowList(); - while (!windows.isEmpty()) { - final WindowState win = windows.get(windows.size() - 1); - removeWindowLocked(win.mSession, win, true); - } } mAnimator.removeDisplayLocked(displayId); } - @Override public void onDisplayChanged(int displayId) { mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0)); } @@ -10878,4 +10970,11 @@ public class WindowManagerService extends IWindowManager.Stub public Object getWindowManagerLock() { return mWindowMap; } + + private final class LocalService extends WindowManagerInternal { + @Override + public void requestTraversalFromDisplayManager() { + requestTraversal(); + } + } } diff --git a/services/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 4d53cea..9f3415e 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -16,8 +16,11 @@ package com.android.server.wm; -import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; +import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION; import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT; +import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION; +import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE; +import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; @@ -29,7 +32,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import android.app.AppOpsManager; +import android.os.Debug; import android.os.RemoteCallbackList; +import android.os.SystemClock; import android.util.TimeUtils; import android.view.IWindowFocusObserver; import android.view.IWindowId; @@ -370,19 +375,17 @@ final class WindowState implements WindowManagerPolicy.WindowState { mAttachedWindow.mChildWindows.add(this); } else { for (int i = 0; i < children_size; i++) { - WindowState child = (WindowState)mAttachedWindow.mChildWindows.get(i); - if (this.mSubLayer < child.mSubLayer) { + WindowState child = mAttachedWindow.mChildWindows.get(i); + if (mSubLayer < child.mSubLayer) { mAttachedWindow.mChildWindows.add(i, this); break; - } else if (this.mSubLayer > child.mSubLayer) { + } else if (mSubLayer > child.mSubLayer) { continue; } - if (this.mBaseLayer <= child.mBaseLayer) { + if (mBaseLayer <= child.mBaseLayer) { mAttachedWindow.mChildWindows.add(i, this); break; - } else { - continue; } } if (children_size == mAttachedWindow.mChildWindows.size()) { @@ -463,8 +466,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { mHaveFrame = true; TaskStack stack = mAppToken != null ? getStack() : null; - if (stack != null && stack.hasSibling()) { - mContainingFrame.set(getStackBounds(stack)); + if (stack != null && !stack.isFullscreen()) { + getStackBounds(stack, mContainingFrame); if (mUnderStatusBar) { mContainingFrame.top = pf.top; } @@ -593,9 +596,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { } if (mIsWallpaper && (fw != mFrame.width() || fh != mFrame.height())) { - final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); - mService.updateWallpaperOffsetLocked(this, - displayInfo.logicalWidth, displayInfo.logicalHeight, false); + final DisplayContent displayContent = getDisplayContent(); + if (displayContent != null) { + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); + mService.updateWallpaperOffsetLocked(this, + displayInfo.logicalWidth, displayInfo.logicalHeight, false); + } } if (DEBUG_LAYOUT || WindowManagerService.localLOGV) Slog.v(TAG, @@ -708,8 +714,16 @@ final class WindowState implements WindowManagerPolicy.WindowState { return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged; } + public DisplayContent getDisplayContent() { + return mAppToken == null ? mDisplayContent : getStack().getDisplayContent(); + } + public int getDisplayId() { - return mDisplayContent.getDisplayId(); + final DisplayContent displayContent = getDisplayContent(); + if (displayContent == null) { + return -1; + } + return displayContent.getDisplayId(); } TaskStack getStack() { @@ -717,21 +731,28 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (wtoken != null) { Task task = mService.mTaskIdToTask.get(wtoken.groupId); if (task != null) { - return task.mStack; + if (task.mStack != null) { + return task.mStack; + } + Slog.e(TAG, "getStack: mStack null for task=" + task); + } else { + Slog.e(TAG, "getStack: " + this + " couldn't find taskId=" + wtoken.groupId + + " Callers=" + Debug.getCallers(4)); } } return mDisplayContent.getHomeStack(); } - Rect getStackBounds() { - return getStackBounds(getStack()); + void getStackBounds(Rect bounds) { + getStackBounds(getStack(), bounds); } - private Rect getStackBounds(TaskStack stack) { + private void getStackBounds(TaskStack stack, Rect bounds) { if (stack != null) { - return stack.mStackBox.mBounds; + stack.getBounds(bounds); + return; } - return mFrame; + bounds.set(mFrame); } public long getInputDispatchingTimeoutNanos() { @@ -1190,7 +1211,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { @Override public boolean isDefaultDisplay() { - return mDisplayContent.isDefaultDisplay; + final DisplayContent displayContent = getDisplayContent(); + if (displayContent == null) { + // Only a window that was on a non-default display can be detached from it. + return false; + } + return getDisplayContent().isDefaultDisplay; } public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) { @@ -1207,7 +1233,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { && win.mAppToken != null && win.mAppToken.showWhenLocked) { // Save some cycles by not calling getDisplayInfo unless it is an application // window intended for all users. - final DisplayInfo displayInfo = win.mDisplayContent.getDisplayInfo(); + final DisplayContent displayContent = win.getDisplayContent(); + if (displayContent == null) { + return true; + } + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); if (win.mFrame.left <= 0 && win.mFrame.top <= 0 && win.mFrame.right >= displayInfo.appWidth && win.mFrame.bottom >= displayInfo.appHeight) { @@ -1249,7 +1279,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { } WindowList getWindowList() { - return mDisplayContent.getWindowList(); + final DisplayContent displayContent = getDisplayContent(); + return displayContent == null ? null : displayContent.getWindowList(); } /** @@ -1278,6 +1309,54 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } + void reportResized() { + try { + if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this + + ": " + mCompatFrame); + boolean configChanged = isConfigChanged(); + if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) { + Slog.i(TAG, "Sending new config to window " + this + ": " + + mWinAnimator.mSurfaceW + "x" + mWinAnimator.mSurfaceH + + " / " + mService.mCurConfiguration); + } + setConfiguration(mService.mCurConfiguration); + if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) + Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING"); + + final Rect frame = mFrame; + final Rect overscanInsets = mLastOverscanInsets; + final Rect contentInsets = mLastContentInsets; + final Rect visibleInsets = mLastVisibleInsets; + final boolean reportDraw = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING; + final Configuration newConfig = configChanged ? mConfiguration : null; + if (mClient instanceof IWindow.Stub) { + // To prevent deadlock simulate one-way call if win.mClient is a local object. + mService.mH.post(new Runnable() { + @Override + public void run() { + try { + mClient.resized(frame, overscanInsets, contentInsets, + visibleInsets, reportDraw, newConfig); + } catch (RemoteException e) { + // Not a remote call, RemoteException won't be raised. + } + } + }); + } else { + mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw, + newConfig); + } + mOverscanInsetsChanged = false; + mContentInsetsChanged = false; + mVisibleInsetsChanged = false; + mWinAnimator.mSurfaceResized = false; + } catch (RemoteException e) { + mOrientationChanging = false; + mLastFreezeDuration = (int)(SystemClock.elapsedRealtime() + - mService.mDisplayFreezeTime); + } + } + public void registerFocusObserver(IWindowFocusObserver observer) { synchronized(mService.mWindowMap) { if (mFocusCallbacks == null) { @@ -1302,7 +1381,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } void dump(PrintWriter pw, String prefix, boolean dumpAll) { - pw.print(prefix); pw.print("mDisplayId="); pw.print(mDisplayContent.getDisplayId()); + pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId()); pw.print(" mSession="); pw.print(mSession); pw.print(" mClient="); pw.println(mClient.asBinder()); pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid); diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index c405170..1ff0afb 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1,4 +1,18 @@ -// Copyright 2012 Google Inc. All Rights Reserved. +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.android.server.wm; @@ -150,8 +164,6 @@ class WindowStateAnimator { int mAttrFlags; int mAttrType; - final int mLayerStack; - public WindowStateAnimator(final WindowState win) { final WindowManagerService service = win.mService; @@ -159,9 +171,15 @@ class WindowStateAnimator { mAnimator = service.mAnimator; mPolicy = service.mPolicy; mContext = service.mContext; - final DisplayInfo displayInfo = win.mDisplayContent.getDisplayInfo(); - mAnimDw = displayInfo.appWidth; - mAnimDh = displayInfo.appHeight; + final DisplayContent displayContent = win.getDisplayContent(); + if (displayContent != null) { + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); + mAnimDw = displayInfo.appWidth; + mAnimDh = displayInfo.appHeight; + } else { + Slog.w(TAG, "WindowStateAnimator ctor: Display has been removed"); + // This is checked on return and dealt with. + } mWin = win; mAttachedWinAnimator = win.mAttachedWindow == null @@ -171,7 +189,6 @@ class WindowStateAnimator { mAttrFlags = win.mAttrs.flags; mAttrType = win.mAttrs.type; mIsWallpaper = win.mIsWallpaper; - mLayerStack = win.mDisplayContent.getDisplay().getLayerStack(); } public void setAnimation(Animation anim) { @@ -243,7 +260,8 @@ class WindowStateAnimator { // Save the animation state as it was before this step so WindowManagerService can tell if // we just started or just stopped animating by comparing mWasAnimating with isAnimating(). mWasAnimating = mAnimating; - if (mService.okToDisplay()) { + final DisplayContent displayContent = mWin.getDisplayContent(); + if (displayContent != null && mService.okToDisplay()) { // We will run animations as long as the display isn't frozen. if (mWin.isDrawnLw() && mAnimation != null) { @@ -258,7 +276,7 @@ class WindowStateAnimator { " scale=" + mService.mWindowAnimationScale); mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mAnimDw, mAnimDh); - final DisplayInfo displayInfo = mWin.mDisplayContent.getDisplayInfo(); + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); mAnimDw = displayInfo.appWidth; mAnimDh = displayInfo.appHeight; mAnimation.setStartTime(currentTime); @@ -337,7 +355,9 @@ class WindowStateAnimator { + mWin.mPolicyVisibilityAfterAnim); } mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim; - mWin.mDisplayContent.layoutNeeded = true; + if (displayContent != null) { + displayContent.layoutNeeded = true; + } if (!mWin.mPolicyVisibility) { if (mService.mCurrentFocus == mWin) { if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG, @@ -363,11 +383,13 @@ class WindowStateAnimator { } else if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) { // Upon completion of a not-visible to visible status bar animation a relayout is // required. - mWin.mDisplayContent.layoutNeeded = true; + if (displayContent != null) { + displayContent.layoutNeeded = true; + } } finishExit(); - final int displayId = mWin.mDisplayContent.getDisplayId(); + final int displayId = mWin.getDisplayId(); mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM); if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats( "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId)); @@ -487,6 +509,7 @@ class WindowStateAnimator { private final Rect mWindowCrop = new Rect(); private boolean mShown = false; private int mLayerStack; + private boolean mIsOpaque; private final String mName; public SurfaceTrace(SurfaceSession s, @@ -572,6 +595,16 @@ class WindowStateAnimator { } @Override + public void setOpaque(boolean isOpaque) { + if (isOpaque != mIsOpaque) { + Slog.v(SURFACE_TAG, "setOpaque(" + isOpaque + "): OLD:" + this + + ". Called by " + Debug.getCallers(3)); + mIsOpaque = isOpaque; + } + super.setOpaque(isOpaque); + } + + @Override public void hide() { if (mShown) { Slog.v(SURFACE_TAG, "hide: OLD:" + this + ". Called by " + Debug.getCallers(3)); @@ -617,7 +650,8 @@ class WindowStateAnimator { + mName + " (" + mLayerStack + "): shown=" + mShown + " layer=" + mLayer + " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y + " " + mSize.x + "x" + mSize.y - + " crop=" + mWindowCrop.toShortString(); + + " crop=" + mWindowCrop.toShortString() + + " opaque=" + mIsOpaque; } } @@ -732,7 +766,10 @@ class WindowStateAnimator { mSurfaceY = mWin.mFrame.top + mWin.mYOffset; mSurfaceControl.setPosition(mSurfaceX, mSurfaceY); mSurfaceLayer = mAnimLayer; - mSurfaceControl.setLayerStack(mLayerStack); + final DisplayContent displayContent = mWin.getDisplayContent(); + if (displayContent != null) { + mSurfaceControl.setLayerStack(displayContent.getDisplay().getLayerStack()); + } mSurfaceControl.setLayer(mAnimLayer); mSurfaceControl.setAlpha(0); mSurfaceShown = false; @@ -921,8 +958,7 @@ class WindowStateAnimator { tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix()); } //TODO (multidisplay): Magnification is supported only for the default display. - if (mService.mDisplayMagnifier != null - && mWin.getDisplayId() == Display.DEFAULT_DISPLAY) { + if (mService.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) { MagnificationSpec spec = mService.mDisplayMagnifier .getMagnificationSpecForWindowLocked(mWin); if (spec != null && !spec.isNop()) { @@ -1002,7 +1038,7 @@ class WindowStateAnimator { && mWin.mBaseLayer < mAnimator.mAboveUniverseLayer); MagnificationSpec spec = null; //TODO (multidisplay): Magnification is supported only for the default display. - if (mService.mDisplayMagnifier != null && mWin.getDisplayId() == Display.DEFAULT_DISPLAY) { + if (mService.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) { spec = mService.mDisplayMagnifier.getMagnificationSpecForWindowLocked(mWin); } if (applyUniverseTransformation || spec != null) { @@ -1080,7 +1116,11 @@ class WindowStateAnimator { void updateSurfaceWindowCrop(final boolean recoveringMemory) { final WindowState w = mWin; - DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo(); + final DisplayContent displayContent = w.getDisplayContent(); + if (displayContent == null) { + return; + } + DisplayInfo displayInfo = displayContent.getDisplayInfo(); // Need to recompute a new system decor rect each time. if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { @@ -1181,8 +1221,7 @@ class WindowStateAnimator { "SIZE " + width + "x" + height, null); mSurfaceResized = true; mSurfaceControl.setSize(width, height); - final int displayId = w.mDisplayContent.getDisplayId(); - mAnimator.setPendingLayoutChanges(displayId, + mAnimator.setPendingLayoutChanges(w.getDisplayId(), WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER); if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) { w.getStack().startDimmingIfNeeded(this); @@ -1329,8 +1368,7 @@ class WindowStateAnimator { Slog.w(TAG, "setTransparentRegionHint: null mSurface after mHasSurface true"); return; } - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, - ">>> OPEN TRANSACTION setTransparentRegion"); + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setTransparentRegion"); SurfaceControl.openTransaction(); try { if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, @@ -1356,8 +1394,7 @@ class WindowStateAnimator { // transformation is being applied by the animation. return; } - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, - ">>> OPEN TRANSACTION setWallpaperOffset"); + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset"); SurfaceControl.openTransaction(); try { if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, @@ -1375,6 +1412,22 @@ class WindowStateAnimator { } } + void setOpaque(boolean isOpaque) { + if (mSurfaceControl == null) { + return; + } + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setOpaque"); + SurfaceControl.openTransaction(); + try { + if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "isOpaque=" + isOpaque, + null); + mSurfaceControl.setOpaque(isOpaque); + } finally { + SurfaceControl.closeTransaction(); + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setOpaque"); + } + } + // This must be called while inside a transaction. boolean performShowLocked() { if (mWin.isHiddenFromUserLocked()) { @@ -1444,7 +1497,10 @@ class WindowStateAnimator { // do a layout. If called from within the transaction // loop, this will cause it to restart with a new // layout. - c.mDisplayContent.layoutNeeded = true; + final DisplayContent displayContent = c.getDisplayContent(); + if (displayContent != null) { + displayContent.layoutNeeded = true; + } } } } diff --git a/services/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 2267123..2267123 100644 --- a/services/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk new file mode 100644 index 0000000..0843e94 --- /dev/null +++ b/services/core/jni/Android.mk @@ -0,0 +1,60 @@ +# This file is included by the top level services directory to collect source +# files +LOCAL_REL_DIR := core/jni + +LOCAL_SRC_FILES += \ + $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \ + $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \ + $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \ + $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \ + $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_location_GpsLocationProvider.cpp \ + $(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \ + $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \ + $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \ + $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \ + $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \ + $(LOCAL_REL_DIR)/onload.cpp + +include external/stlport/libstlport.mk + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + frameworks/base/services \ + frameworks/base/libs \ + frameworks/base/core/jni \ + frameworks/native/services \ + external/skia/include/core \ + libcore/include \ + libcore/include/libsuspend \ + $(call include-path-for, libhardware)/hardware \ + $(call include-path-for, libhardware_legacy)/hardware_legacy \ + +LOCAL_SHARED_LIBRARIES += \ + libandroid_runtime \ + libandroidfw \ + libbinder \ + libcutils \ + liblog \ + libhardware \ + libhardware_legacy \ + libnativehelper \ + libutils \ + libui \ + libinput \ + libinputservice \ + libsensorservice \ + libskia \ + libgui \ + libusbhost \ + libsuspend \ + libEGL \ + libGLESv2 + diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp new file mode 100644 index 0000000..342515b --- /dev/null +++ b/services/core/jni/com_android_server_AlarmManagerService.cpp @@ -0,0 +1,321 @@ +/* //device/libs/android_runtime/android_server_AlarmManagerService.cpp +** +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "AlarmManagerService" + +#include "JNIHelp.h" +#include "jni.h" +#include <utils/Log.h> +#include <utils/misc.h> + +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/epoll.h> +#include <sys/timerfd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <linux/ioctl.h> +#include <linux/android_alarm.h> + +namespace android { + +static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1; +static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = { + CLOCK_REALTIME_ALARM, + CLOCK_REALTIME, + CLOCK_BOOTTIME_ALARM, + CLOCK_BOOTTIME, + CLOCK_MONOTONIC, + CLOCK_REALTIME, +}; +/* to match the legacy alarm driver implementation, we need an extra + CLOCK_REALTIME fd which exists specifically to be canceled on RTC changes */ + +class AlarmImpl +{ +public: + AlarmImpl(int *fds, size_t n_fds); + virtual ~AlarmImpl(); + + virtual int set(int type, struct timespec *ts) = 0; + virtual int waitForAlarm() = 0; + +protected: + int *fds; + size_t n_fds; +}; + +class AlarmImplAlarmDriver : public AlarmImpl +{ +public: + AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { } + + int set(int type, struct timespec *ts); + int waitForAlarm(); +}; + +class AlarmImplTimerFd : public AlarmImpl +{ +public: + AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd) : + AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd) { } + ~AlarmImplTimerFd(); + + int set(int type, struct timespec *ts); + int waitForAlarm(); + +private: + int epollfd; +}; + +AlarmImpl::AlarmImpl(int *fds_, size_t n_fds) : fds(new int[n_fds]), + n_fds(n_fds) +{ + memcpy(fds, fds_, n_fds * sizeof(fds[0])); +} + +AlarmImpl::~AlarmImpl() +{ + for (size_t i = 0; i < n_fds; i++) { + close(fds[i]); + } + delete [] fds; +} + +int AlarmImplAlarmDriver::set(int type, struct timespec *ts) +{ + return ioctl(fds[0], ANDROID_ALARM_SET(type), ts); +} + +int AlarmImplAlarmDriver::waitForAlarm() +{ + return ioctl(fds[0], ANDROID_ALARM_WAIT); +} + +AlarmImplTimerFd::~AlarmImplTimerFd() +{ + for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) { + epoll_ctl(epollfd, EPOLL_CTL_DEL, fds[i], NULL); + } + close(epollfd); +} + +int AlarmImplTimerFd::set(int type, struct timespec *ts) +{ + if (type > ANDROID_ALARM_TYPE_COUNT) { + errno = EINVAL; + return -1; + } + + if (!ts->tv_nsec && !ts->tv_sec) { + ts->tv_nsec = 1; + } + /* timerfd interprets 0 = disarm, so replace with a practically + equivalent deadline of 1 ns */ + + struct itimerspec spec; + memset(&spec, 0, sizeof(spec)); + memcpy(&spec.it_value, ts, sizeof(spec.it_value)); + + return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL); +} + +int AlarmImplTimerFd::waitForAlarm() +{ + epoll_event events[N_ANDROID_TIMERFDS]; + + int nevents = epoll_wait(epollfd, events, N_ANDROID_TIMERFDS, -1); + if (nevents < 0) { + return nevents; + } + + int result = 0; + for (int i = 0; i < nevents; i++) { + uint32_t alarm_idx = events[i].data.u32; + uint64_t unused; + ssize_t err = read(fds[alarm_idx], &unused, sizeof(unused)); + if (err < 0) { + if (alarm_idx == ANDROID_ALARM_TYPE_COUNT && errno == ECANCELED) { + result |= ANDROID_ALARM_TIME_CHANGE_MASK; + } else { + return err; + } + } else { + result |= (1 << alarm_idx); + } + } + + return result; +} + +static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest) +{ + struct timezone tz; + + tz.tz_minuteswest = minswest; + tz.tz_dsttime = 0; + + int result = settimeofday(NULL, &tz); + if (result < 0) { + ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno)); + return -1; + } else { + ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest); + } + + return 0; +} + +static jlong init_alarm_driver() +{ + int fd = open("/dev/alarm", O_RDWR); + if (fd < 0) { + ALOGV("opening alarm driver failed: %s", strerror(errno)); + return 0; + } + + AlarmImpl *ret = new AlarmImplAlarmDriver(fd); + return reinterpret_cast<jlong>(ret); +} + +static jlong init_timerfd() +{ + int epollfd; + int fds[N_ANDROID_TIMERFDS]; + + epollfd = epoll_create(N_ANDROID_TIMERFDS); + if (epollfd < 0) { + ALOGV("epoll_create(%u) failed: %s", N_ANDROID_TIMERFDS, + strerror(errno)); + return 0; + } + + for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) { + fds[i] = timerfd_create(android_alarm_to_clockid[i], 0); + if (fds[i] < 0) { + ALOGV("timerfd_create(%u) failed: %s", android_alarm_to_clockid[i], + strerror(errno)); + close(epollfd); + for (size_t j = 0; j < i; j++) { + close(fds[j]); + } + return 0; + } + } + + AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd); + + for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) { + epoll_event event; + event.events = EPOLLIN | EPOLLWAKEUP; + event.data.u32 = i; + + int err = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event); + if (err < 0) { + ALOGV("epoll_ctl(EPOLL_CTL_ADD) failed: %s", strerror(errno)); + delete ret; + return 0; + } + } + + struct itimerspec spec; + memset(&spec, 0, sizeof(spec)); + /* 0 = disarmed; the timerfd doesn't need to be armed to get + RTC change notifications, just set up as cancelable */ + + int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT], + TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL); + if (err < 0) { + ALOGV("timerfd_settime() failed: %s", strerror(errno)); + delete ret; + return 0; + } + + return reinterpret_cast<jlong>(ret); +} + +static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject) +{ + jlong ret = init_alarm_driver(); + if (ret) { + return ret; + } + + return init_timerfd(); +} + +static void android_server_AlarmManagerService_close(JNIEnv*, jobject, jlong nativeData) +{ + AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData); + delete impl; +} + +static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds) +{ + AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData); + struct timespec ts; + ts.tv_sec = seconds; + ts.tv_nsec = nanoseconds; + + int result = impl->set(type, &ts); + if (result < 0) + { + ALOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno)); + } +} + +static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData) +{ + AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData); + int result = 0; + + do + { + result = impl->waitForAlarm(); + } while (result < 0 && errno == EINTR); + + if (result < 0) + { + ALOGE("Unable to wait on alarm: %s\n", strerror(errno)); + return 0; + } + + return result; +} + +static JNINativeMethod sMethods[] = { + /* name, signature, funcPtr */ + {"init", "()J", (void*)android_server_AlarmManagerService_init}, + {"close", "(J)V", (void*)android_server_AlarmManagerService_close}, + {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set}, + {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm}, + {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone}, +}; + +int register_android_server_AlarmManagerService(JNIEnv* env) +{ + return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService", + sMethods, NELEM(sMethods)); +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp index 885d21e..4a1b55d 100644 --- a/services/jni/com_android_server_AssetAtlasService.cpp +++ b/services/core/jni/com_android_server_AssetAtlasService.cpp @@ -54,11 +54,11 @@ static struct { jfieldID mNativeCanvas; } gCanvasFinalizerClassInfo; -#define GET_INT(object, field) \ - env->GetIntField(object, field) +#define GET_LONG(object, field) \ + env->GetLongField(object, field) -#define SET_INT(object, field, value) \ - env->SetIntField(object, field, value) +#define SET_LONG(object, field, value) \ + env->SetLongField(object, field, value) // ---------------------------------------------------------------------------- // Canvas management @@ -67,9 +67,9 @@ static struct { static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) { jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer); SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>( - GET_INT(canvasObj, gCanvasClassInfo.mNativeCanvas)); - SET_INT(canvasObj, gCanvasClassInfo.mNativeCanvas, (int) newCanvas); - SET_INT(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int) newCanvas); + GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas)); + SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas); + SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas); SkSafeUnref(previousCanvas); } @@ -261,10 +261,10 @@ int register_android_server_AssetAtlasService(JNIEnv* env) { FIND_CLASS(clazz, "android/graphics/Canvas"); GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;"); - GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I"); + GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J"); FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer"); - GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I"); + GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J"); return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/services/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp index 004c0aa..004c0aa 100644 --- a/services/jni/com_android_server_ConsumerIrService.cpp +++ b/services/core/jni/com_android_server_ConsumerIrService.cpp diff --git a/services/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp index b889b78..b889b78 100644 --- a/services/jni/com_android_server_SerialService.cpp +++ b/services/core/jni/com_android_server_SerialService.cpp diff --git a/services/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp index 0625544..0625544 100644 --- a/services/jni/com_android_server_SystemServer.cpp +++ b/services/core/jni/com_android_server_SystemServer.cpp diff --git a/services/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp index 3551733..3551733 100644 --- a/services/jni/com_android_server_UsbDeviceManager.cpp +++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp diff --git a/services/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp index 639790b..f1fa6cf 100644 --- a/services/jni/com_android_server_UsbHostManager.cpp +++ b/services/core/jni/com_android_server_UsbHostManager.cpp @@ -73,6 +73,9 @@ static int usb_device_added(const char *devname, void* client_data) { uint8_t deviceClass = deviceDesc->bDeviceClass; uint8_t deviceSubClass = deviceDesc->bDeviceSubClass; uint8_t protocol = deviceDesc->bDeviceProtocol; + char *manufacturer = usb_device_get_manufacturer_name(device); + char *product = usb_device_get_product_name(device); + char *serial = usb_device_get_serial(device); usb_descriptor_iter_init(device, &iter); @@ -109,12 +112,19 @@ static int usb_device_added(const char *devname, void* client_data) { env->SetIntArrayRegion(endpointArray, 0, length, endpointValues.array()); jstring deviceName = env->NewStringUTF(devname); + jstring manufacturerName = env->NewStringUTF(manufacturer); + jstring productName = env->NewStringUTF(product); + jstring serialNumber = env->NewStringUTF(serial); env->CallVoidMethod(thiz, method_usbDeviceAdded, deviceName, vendorId, productId, deviceClass, - deviceSubClass, protocol, interfaceArray, endpointArray); + deviceSubClass, protocol, manufacturerName, + productName, serialNumber, interfaceArray, endpointArray); env->DeleteLocalRef(interfaceArray); env->DeleteLocalRef(endpointArray); + env->DeleteLocalRef(serialNumber); + env->DeleteLocalRef(productName); + env->DeleteLocalRef(manufacturerName); env->DeleteLocalRef(deviceName); checkAndClearExceptionFromCallback(env, __FUNCTION__); @@ -179,7 +189,7 @@ int register_android_server_UsbHostManager(JNIEnv *env) ALOGE("Can't find com/android/server/usb/UsbHostManager"); return -1; } - method_usbDeviceAdded = env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;IIIII[I[I)V"); + method_usbDeviceAdded = env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I)V"); if (method_usbDeviceAdded == NULL) { ALOGE("Can't find usbDeviceAdded"); return -1; diff --git a/services/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index 2b3f74a..2b3f74a 100644 --- a/services/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp index bf34a74..bf34a74 100644 --- a/services/jni/com_android_server_connectivity_Vpn.cpp +++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp diff --git a/services/core/jni/com_android_server_dreams_McuHal.cpp b/services/core/jni/com_android_server_dreams_McuHal.cpp new file mode 100644 index 0000000..a6d9297 --- /dev/null +++ b/services/core/jni/com_android_server_dreams_McuHal.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "McuHal" + +//#define LOG_NDEBUG 0 + +#include "JNIHelp.h" +#include "jni.h" + +#include <ScopedUtfChars.h> +#include <ScopedPrimitiveArray.h> + +#include <utils/Errors.h> +#include <utils/Log.h> +#include <hardware/mcu.h> + +namespace android { + +static jlong nativeOpen(JNIEnv* env, jclass clazz) { + mcu_module_t* module = NULL; + status_t err = hw_get_module(MCU_HARDWARE_MODULE_ID, + (hw_module_t const**)&module); + if (err) { + ALOGE("Couldn't load %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err)); + return 0; + } + + err = module->init(module); + if (err) { + ALOGE("Couldn't initialize %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err)); + return 0; + } + + return reinterpret_cast<jlong>(module); +} + +static jbyteArray nativeSendMessage(JNIEnv* env, jclass clazz, + jlong ptr, jstring msgStr, jbyteArray argArray) { + mcu_module_t* module = reinterpret_cast<mcu_module_t*>(ptr); + + ScopedUtfChars msg(env, msgStr); + ALOGV("Sending message %s to MCU", msg.c_str()); + + void* result = NULL; + size_t resultSize = 0; + status_t err; + if (argArray) { + ScopedByteArrayRO arg(env, argArray); + err = module->sendMessage(module, msg.c_str(), arg.get(), arg.size(), + &result, &resultSize); + } else { + err = module->sendMessage(module, msg.c_str(), NULL, 0, &result, &resultSize); + } + if (err) { + ALOGE("Couldn't send message to MCU (%s)", strerror(-err)); + return NULL; + } + + if (!result) { + return NULL; + } + + jbyteArray resultArray = env->NewByteArray(resultSize); + if (resultArray) { + env->SetByteArrayRegion(resultArray, 0, resultSize, static_cast<jbyte*>(result)); + } + free(result); + return resultArray; +} + +static JNINativeMethod gMcuHalMethods[] = { + /* name, signature, funcPtr */ + { "nativeOpen", "()J", + (void*) nativeOpen }, + { "nativeSendMessage", "(JLjava/lang/String;[B)[B", + (void*) nativeSendMessage }, +}; + +int register_android_server_dreams_McuHal(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "com/android/server/dreams/McuHal", + gMcuHalMethods, NELEM(gMcuHalMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + return 0; +} + +} /* namespace android */ diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp new file mode 100644 index 0000000..6e03993 --- /dev/null +++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp @@ -0,0 +1,756 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "HdmiCecJni" + +#define LOG_NDEBUG 1 + +#include "ScopedPrimitiveArray.h" + +#include <string> +#include <deque> +#include <map> + +#include <android_runtime/AndroidRuntime.h> +#include <android_runtime/Log.h> +#include <hardware/hdmi_cec.h> + +namespace android { + +static struct { + jmethodID handleMessage; + jmethodID handleHotplug; + jmethodID getActiveSource; + jmethodID getLanguage; +} gHdmiCecServiceClassInfo; + +#ifndef min +#define min(a, b) ((a) > (b) ? (b) : (a)) +#endif + +class HdmiCecHandler { +public: + enum HdmiCecError { + SUCCESS = 0, + FAILED = -1 + }; + + // Data type to hold a CEC message or internal event data. + typedef union { + cec_message_t cec; + hotplug_event_t hotplug; + } queue_item_t; + + // Entry used for message queue. + typedef std::pair<int, const queue_item_t> MessageEntry; + + HdmiCecHandler(hdmi_cec_device_t* device, jobject callbacksObj); + + void initialize(); + + // initialize individual logical device. + cec_logical_address_t initLogicalDevice(cec_device_type_t type); + void releaseLogicalDevice(cec_device_type_t type); + + cec_logical_address_t getLogicalAddress(cec_device_type_t deviceType); + uint16_t getPhysicalAddress(); + cec_device_type_t getDeviceType(cec_logical_address_t addr); + void queueMessage(const MessageEntry& message); + void queueOutgoingMessage(const cec_message_t& message); + void sendReportPhysicalAddress(cec_logical_address_t srcAddr); + void sendActiveSource(cec_logical_address_t srcAddr); + void sendFeatureAbort(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr, + int opcode, int reason); + void sendCecVersion(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr, + int version); + void sendDeviceVendorId(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr); + void sendGiveDeviceVendorID(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr); + void sendSetOsdName(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr, + const char* name, size_t len); + void sendSetMenuLanguage(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr); + + void sendCecMessage(const cec_message_t& message); + void setOsdName(const char* name, size_t len); + +private: + enum { + EVENT_TYPE_RX, + EVENT_TYPE_TX, + EVENT_TYPE_HOTPLUG, + EVENT_TYPE_STANDBY + }; + + /* + * logical address pool for each device type. + */ + static const cec_logical_address_t TV_ADDR_POOL[]; + static const cec_logical_address_t PLAYBACK_ADDR_POOL[]; + static const cec_logical_address_t RECORDER_ADDR_POOL[]; + static const cec_logical_address_t TUNER_ADDR_POOL[]; + + static const unsigned int MAX_BUFFER_SIZE = 256; + static const uint16_t INVALID_PHYSICAL_ADDRESS = 0xFFFF; + + static void onReceived(const hdmi_event_t* event, void* arg); + static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName); + + void updatePhysicalAddress(); + void updateLogicalAddress(); + + // Allocate logical address. The CEC standard recommends that we try to use the address + // we have ever used before, in case this is to allocate an address afte the cable is + // connected again. If preferredAddr is given a valid one (not CEC_ADDR_UNREGISTERED), then + // this method checks if the address is available first. If not, it tries other addresses + // int the address pool available for the given type. + cec_logical_address_t allocateLogicalAddress(cec_device_type_t type, + cec_logical_address_t preferredAddr); + + // Send a CEC ping message. Returns true if successful. + bool sendPing(cec_logical_address_t addr); + + // Return the pool of logical addresses that are used for a given device type. + // One of the addresses in the pool will be chosen in the allocation logic. + bool getLogicalAddressPool(cec_device_type_t type, const cec_logical_address_t** addrPool, + size_t* poolSize); + + // Handles the message retrieved from internal message queue. The message can be + // for either rx or tx. + void dispatchMessage(const MessageEntry& message); + void processIncomingMessage(const cec_message_t& msg); + + // Check the message before we pass it up to framework. If true, we proceed. + // otherwise do not propagate it. + bool precheckMessage(const cec_message_t& msg); + + // Propagate the message up to Java layer. + void propagateMessage(const cec_message_t& msg); + void propagateHotplug(bool connected); + + // Handles incoming <Request Active Source> message. If one of logical + // devices is active, it should reply with <Active Source> message. + void handleRequestActiveSource(); + void handleGetOsdName(const cec_message_t& msg); + void handleGiveDeviceVendorID(const cec_message_t& msg); + void handleGetCECVersion(const cec_message_t& msg); + void handleGetMenuLanguage(const cec_message_t& msg); + + // Internal thread for message queue handler + class HdmiThread : public Thread { + public: + HdmiThread(HdmiCecHandler* hdmiCecHandler, bool canCallJava) : + Thread(canCallJava), + mHdmiCecHandler(hdmiCecHandler) { + } + private: + virtual bool threadLoop() { + ALOGV("HdmiThread started"); + AutoMutex _l(mHdmiCecHandler->mMessageQueueLock); + mHdmiCecHandler->mMessageQueueCondition.wait(mHdmiCecHandler->mMessageQueueLock); + /* Process all messages in the queue */ + while (mHdmiCecHandler->mMessageQueue.size() > 0) { + MessageEntry entry = mHdmiCecHandler->mMessageQueue.front(); + mHdmiCecHandler->dispatchMessage(entry); + } + return true; + } + + HdmiCecHandler* mHdmiCecHandler; + }; + + // device type -> logical address mapping + std::map<cec_device_type_t, cec_logical_address_t> mLogicalDevices; + + hdmi_cec_device_t* mDevice; + jobject mCallbacksObj; + Mutex mLock; + Mutex mMessageQueueLock; + Condition mMessageQueueCondition; + sp<HdmiThread> mMessageQueueHandler; + + std::deque<MessageEntry> mMessageQueue; + uint16_t mPhysicalAddress; + std::string mOsdName; +}; + + const cec_logical_address_t HdmiCecHandler::TV_ADDR_POOL[] = { + CEC_ADDR_TV, + CEC_ADDR_FREE_USE, + }; + + const cec_logical_address_t HdmiCecHandler::PLAYBACK_ADDR_POOL[] = { + CEC_ADDR_PLAYBACK_1, + CEC_ADDR_PLAYBACK_2, + CEC_ADDR_PLAYBACK_3 + }; + + const cec_logical_address_t HdmiCecHandler::RECORDER_ADDR_POOL[] = { + CEC_ADDR_RECORDER_1, + CEC_ADDR_RECORDER_2, + CEC_ADDR_RECORDER_3 + }; + + const cec_logical_address_t HdmiCecHandler::TUNER_ADDR_POOL[] = { + CEC_ADDR_TUNER_1, + CEC_ADDR_TUNER_2, + CEC_ADDR_TUNER_3, + CEC_ADDR_TUNER_4 + }; + +HdmiCecHandler::HdmiCecHandler(hdmi_cec_device_t* device, jobject callbacksObj) : + mDevice(device), + mCallbacksObj(callbacksObj) { +} + +void HdmiCecHandler::initialize() { + mDevice->register_event_callback(mDevice, HdmiCecHandler::onReceived, this); + mMessageQueueHandler = new HdmiThread(this, true /* canCallJava */); + mMessageQueueHandler->run("MessageHandler"); + updatePhysicalAddress(); +} + +uint16_t HdmiCecHandler::getPhysicalAddress() { + return mPhysicalAddress; +} + +cec_logical_address_t HdmiCecHandler::initLogicalDevice(cec_device_type_t type) { + cec_logical_address addr = allocateLogicalAddress(type, CEC_ADDR_UNREGISTERED); + if (addr != CEC_ADDR_UNREGISTERED && !mDevice->add_logical_address(mDevice, addr)) { + mLogicalDevices.insert(std::pair<cec_device_type_t, cec_logical_address_t>(type, addr)); + + // Broadcast <Report Physical Address> when a new logical address was allocated to let + // other devices discover the new logical device and its logical - physical address + // association. + sendReportPhysicalAddress(addr); + } + return addr; +} + +void HdmiCecHandler::releaseLogicalDevice(cec_device_type_t type) { + std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.find(type); + if (it != mLogicalDevices.end()) { + mLogicalDevices.erase(it); + } + // TODO: remove the address monitored in HAL as well. +} + +cec_logical_address_t HdmiCecHandler::getLogicalAddress(cec_device_type_t type) { + std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.find(type); + if (it != mLogicalDevices.end()) { + return it->second; + } + return CEC_ADDR_UNREGISTERED; +} + +cec_device_type_t HdmiCecHandler::getDeviceType(cec_logical_address_t addr) { + std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin(); + for (; it != mLogicalDevices.end(); ++it) { + if (it->second == addr) { + return it->first; + } + } + return CEC_DEVICE_INACTIVE; +} + +void HdmiCecHandler::queueMessage(const MessageEntry& entry) { + AutoMutex _l(mMessageQueueLock); + if (mMessageQueue.size() <= MAX_BUFFER_SIZE) { + mMessageQueue.push_back(entry); + mMessageQueueCondition.signal(); + } else { + ALOGW("Queue is full! Message dropped."); + } +} + +void HdmiCecHandler::queueOutgoingMessage(const cec_message_t& message) { + queue_item_t item; + item.cec = message; + MessageEntry entry = std::make_pair(EVENT_TYPE_TX, item); + queueMessage(entry); +} + +void HdmiCecHandler::sendReportPhysicalAddress(cec_logical_address_t addr) { + if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) { + ALOGE("Invalid physical address."); + return; + } + cec_device_type_t deviceType = getDeviceType(addr); + if (deviceType == CEC_DEVICE_INACTIVE) { + ALOGE("Invalid logical address: %d", addr); + return; + } + + cec_message_t msg; + msg.initiator = addr; + msg.destination = CEC_ADDR_BROADCAST; + msg.length = 4; + msg.body[0] = CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS; + msg.body[1] = (mPhysicalAddress >> 8) & 0xff; + msg.body[2] = mPhysicalAddress & 0xff; + msg.body[3] = deviceType; + queueOutgoingMessage(msg); +} + +void HdmiCecHandler::sendActiveSource(cec_logical_address_t srcAddr) { + if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) { + ALOGE("Error getting physical address."); + return; + } + cec_message_t msg; + msg.initiator = srcAddr; + msg.destination = CEC_ADDR_BROADCAST; + msg.length = 3; + msg.body[0] = CEC_MESSAGE_ACTIVE_SOURCE; + msg.body[1] = (mPhysicalAddress >> 8) & 0xff; + msg.body[2] = mPhysicalAddress & 0xff; + queueOutgoingMessage(msg); +} + +void HdmiCecHandler::sendFeatureAbort(cec_logical_address_t srcAddr, + cec_logical_address_t dstAddr, int opcode, int reason) { + cec_message_t msg; + msg.initiator = srcAddr; + msg.destination = dstAddr; + msg.length = 3; + msg.body[0] = CEC_MESSAGE_FEATURE_ABORT; + msg.body[1] = opcode; + msg.body[2] = reason; + queueOutgoingMessage(msg); +} + +void HdmiCecHandler::sendCecVersion(cec_logical_address_t srcAddr, + cec_logical_address_t dstAddr, int version) { + cec_message_t msg; + msg.initiator = srcAddr; + msg.destination = dstAddr; + msg.length = 2; + msg.body[0] = CEC_MESSAGE_CEC_VERSION; + msg.body[1] = version; + queueOutgoingMessage(msg); +} + +void HdmiCecHandler::sendGiveDeviceVendorID(cec_logical_address_t srcAddr, + cec_logical_address_t dstAddr) { + cec_message_t msg; + msg.initiator = srcAddr; + msg.destination = dstAddr; + msg.length = 1; + msg.body[0] = CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID; + queueOutgoingMessage(msg); +} + +void HdmiCecHandler::sendDeviceVendorId(cec_logical_address_t srcAddr, + cec_logical_address_t dstAddr) { + cec_message_t msg; + msg.initiator = srcAddr; + msg.destination = dstAddr; + msg.length = 4; + msg.body[0] = CEC_MESSAGE_DEVICE_VENDOR_ID; + uint32_t vendor_id; + mDevice->get_vendor_id(mDevice, &vendor_id); + msg.body[1] = (vendor_id >> 16) & 0xff; + msg.body[2] = (vendor_id >> 8) & 0xff; + msg.body[3] = vendor_id & 0xff; + queueOutgoingMessage(msg); +} + +void HdmiCecHandler::sendSetOsdName(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr, + const char* name, size_t len) { + cec_message_t msg; + msg.initiator = srcAddr; + msg.destination = dstAddr; + msg.body[0] = CEC_MESSAGE_SET_OSD_NAME; + msg.length = min(len + 1, CEC_MESSAGE_BODY_MAX_LENGTH); + std::memcpy(msg.body + 1, name, msg.length - 1); + queueOutgoingMessage(msg); +} + +void HdmiCecHandler::sendSetMenuLanguage(cec_logical_address_t srcAddr, + cec_logical_address_t dstAddr) { + char lang[4]; // buffer for 3-letter language code + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jstring res = (jstring) env->CallObjectMethod(mCallbacksObj, + gHdmiCecServiceClassInfo.getLanguage, + getDeviceType(srcAddr)); + const char *clang = env->GetStringUTFChars(res, NULL); + strlcpy(lang, clang, sizeof(lang)); + env->ReleaseStringUTFChars(res, clang); + + cec_message_t msg; + msg.initiator = srcAddr; + msg.destination = dstAddr; + msg.length = 4; // opcode (1) + language code (3) + msg.body[0] = CEC_MESSAGE_SET_MENU_LANGUAGE; + std::memcpy(msg.body + 1, lang, 3); + queueOutgoingMessage(msg); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +void HdmiCecHandler::sendCecMessage(const cec_message_t& message) { + AutoMutex _l(mLock); + ALOGV("sendCecMessage"); + mDevice->send_message(mDevice, &message); +} + +void HdmiCecHandler::setOsdName(const char* name, size_t len) { + mOsdName.assign(name, min(len, CEC_MESSAGE_BODY_MAX_LENGTH - 1)); +} + +// static +void HdmiCecHandler::onReceived(const hdmi_event_t* event, void* arg) { + HdmiCecHandler* handler = static_cast<HdmiCecHandler*>(arg); + if (handler == NULL) { + return; + } + queue_item_t item; + if (event->type == HDMI_EVENT_CEC_MESSAGE) { + item.cec = event->cec; + MessageEntry entry = std::make_pair<int, const queue_item_t>(EVENT_TYPE_RX, item); + handler->queueMessage(entry); + } else if (event->type == HDMI_EVENT_HOT_PLUG) { + item.hotplug = event->hotplug; + MessageEntry entry = std::make_pair<int, const queue_item_t>(EVENT_TYPE_HOTPLUG, item); + handler->queueMessage(entry); + } +} + +// static +void HdmiCecHandler::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { + if (env->ExceptionCheck()) { + ALOGE("An exception was thrown by callback '%s'.", methodName); + LOGE_EX(env); + env->ExceptionClear(); + } +} + +void HdmiCecHandler::updatePhysicalAddress() { + uint16_t addr; + if (!mDevice->get_physical_address(mDevice, &addr)) { + mPhysicalAddress = addr; + } else { + mPhysicalAddress = INVALID_PHYSICAL_ADDRESS; + } +} + +void HdmiCecHandler::updateLogicalAddress() { + mDevice->clear_logical_address(mDevice); + std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin(); + for (; it != mLogicalDevices.end(); ++it) { + cec_logical_address_t addr; + cec_logical_address_t preferredAddr = it->second; + cec_device_type_t deviceType = it->first; + addr = allocateLogicalAddress(deviceType, preferredAddr); + if (!mDevice->add_logical_address(mDevice, addr)) { + it->second = addr; + } else { + it->second = CEC_ADDR_UNREGISTERED; + } + } +} + +cec_logical_address_t HdmiCecHandler::allocateLogicalAddress(cec_device_type_t type, + cec_logical_address_t preferredAddr) { + const cec_logical_address_t* addrPool; + size_t poolSize; + if (getLogicalAddressPool(type, &addrPool, &poolSize) < 0) { + return CEC_ADDR_UNREGISTERED; + } + unsigned start = 0; + + // Find the index of preferred address in the pool. If not found, the start + // position will be 0. This happens when the passed preferredAddr is set to + // CEC_ADDR_UNREGISTERED, meaning that no preferred address is given. + for (unsigned i = 0; i < poolSize; i++) { + if (addrPool[i] == preferredAddr) { + start = i; + break; + } + } + for (unsigned i = 0; i < poolSize; i++) { + cec_logical_address_t addr = addrPool[(start + i) % poolSize]; + if (!sendPing(addr)) { + // Failure in pinging means the address is available, not taken by any device. + ALOGV("Logical Address Allocation success: %d", addr); + return addr; + } + } + ALOGE("Logical Address Allocation failed"); + return CEC_ADDR_UNREGISTERED; +} + +bool HdmiCecHandler::sendPing(cec_logical_address addr) { + cec_message_t msg; + msg.initiator = msg.destination = addr; + msg.length = 0; + return !mDevice->send_message(mDevice, &msg); + +} + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +bool HdmiCecHandler::getLogicalAddressPool(cec_device_type_t deviceType, + const cec_logical_address_t** addrPool, size_t* poolSize) { + switch (deviceType) { + case CEC_DEVICE_TV: + *addrPool = TV_ADDR_POOL; + *poolSize = ARRAY_SIZE(TV_ADDR_POOL); + break; + case CEC_DEVICE_RECORDER: + *addrPool = RECORDER_ADDR_POOL; + *poolSize = ARRAY_SIZE(RECORDER_ADDR_POOL); + break; + case CEC_DEVICE_TUNER: + *addrPool = TUNER_ADDR_POOL; + *poolSize = ARRAY_SIZE(TUNER_ADDR_POOL); + break; + case CEC_DEVICE_PLAYBACK: + *addrPool = PLAYBACK_ADDR_POOL; + *poolSize = ARRAY_SIZE(PLAYBACK_ADDR_POOL); + break; + default: + ALOGE("Unsupported device type: %d", deviceType); + return false; + } + return true; +} + +#undef ARRAY_SIZE + +void HdmiCecHandler::dispatchMessage(const MessageEntry& entry) { + int type = entry.first; + mMessageQueueLock.unlock(); + if (type == EVENT_TYPE_RX) { + mMessageQueue.pop_front(); + processIncomingMessage(entry.second.cec); + } else if (type == EVENT_TYPE_TX) { + sendCecMessage(entry.second.cec); + mMessageQueue.pop_front(); + } else if (type == EVENT_TYPE_HOTPLUG) { + mMessageQueue.pop_front(); + bool connected = entry.second.hotplug.connected; + if (connected) { + updatePhysicalAddress(); + updateLogicalAddress(); + } + propagateHotplug(connected); + } + mMessageQueueLock.lock(); +} + +void HdmiCecHandler::processIncomingMessage(const cec_message_t& msg) { + int opcode = msg.body[0]; + if (opcode == CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS) { + sendReportPhysicalAddress(msg.destination); + } else if (opcode == CEC_MESSAGE_REQUEST_ACTIVE_SOURCE) { + handleRequestActiveSource(); + } else if (opcode == CEC_MESSAGE_GET_OSD_NAME) { + handleGetOsdName(msg); + } else if (opcode == CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID) { + handleGiveDeviceVendorID(msg); + } else if (opcode == CEC_MESSAGE_GET_CEC_VERSION) { + handleGetCECVersion(msg); + } else if (opcode == CEC_MESSAGE_GET_MENU_LANGUAGE) { + handleGetMenuLanguage(msg); + } else if (opcode == CEC_MESSAGE_ABORT) { + // Compliance testing requires that abort message be responded with feature abort. + sendFeatureAbort(msg.destination, msg.initiator, msg.body[0], ABORT_REFUSED); + } else { + if (precheckMessage(msg)) { + propagateMessage(msg); + } + } +} + +bool HdmiCecHandler::precheckMessage(const cec_message_t& msg) { + // Check if this is the broadcast message coming to itself, which need not be passed + // back to framework. This happens because CEC spec specifies that a physical device + // may host multiple logical devices. A broadcast message sent by one of them therefore + // should be able to reach the others by the loopback mechanism. + // + // Currently we don't deal with multiple logical devices, so this is not necessary. + // It should be revisited once we support hosting multiple logical devices. + int opcode = msg.body[0]; + if (msg.destination == CEC_ADDR_BROADCAST && + (opcode == CEC_MESSAGE_ACTIVE_SOURCE || + opcode == CEC_MESSAGE_SET_STREAM_PATH || + opcode == CEC_MESSAGE_INACTIVE_SOURCE)) { + uint16_t senderAddr = (msg.body[1] << 8) + msg.body[2]; + if (senderAddr == mPhysicalAddress) { + return false; + } + } + return true; +} + +void HdmiCecHandler::propagateMessage(const cec_message_t& msg) { + int paramLen = msg.length - 1; + jint srcAddr = msg.initiator; + jint dstAddr = msg.destination; + jint opcode = msg.body[0]; + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jbyteArray params = env->NewByteArray(paramLen); + const jbyte* body = reinterpret_cast<const jbyte *>(msg.body + 1); + if (paramLen > 0) { + env->SetByteArrayRegion(params, 0, paramLen, body); + } + env->CallVoidMethod(mCallbacksObj, + gHdmiCecServiceClassInfo.handleMessage, + srcAddr, dstAddr, opcode, params); + env->DeleteLocalRef(params); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +void HdmiCecHandler::propagateHotplug(bool connected) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, + gHdmiCecServiceClassInfo.handleHotplug, + connected); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + + +void HdmiCecHandler::handleRequestActiveSource() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jint activeDeviceType = env->CallIntMethod(mCallbacksObj, + gHdmiCecServiceClassInfo.getActiveSource); + if (activeDeviceType != CEC_DEVICE_INACTIVE) { + sendActiveSource(getLogicalAddress(static_cast<cec_device_type_t>(activeDeviceType))); + } + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +void HdmiCecHandler::handleGetOsdName(const cec_message_t& msg) { + if (!mOsdName.empty()) { + sendSetOsdName(msg.destination, msg.initiator, mOsdName.c_str(), mOsdName.length()); + } +} + +void HdmiCecHandler::handleGiveDeviceVendorID(const cec_message_t& msg) { + sendDeviceVendorId(msg.destination, msg.initiator); +} + +void HdmiCecHandler::handleGetCECVersion(const cec_message_t& msg) { + int version; + mDevice->get_version(mDevice, &version); + sendCecVersion(msg.destination, msg.initiator, version); +} + +void HdmiCecHandler::handleGetMenuLanguage(const cec_message_t& msg) { + sendSetMenuLanguage(msg.destination, msg.initiator); +} + +//------------------------------------------------------------------------------ + +#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ + var = env->GetMethodID(clazz, methodName, methodDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find method " methodName); + +static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj) { + int err; + hw_module_t* module; + err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID, const_cast<const hw_module_t **>(&module)); + if (err != 0) { + ALOGE("Error acquiring hardware module: %d", err); + return 0; + } + hw_device_t* device; + err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device); + if (err != 0) { + ALOGE("Error opening hardware module: %d", err); + return 0; + } + HdmiCecHandler *handler = new HdmiCecHandler(reinterpret_cast<hdmi_cec_device *>(device), + env->NewGlobalRef(callbacksObj)); + handler->initialize(); + + GET_METHOD_ID(gHdmiCecServiceClassInfo.handleMessage, clazz, + "handleMessage", "(III[B)V"); + GET_METHOD_ID(gHdmiCecServiceClassInfo.handleHotplug, clazz, + "handleHotplug", "(Z)V"); + GET_METHOD_ID(gHdmiCecServiceClassInfo.getActiveSource, clazz, + "getActiveSource", "()I"); + GET_METHOD_ID(gHdmiCecServiceClassInfo.getLanguage, clazz, + "getLanguage", "(I)Ljava/lang/String;"); + + return reinterpret_cast<jlong>(handler); +} + +static void nativeSendMessage(JNIEnv* env, jclass clazz, jlong handlerPtr, jint deviceType, + jint dstAddr, jint opcode, jbyteArray params) { + HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr); + cec_logical_address_t srcAddr = handler->getLogicalAddress( + static_cast<cec_device_type_t>(deviceType)); + jsize len = env->GetArrayLength(params); + ScopedByteArrayRO paramsPtr(env, params); + cec_message_t message; + message.initiator = srcAddr; + message.destination = static_cast<cec_logical_address_t>(dstAddr); + message.length = min(len + 1, CEC_MESSAGE_BODY_MAX_LENGTH); + message.body[0] = opcode; + std::memcpy(message.body + 1, paramsPtr.get(), message.length - 1); + handler->sendCecMessage(message); +} + +static jint nativeAllocateLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr, + jint deviceType) { + HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr); + return handler->initLogicalDevice(static_cast<cec_device_type_t>(deviceType)); +} + +static void nativeRemoveLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr, + jint deviceType) { + HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr); + return handler->releaseLogicalDevice(static_cast<cec_device_type_t>(deviceType)); +} + +static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr) { + HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr); + return handler->getPhysicalAddress(); +} + +static void nativeSetOsdName(JNIEnv* env, jclass clazz, jlong handlerPtr, jbyteArray name) { + HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr); + jsize len = env->GetArrayLength(name); + if (len > 0) { + ScopedByteArrayRO namePtr(env, name); + handler->setOsdName(reinterpret_cast<const char *>(namePtr.get()), len); + } +} + +static JNINativeMethod sMethods[] = { + /* name, signature, funcPtr */ + { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecService;)J", + (void *)nativeInit }, + { "nativeSendMessage", "(JIII[B)V", + (void *)nativeSendMessage }, + { "nativeAllocateLogicalAddress", "(JI)I", + (void *)nativeAllocateLogicalAddress }, + { "nativeRemoveLogicalAddress", "(JI)V", + (void *)nativeRemoveLogicalAddress }, + { "nativeGetPhysicalAddress", "(J)I", + (void *)nativeGetPhysicalAddress }, + { "nativeSetOsdName", "(J[B)V", + (void *)nativeSetOsdName }, +}; + +#define CLASS_PATH "com/android/server/hdmi/HdmiCecService" + +int register_android_server_hdmi_HdmiCecService(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp index b9681ab..f943d16 100644 --- a/services/jni/com_android_server_input_InputApplicationHandle.cpp +++ b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp @@ -90,7 +90,7 @@ sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle( AutoMutex _l(gHandleMutex); - int ptr = env->GetIntField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr); + jlong ptr = env->GetLongField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr); NativeInputApplicationHandle* handle; if (ptr) { handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr); @@ -98,8 +98,8 @@ sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle( jweak objWeak = env->NewWeakGlobalRef(inputApplicationHandleObj); handle = new NativeInputApplicationHandle(objWeak); handle->incStrong((void*)android_server_InputApplicationHandle_getHandle); - env->SetIntField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr, - reinterpret_cast<int>(handle)); + env->SetLongField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr, + reinterpret_cast<jlong>(handle)); } return handle; } @@ -110,9 +110,9 @@ sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle( static void android_server_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) { AutoMutex _l(gHandleMutex); - int ptr = env->GetIntField(obj, gInputApplicationHandleClassInfo.ptr); + jlong ptr = env->GetLongField(obj, gInputApplicationHandleClassInfo.ptr); if (ptr) { - env->SetIntField(obj, gInputApplicationHandleClassInfo.ptr, 0); + env->SetLongField(obj, gInputApplicationHandleClassInfo.ptr, 0); NativeInputApplicationHandle* handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr); handle->decStrong((void*)android_server_InputApplicationHandle_getHandle); @@ -143,7 +143,7 @@ int register_android_server_InputApplicationHandle(JNIEnv* env) { FIND_CLASS(clazz, "com/android/server/input/InputApplicationHandle"); GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz, - "ptr", "I"); + "ptr", "J"); GET_FIELD_ID(gInputApplicationHandleClassInfo.name, clazz, "name", "Ljava/lang/String;"); diff --git a/services/jni/com_android_server_input_InputApplicationHandle.h b/services/core/jni/com_android_server_input_InputApplicationHandle.h index 89d48c6..89d48c6 100644 --- a/services/jni/com_android_server_input_InputApplicationHandle.h +++ b/services/core/jni/com_android_server_input_InputApplicationHandle.h diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 4ab2086..a4f4a0b 100644 --- a/services/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -69,7 +69,7 @@ static struct { jmethodID notifyANR; jmethodID filterInputEvent; jmethodID interceptKeyBeforeQueueing; - jmethodID interceptMotionBeforeQueueingWhenScreenOff; + jmethodID interceptWakeMotionBeforeQueueing; jmethodID interceptKeyBeforeDispatching; jmethodID dispatchUnhandledKey; jmethodID checkInjectEventsPermission; @@ -99,6 +99,12 @@ static struct { jclass clazz; } gMotionEventClassInfo; +static struct { + jclass clazz; + jmethodID constructor; +} gInputDeviceIdentifierInfo; + + // --- Global functions --- @@ -144,8 +150,6 @@ static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t styl enum { WM_ACTION_PASS_TO_USER = 1, - WM_ACTION_WAKE_UP = 2, - WM_ACTION_GO_TO_SLEEP = 4, }; @@ -177,13 +181,14 @@ public: void setSystemUiVisibility(int32_t visibility); void setPointerSpeed(int32_t speed); void setShowTouches(bool enabled); + void setInteractive(bool interactive); /* --- InputReaderPolicyInterface implementation --- */ virtual void getReaderConfiguration(InputReaderConfiguration* outConfig); virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId); virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices); - virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor); + virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier); virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier); /* --- InputDispatcherPolicyInterface implementation --- */ @@ -197,7 +202,6 @@ public: virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle); virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags); virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig); - virtual bool isKeyRepeatEnabled(); virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags); virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags); virtual nsecs_t interceptKeyBeforeDispatching( @@ -245,14 +249,12 @@ private: wp<PointerController> pointerController; } mLocked; + volatile bool mInteractive; + void updateInactivityTimeoutLocked(const sp<PointerController>& controller); void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags); void ensureSpriteControllerLocked(); - // Power manager interactions. - bool isScreenOn(); - bool isScreenBright(); - static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName); static inline JNIEnv* jniEnv() { @@ -264,7 +266,7 @@ private: NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : - mLooper(looper) { + mLooper(looper), mInteractive(true) { JNIEnv* env = jniEnv(); mContextObj = env->NewGlobalRef(contextObj); @@ -492,13 +494,16 @@ void NativeInputManager::notifyInputDevicesChanged(const Vector<InputDeviceInfo> } sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay( - const String8& inputDeviceDescriptor) { + const InputDeviceIdentifier& identifier) { JNIEnv* env = jniEnv(); sp<KeyCharacterMap> result; - ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.string())); + ScopedLocalRef<jstring> descriptor(env, env->NewStringUTF(identifier.descriptor.string())); + ScopedLocalRef<jobject> identifierObj(env, env->NewObject(gInputDeviceIdentifierInfo.clazz, + gInputDeviceIdentifierInfo.constructor, descriptor.get(), + identifier.vendor, identifier.product)); ScopedLocalRef<jobjectArray> arrayObj(env, jobjectArray(env->CallObjectMethod(mServiceObj, - gServiceClassInfo.getKeyboardLayoutOverlay, descriptorObj.get()))); + gServiceClassInfo.getKeyboardLayoutOverlay, identifierObj.get()))); if (arrayObj.get()) { ScopedLocalRef<jstring> filenameObj(env, jstring(env->GetObjectArrayElement(arrayObj.get(), 0))); @@ -617,11 +622,6 @@ void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration } } -bool NativeInputManager::isKeyRepeatEnabled() { - // Only enable automatic key repeating when the screen is on. - return isScreenOn(); -} - void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) { Vector<sp<InputWindowHandle> > windowHandles; @@ -733,12 +733,8 @@ void NativeInputManager::setShowTouches(bool enabled) { InputReaderConfiguration::CHANGE_SHOW_TOUCHES); } -bool NativeInputManager::isScreenOn() { - return android_server_PowerManagerService_isScreenOn(); -} - -bool NativeInputManager::isScreenBright() { - return android_server_PowerManagerService_isScreenBright(); +void NativeInputManager::setInteractive(bool interactive) { + mInteractive = interactive; } bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) { @@ -779,18 +775,18 @@ void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, // - Ignore untrusted events and pass them along. // - Ask the window manager what to do with normal events and trusted injected events. // - For normal events wake and brighten the screen if currently off or dim. + if (mInteractive) { + policyFlags |= POLICY_FLAG_INTERACTIVE; + } if ((policyFlags & POLICY_FLAG_TRUSTED)) { nsecs_t when = keyEvent->getEventTime(); - bool isScreenOn = this->isScreenOn(); - bool isScreenBright = this->isScreenBright(); - JNIEnv* env = jniEnv(); jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); jint wmActions; if (keyEventObj) { wmActions = env->CallIntMethod(mServiceObj, gServiceClassInfo.interceptKeyBeforeQueueing, - keyEventObj, policyFlags, isScreenOn); + keyEventObj, policyFlags); if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) { wmActions = 0; } @@ -801,16 +797,6 @@ void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, wmActions = 0; } - if (!(policyFlags & POLICY_FLAG_INJECTED)) { - if (!isScreenOn) { - policyFlags |= POLICY_FLAG_WOKE_HERE; - } - - if (!isScreenBright) { - policyFlags |= POLICY_FLAG_BRIGHT_HERE; - } - } - handleInterceptActions(wmActions, when, /*byref*/ policyFlags); } else { policyFlags |= POLICY_FLAG_PASS_TO_USER; @@ -823,24 +809,22 @@ void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& p // - No special filtering for injected events required at this time. // - Filter normal events based on screen state. // - For normal events brighten (but do not wake) the screen if currently dim. + if (mInteractive) { + policyFlags |= POLICY_FLAG_INTERACTIVE; + } if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) { - if (isScreenOn()) { + if (policyFlags & POLICY_FLAG_INTERACTIVE) { policyFlags |= POLICY_FLAG_PASS_TO_USER; - - if (!isScreenBright()) { - policyFlags |= POLICY_FLAG_BRIGHT_HERE; - } - } else { + } else if (policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED)) { JNIEnv* env = jniEnv(); jint wmActions = env->CallIntMethod(mServiceObj, - gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff, - policyFlags); + gServiceClassInfo.interceptWakeMotionBeforeQueueing, + when, policyFlags); if (checkAndClearExceptionFromCallback(env, - "interceptMotionBeforeQueueingWhenScreenOff")) { + "interceptWakeMotionBeforeQueueing")) { wmActions = 0; } - policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE; handleInterceptActions(wmActions, when, /*byref*/ policyFlags); } } else { @@ -850,20 +834,6 @@ void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& p void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags) { - if (wmActions & WM_ACTION_GO_TO_SLEEP) { -#if DEBUG_INPUT_DISPATCHER_POLICY - ALOGD("handleInterceptActions: Going to sleep."); -#endif - android_server_PowerManagerService_goToSleep(when); - } - - if (wmActions & WM_ACTION_WAKE_UP) { -#if DEBUG_INPUT_DISPATCHER_POLICY - ALOGD("handleInterceptActions: Waking up."); -#endif - android_server_PowerManagerService_wakeUp(when); - } - if (wmActions & WM_ACTION_PASS_TO_USER) { policyFlags |= POLICY_FLAG_PASS_TO_USER; } else { @@ -977,7 +947,7 @@ void NativeInputManager::loadPointerResources(PointerResources* outResources) { // ---------------------------------------------------------------------------- -static jint nativeInit(JNIEnv* env, jclass clazz, +static jlong nativeInit(JNIEnv* env, jclass clazz, jobject serviceObj, jobject contextObj, jobject messageQueueObj) { sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { @@ -988,10 +958,10 @@ static jint nativeInit(JNIEnv* env, jclass clazz, NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper()); im->incStrong(0); - return reinterpret_cast<jint>(im); + return reinterpret_cast<jlong>(im); } -static void nativeStart(JNIEnv* env, jclass clazz, jint ptr) { +static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); status_t result = im->getInputManager()->start(); @@ -1000,7 +970,7 @@ static void nativeStart(JNIEnv* env, jclass clazz, jint ptr) { } } -static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz, jint ptr, jboolean external, +static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz, jlong ptr, jboolean external, jint displayId, jint orientation, jint logicalLeft, jint logicalTop, jint logicalRight, jint logicalBottom, jint physicalLeft, jint physicalTop, jint physicalRight, jint physicalBottom, @@ -1024,31 +994,31 @@ static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz, jint ptr, jboole } static jint nativeGetScanCodeState(JNIEnv* env, jclass clazz, - jint ptr, jint deviceId, jint sourceMask, jint scanCode) { + jlong ptr, jint deviceId, jint sourceMask, jint scanCode) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - return im->getInputManager()->getReader()->getScanCodeState( + return (jint) im->getInputManager()->getReader()->getScanCodeState( deviceId, uint32_t(sourceMask), scanCode); } static jint nativeGetKeyCodeState(JNIEnv* env, jclass clazz, - jint ptr, jint deviceId, jint sourceMask, jint keyCode) { + jlong ptr, jint deviceId, jint sourceMask, jint keyCode) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - return im->getInputManager()->getReader()->getKeyCodeState( + return (jint) im->getInputManager()->getReader()->getKeyCodeState( deviceId, uint32_t(sourceMask), keyCode); } static jint nativeGetSwitchState(JNIEnv* env, jclass clazz, - jint ptr, jint deviceId, jint sourceMask, jint sw) { + jlong ptr, jint deviceId, jint sourceMask, jint sw) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); - return im->getInputManager()->getReader()->getSwitchState( + return (jint) im->getInputManager()->getReader()->getSwitchState( deviceId, uint32_t(sourceMask), sw); } static jboolean nativeHasKeys(JNIEnv* env, jclass clazz, - jint ptr, jint deviceId, jint sourceMask, jintArray keyCodes, jbooleanArray outFlags) { + jlong ptr, jint deviceId, jint sourceMask, jintArray keyCodes, jbooleanArray outFlags) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); int32_t* codes = env->GetIntArrayElements(keyCodes, NULL); @@ -1056,8 +1026,12 @@ static jboolean nativeHasKeys(JNIEnv* env, jclass clazz, jsize numCodes = env->GetArrayLength(keyCodes); jboolean result; if (numCodes == env->GetArrayLength(keyCodes)) { - result = im->getInputManager()->getReader()->hasKeys( - deviceId, uint32_t(sourceMask), numCodes, codes, flags); + if (im->getInputManager()->getReader()->hasKeys( + deviceId, uint32_t(sourceMask), numCodes, codes, flags)) { + result = JNI_TRUE; + } else { + result = JNI_FALSE; + } } else { result = JNI_FALSE; } @@ -1082,7 +1056,7 @@ static void handleInputChannelDisposed(JNIEnv* env, } static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz, - jint ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) { + jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, @@ -1111,7 +1085,7 @@ static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz, } static void nativeUnregisterInputChannel(JNIEnv* env, jclass clazz, - jint ptr, jobject inputChannelObj) { + jlong ptr, jobject inputChannelObj) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, @@ -1132,14 +1106,14 @@ static void nativeUnregisterInputChannel(JNIEnv* env, jclass clazz, } static void nativeSetInputFilterEnabled(JNIEnv* env, jclass clazz, - jint ptr, jboolean enabled) { + jlong ptr, jboolean enabled) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->getInputManager()->getDispatcher()->setInputFilterEnabled(enabled); } static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz, - jint ptr, jobject inputEventObj, jint injectorPid, jint injectorUid, + jlong ptr, jobject inputEventObj, jint displayId, jint injectorPid, jint injectorUid, jint syncMode, jint timeoutMillis, jint policyFlags) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); @@ -1151,8 +1125,8 @@ static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz, return INPUT_EVENT_INJECTION_FAILED; } - return im->getInputManager()->getDispatcher()->injectInputEvent( - & keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis, + return (jint) im->getInputManager()->getDispatcher()->injectInputEvent( + & keyEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis, uint32_t(policyFlags)); } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) { const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj); @@ -1161,8 +1135,8 @@ static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz, return INPUT_EVENT_INJECTION_FAILED; } - return im->getInputManager()->getDispatcher()->injectInputEvent( - motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis, + return (jint) im->getInputManager()->getDispatcher()->injectInputEvent( + motionEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis, uint32_t(policyFlags)); } else { jniThrowRuntimeException(env, "Invalid input event type."); @@ -1171,35 +1145,35 @@ static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz, } static void nativeSetInputWindows(JNIEnv* env, jclass clazz, - jint ptr, jobjectArray windowHandleObjArray) { + jlong ptr, jobjectArray windowHandleObjArray) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->setInputWindows(env, windowHandleObjArray); } static void nativeSetFocusedApplication(JNIEnv* env, jclass clazz, - jint ptr, jobject applicationHandleObj) { + jlong ptr, jobject applicationHandleObj) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->setFocusedApplication(env, applicationHandleObj); } static void nativeSetInputDispatchMode(JNIEnv* env, - jclass clazz, jint ptr, jboolean enabled, jboolean frozen) { + jclass clazz, jlong ptr, jboolean enabled, jboolean frozen) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->setInputDispatchMode(enabled, frozen); } static void nativeSetSystemUiVisibility(JNIEnv* env, - jclass clazz, jint ptr, jint visibility) { + jclass clazz, jlong ptr, jint visibility) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->setSystemUiVisibility(visibility); } static jboolean nativeTransferTouchFocus(JNIEnv* env, - jclass clazz, jint ptr, jobject fromChannelObj, jobject toChannelObj) { + jclass clazz, jlong ptr, jobject fromChannelObj, jobject toChannelObj) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); sp<InputChannel> fromChannel = @@ -1208,29 +1182,40 @@ static jboolean nativeTransferTouchFocus(JNIEnv* env, android_view_InputChannel_getInputChannel(env, toChannelObj); if (fromChannel == NULL || toChannel == NULL) { - return false; + return JNI_FALSE; } - return im->getInputManager()->getDispatcher()-> - transferTouchFocus(fromChannel, toChannel); + if (im->getInputManager()->getDispatcher()-> + transferTouchFocus(fromChannel, toChannel)) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } } static void nativeSetPointerSpeed(JNIEnv* env, - jclass clazz, jint ptr, jint speed) { + jclass clazz, jlong ptr, jint speed) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->setPointerSpeed(speed); } static void nativeSetShowTouches(JNIEnv* env, - jclass clazz, jint ptr, jboolean enabled) { + jclass clazz, jlong ptr, jboolean enabled) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->setShowTouches(enabled); } +static void nativeSetInteractive(JNIEnv* env, + jclass clazz, jlong ptr, jboolean interactive) { + NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); + + im->setInteractive(interactive); +} + static void nativeVibrate(JNIEnv* env, - jclass clazz, jint ptr, jint deviceId, jlongArray patternObj, + jclass clazz, jlong ptr, jint deviceId, jlongArray patternObj, jint repeat, jint token) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); @@ -1247,7 +1232,7 @@ static void nativeVibrate(JNIEnv* env, nsecs_t pattern[patternSize]; for (size_t i = 0; i < patternSize; i++) { pattern[i] = max(jlong(0), min(patternMillis[i], - MAX_VIBRATE_PATTERN_DELAY_NSECS / 1000000LL)) * 1000000LL; + (jlong)(MAX_VIBRATE_PATTERN_DELAY_NSECS / 1000000LL))) * 1000000LL; } env->ReleasePrimitiveArrayCritical(patternObj, patternMillis, JNI_ABORT); @@ -1255,14 +1240,14 @@ static void nativeVibrate(JNIEnv* env, } static void nativeCancelVibrate(JNIEnv* env, - jclass clazz, jint ptr, jint deviceId, jint token) { + jclass clazz, jlong ptr, jint deviceId, jint token) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->getInputManager()->getReader()->cancelVibrate(deviceId, token); } static void nativeReloadKeyboardLayouts(JNIEnv* env, - jclass clazz, jint ptr) { + jclass clazz, jlong ptr) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->getInputManager()->getReader()->requestRefreshConfiguration( @@ -1270,14 +1255,14 @@ static void nativeReloadKeyboardLayouts(JNIEnv* env, } static void nativeReloadDeviceAliases(JNIEnv* env, - jclass clazz, jint ptr) { + jclass clazz, jlong ptr) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->getInputManager()->getReader()->requestRefreshConfiguration( InputReaderConfiguration::CHANGE_DEVICE_ALIAS); } -static jstring nativeDump(JNIEnv* env, jclass clazz, jint ptr) { +static jstring nativeDump(JNIEnv* env, jclass clazz, jlong ptr) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); String8 dump; @@ -1285,7 +1270,7 @@ static jstring nativeDump(JNIEnv* env, jclass clazz, jint ptr) { return env->NewStringUTF(dump.string()); } -static void nativeMonitor(JNIEnv* env, jclass clazz, jint ptr) { +static void nativeMonitor(JNIEnv* env, jclass clazz, jlong ptr) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); im->getInputManager()->getReader()->monitor(); @@ -1297,54 +1282,56 @@ static void nativeMonitor(JNIEnv* env, jclass clazz, jint ptr) { static JNINativeMethod gInputManagerMethods[] = { /* name, signature, funcPtr */ { "nativeInit", - "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)I", + "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)J", (void*) nativeInit }, - { "nativeStart", "(I)V", + { "nativeStart", "(J)V", (void*) nativeStart }, - { "nativeSetDisplayViewport", "(IZIIIIIIIIIIII)V", + { "nativeSetDisplayViewport", "(JZIIIIIIIIIIII)V", (void*) nativeSetDisplayViewport }, - { "nativeGetScanCodeState", "(IIII)I", + { "nativeGetScanCodeState", "(JIII)I", (void*) nativeGetScanCodeState }, - { "nativeGetKeyCodeState", "(IIII)I", + { "nativeGetKeyCodeState", "(JIII)I", (void*) nativeGetKeyCodeState }, - { "nativeGetSwitchState", "(IIII)I", + { "nativeGetSwitchState", "(JIII)I", (void*) nativeGetSwitchState }, - { "nativeHasKeys", "(III[I[Z)Z", + { "nativeHasKeys", "(JII[I[Z)Z", (void*) nativeHasKeys }, { "nativeRegisterInputChannel", - "(ILandroid/view/InputChannel;Lcom/android/server/input/InputWindowHandle;Z)V", + "(JLandroid/view/InputChannel;Lcom/android/server/input/InputWindowHandle;Z)V", (void*) nativeRegisterInputChannel }, - { "nativeUnregisterInputChannel", "(ILandroid/view/InputChannel;)V", + { "nativeUnregisterInputChannel", "(JLandroid/view/InputChannel;)V", (void*) nativeUnregisterInputChannel }, - { "nativeSetInputFilterEnabled", "(IZ)V", + { "nativeSetInputFilterEnabled", "(JZ)V", (void*) nativeSetInputFilterEnabled }, - { "nativeInjectInputEvent", "(ILandroid/view/InputEvent;IIIII)I", + { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIIII)I", (void*) nativeInjectInputEvent }, - { "nativeSetInputWindows", "(I[Lcom/android/server/input/InputWindowHandle;)V", + { "nativeSetInputWindows", "(J[Lcom/android/server/input/InputWindowHandle;)V", (void*) nativeSetInputWindows }, - { "nativeSetFocusedApplication", "(ILcom/android/server/input/InputApplicationHandle;)V", + { "nativeSetFocusedApplication", "(JLcom/android/server/input/InputApplicationHandle;)V", (void*) nativeSetFocusedApplication }, - { "nativeSetInputDispatchMode", "(IZZ)V", + { "nativeSetInputDispatchMode", "(JZZ)V", (void*) nativeSetInputDispatchMode }, - { "nativeSetSystemUiVisibility", "(II)V", + { "nativeSetSystemUiVisibility", "(JI)V", (void*) nativeSetSystemUiVisibility }, - { "nativeTransferTouchFocus", "(ILandroid/view/InputChannel;Landroid/view/InputChannel;)Z", + { "nativeTransferTouchFocus", "(JLandroid/view/InputChannel;Landroid/view/InputChannel;)Z", (void*) nativeTransferTouchFocus }, - { "nativeSetPointerSpeed", "(II)V", + { "nativeSetPointerSpeed", "(JI)V", (void*) nativeSetPointerSpeed }, - { "nativeSetShowTouches", "(IZ)V", + { "nativeSetShowTouches", "(JZ)V", (void*) nativeSetShowTouches }, - { "nativeVibrate", "(II[JII)V", + { "nativeSetInteractive", "(JZ)V", + (void*) nativeSetInteractive }, + { "nativeVibrate", "(JI[JII)V", (void*) nativeVibrate }, - { "nativeCancelVibrate", "(III)V", + { "nativeCancelVibrate", "(JII)V", (void*) nativeCancelVibrate }, - { "nativeReloadKeyboardLayouts", "(I)V", + { "nativeReloadKeyboardLayouts", "(J)V", (void*) nativeReloadKeyboardLayouts }, - { "nativeReloadDeviceAliases", "(I)V", + { "nativeReloadDeviceAliases", "(J)V", (void*) nativeReloadDeviceAliases }, - { "nativeDump", "(I)Ljava/lang/String;", + { "nativeDump", "(J)Ljava/lang/String;", (void*) nativeDump }, - { "nativeMonitor", "(I)V", + { "nativeMonitor", "(J)V", (void*) nativeMonitor }, }; @@ -1390,11 +1377,10 @@ int register_android_server_InputManager(JNIEnv* env) { "filterInputEvent", "(Landroid/view/InputEvent;I)Z"); GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz, - "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I"); + "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I"); - GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff, - clazz, - "interceptMotionBeforeQueueingWhenScreenOff", "(I)I"); + GET_METHOD_ID(gServiceClassInfo.interceptWakeMotionBeforeQueueing, clazz, + "interceptWakeMotionBeforeQueueing", "(JI)I"); GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz, "interceptKeyBeforeDispatching", @@ -1438,7 +1424,8 @@ int register_android_server_InputManager(JNIEnv* env) { "getPointerIcon", "()Landroid/view/PointerIcon;"); GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz, - "getKeyboardLayoutOverlay", "(Ljava/lang/String;)[Ljava/lang/String;"); + "getKeyboardLayoutOverlay", + "(Landroid/hardware/input/InputDeviceIdentifier;)[Ljava/lang/String;"); GET_METHOD_ID(gServiceClassInfo.getDeviceAlias, clazz, "getDeviceAlias", "(Ljava/lang/String;)Ljava/lang/String;"); @@ -1458,6 +1445,13 @@ int register_android_server_InputManager(JNIEnv* env) { FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent"); gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz)); + // InputDeviceIdentifier + + FIND_CLASS(gInputDeviceIdentifierInfo.clazz, "android/hardware/input/InputDeviceIdentifier"); + gInputDeviceIdentifierInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceIdentifierInfo.clazz)); + GET_METHOD_ID(gInputDeviceIdentifierInfo.constructor, gInputDeviceIdentifierInfo.clazz, + "<init>", "(Ljava/lang/String;II)V"); + return 0; } diff --git a/services/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp index 82e3dad..b80183c 100644 --- a/services/jni/com_android_server_input_InputWindowHandle.cpp +++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp @@ -173,7 +173,7 @@ sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle( AutoMutex _l(gHandleMutex); - int ptr = env->GetIntField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr); + jlong ptr = env->GetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr); NativeInputWindowHandle* handle; if (ptr) { handle = reinterpret_cast<NativeInputWindowHandle*>(ptr); @@ -187,8 +187,8 @@ sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle( jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj); handle = new NativeInputWindowHandle(inputApplicationHandle, objWeak); handle->incStrong((void*)android_server_InputWindowHandle_getHandle); - env->SetIntField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr, - reinterpret_cast<int>(handle)); + env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr, + reinterpret_cast<jlong>(handle)); } return handle; } @@ -199,9 +199,9 @@ sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle( static void android_server_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) { AutoMutex _l(gHandleMutex); - int ptr = env->GetIntField(obj, gInputWindowHandleClassInfo.ptr); + jlong ptr = env->GetLongField(obj, gInputWindowHandleClassInfo.ptr); if (ptr) { - env->SetIntField(obj, gInputWindowHandleClassInfo.ptr, 0); + env->SetLongField(obj, gInputWindowHandleClassInfo.ptr, 0); NativeInputWindowHandle* handle = reinterpret_cast<NativeInputWindowHandle*>(ptr); handle->decStrong((void*)android_server_InputWindowHandle_getHandle); @@ -232,7 +232,7 @@ int register_android_server_InputWindowHandle(JNIEnv* env) { FIND_CLASS(clazz, "com/android/server/input/InputWindowHandle"); GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz, - "ptr", "I"); + "ptr", "J"); GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle, clazz, diff --git a/services/jni/com_android_server_input_InputWindowHandle.h b/services/core/jni/com_android_server_input_InputWindowHandle.h index 2cfa17d3..2cfa17d3 100644 --- a/services/jni/com_android_server_input_InputWindowHandle.h +++ b/services/core/jni/com_android_server_input_InputWindowHandle.h diff --git a/services/jni/com_android_server_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp index 401e1aa..d51e044 100644 --- a/services/jni/com_android_server_LightsService.cpp +++ b/services/core/jni/com_android_server_lights_LightsService.cpp @@ -60,7 +60,7 @@ static light_device_t* get_device(hw_module_t* module, char const* name) } } -static jint init_native(JNIEnv *env, jobject clazz) +static jlong init_native(JNIEnv *env, jobject clazz) { int err; hw_module_t* module; @@ -90,10 +90,10 @@ static jint init_native(JNIEnv *env, jobject clazz) memset(devices, 0, sizeof(Devices)); } - return (jint)devices; + return (jlong)devices; } -static void finalize_native(JNIEnv *env, jobject clazz, int ptr) +static void finalize_native(JNIEnv *env, jobject clazz, jlong ptr) { Devices* devices = (Devices*)ptr; if (devices == NULL) { @@ -103,8 +103,8 @@ static void finalize_native(JNIEnv *env, jobject clazz, int ptr) free(devices); } -static void setLight_native(JNIEnv *env, jobject clazz, int ptr, - int light, int colorARGB, int flashMode, int onMS, int offMS, int brightnessMode) +static void setLight_native(JNIEnv *env, jobject clazz, jlong ptr, + jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode) { Devices* devices = (Devices*)ptr; light_state_t state; @@ -127,14 +127,14 @@ static void setLight_native(JNIEnv *env, jobject clazz, int ptr, } static JNINativeMethod method_table[] = { - { "init_native", "()I", (void*)init_native }, - { "finalize_native", "(I)V", (void*)finalize_native }, - { "setLight_native", "(IIIIIII)V", (void*)setLight_native }, + { "init_native", "()J", (void*)init_native }, + { "finalize_native", "(J)V", (void*)finalize_native }, + { "setLight_native", "(JIIIIII)V", (void*)setLight_native }, }; int register_android_server_LightsService(JNIEnv *env) { - return jniRegisterNativeMethods(env, "com/android/server/LightsService", + return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService", method_table, NELEM(method_table)); } diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp index 6c14887..6c14887 100644 --- a/services/jni/com_android_server_location_FlpHardwareProvider.cpp +++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp index aec254b..e9ba116 100644 --- a/services/jni/com_android_server_location_GpsLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp @@ -387,7 +387,11 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, } static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) { - return (sGpsInterface != NULL); + if (sGpsInterface != NULL) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } } static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj) @@ -398,7 +402,7 @@ static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject o // fail if the main interface fails to initialize if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) - return false; + return JNI_FALSE; // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL, // but continue to allow the rest of the GPS interface to work. @@ -413,7 +417,7 @@ static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject o if (sGpsGeofencingInterface) sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks); - return true; + return JNI_TRUE; } static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj) @@ -425,27 +429,42 @@ static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject ob static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time) { - if (sGpsInterface) - return (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy, - preferred_time) == 0); + if (sGpsInterface) { + if (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy, + preferred_time) == 0) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } + } else - return false; + return JNI_FALSE; } static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj) { - if (sGpsInterface) - return (sGpsInterface->start() == 0); + if (sGpsInterface) { + if (sGpsInterface->start() == 0) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } + } else - return false; + return JNI_FALSE; } static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj) { - if (sGpsInterface) - return (sGpsInterface->stop() == 0); + if (sGpsInterface) { + if (sGpsInterface->stop() == 0) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } + } else - return false; + return JNI_FALSE; } static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags) @@ -482,7 +501,7 @@ static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, job env->ReleaseFloatArrayElements(elevArray, elev, 0); env->ReleaseFloatArrayElements(azumArray, azim, 0); env->ReleaseIntArrayElements(maskArray, mask, 0); - return num_svs; + return (jint) num_svs; } static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(JNIEnv* env, @@ -552,7 +571,7 @@ static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject length = buffer_size; memcpy(nmea, sNmeaString, length); env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT); - return length; + return (jint) length; } static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, @@ -571,7 +590,11 @@ static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jo static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj) { - return (sGpsXtraInterface != NULL); + if (sGpsXtraInterface != NULL) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } } static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj, @@ -658,7 +681,7 @@ static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* e } static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj, - jboolean connected, int type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn) + jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn) { if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) { diff --git a/services/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index 151e134..af09861 100644 --- a/services/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -42,8 +42,6 @@ namespace android { // ---------------------------------------------------------------------------- static struct { - jmethodID wakeUpFromNative; - jmethodID goToSleepFromNative; jmethodID userActivityFromNative; } gPowerManagerServiceClassInfo; @@ -52,10 +50,6 @@ static struct { static jobject gPowerManagerServiceObj; static struct power_module* gPowerModule; -static Mutex gPowerManagerLock; -static bool gScreenOn; -static bool gScreenBright; - static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1]; // Throttling interval for user activity calls. @@ -73,16 +67,6 @@ static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodNa return false; } -bool android_server_PowerManagerService_isScreenOn() { - AutoMutex _l(gPowerManagerLock); - return gScreenOn; -} - -bool android_server_PowerManagerService_isScreenBright() { - AutoMutex _l(gPowerManagerLock); - return gScreenBright; -} - void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) { // Tell the power HAL when user activity occurs. if (gPowerModule && gPowerModule->powerHint) { @@ -114,28 +98,6 @@ void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t } } -void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) { - if (gPowerManagerServiceObj) { - JNIEnv* env = AndroidRuntime::getJNIEnv(); - - env->CallVoidMethod(gPowerManagerServiceObj, - gPowerManagerServiceClassInfo.wakeUpFromNative, - nanoseconds_to_milliseconds(eventTime)); - checkAndClearExceptionFromCallback(env, "wakeUpFromNative"); - } -} - -void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) { - if (gPowerManagerServiceObj) { - JNIEnv* env = AndroidRuntime::getJNIEnv(); - - env->CallVoidMethod(gPowerManagerServiceObj, - gPowerManagerServiceClassInfo.goToSleepFromNative, - nanoseconds_to_milliseconds(eventTime), 0); - checkAndClearExceptionFromCallback(env, "goToSleepFromNative"); - } -} - // ---------------------------------------------------------------------------- static void nativeInit(JNIEnv* env, jobject obj) { @@ -150,13 +112,6 @@ static void nativeInit(JNIEnv* env, jobject obj) { } } -static void nativeSetPowerState(JNIEnv* env, - jclass clazz, jboolean screenOn, jboolean screenBright) { - AutoMutex _l(gPowerManagerLock); - gScreenOn = screenOn; - gScreenBright = screenBright; -} - static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) { ScopedUtfChars name(env, nameStr); acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str()); @@ -195,8 +150,6 @@ static JNINativeMethod gPowerManagerServiceMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()V", (void*) nativeInit }, - { "nativeSetPowerState", "(ZZ)V", - (void*) nativeSetPowerState }, { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V", (void*) nativeAcquireSuspendBlocker }, { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V", @@ -229,12 +182,6 @@ int register_android_server_PowerManagerService(JNIEnv* env) { jclass clazz; FIND_CLASS(clazz, "com/android/server/power/PowerManagerService"); - GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz, - "wakeUpFromNative", "(J)V"); - - GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz, - "goToSleepFromNative", "(JI)V"); - GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz, "userActivityFromNative", "(JII)V"); @@ -242,8 +189,6 @@ int register_android_server_PowerManagerService(JNIEnv* env) { for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) { gLastEventTime[i] = LLONG_MIN; } - gScreenOn = true; - gScreenBright = true; gPowerManagerServiceObj = NULL; gPowerModule = NULL; return 0; diff --git a/services/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h index 0808b80..fb8153f 100644 --- a/services/jni/com_android_server_power_PowerManagerService.h +++ b/services/core/jni/com_android_server_power_PowerManagerService.h @@ -24,11 +24,7 @@ namespace android { -extern bool android_server_PowerManagerService_isScreenOn(); -extern bool android_server_PowerManagerService_isScreenBright(); extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType); -extern void android_server_PowerManagerService_wakeUp(nsecs_t eventTime); -extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime); } // namespace android diff --git a/services/jni/onload.cpp b/services/core/jni/onload.cpp index efc34a2..904966a 100644 --- a/services/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -21,6 +21,7 @@ namespace android { int register_android_server_AlarmManagerService(JNIEnv* env); +int register_android_server_AssetAtlasService(JNIEnv* env); int register_android_server_ConsumerIrService(JNIEnv *env); int register_android_server_InputApplicationHandle(JNIEnv* env); int register_android_server_InputWindowHandle(JNIEnv* env); @@ -28,14 +29,15 @@ int register_android_server_InputManager(JNIEnv* env); int register_android_server_LightsService(JNIEnv* env); int register_android_server_PowerManagerService(JNIEnv* env); int register_android_server_SerialService(JNIEnv* env); +int register_android_server_SystemServer(JNIEnv* env); int register_android_server_UsbDeviceManager(JNIEnv* env); int register_android_server_UsbHostManager(JNIEnv* env); int register_android_server_VibratorService(JNIEnv* env); -int register_android_server_SystemServer(JNIEnv* env); int register_android_server_location_GpsLocationProvider(JNIEnv* env); int register_android_server_location_FlpHardwareProvider(JNIEnv* env); int register_android_server_connectivity_Vpn(JNIEnv* env); -int register_android_server_AssetAtlasService(JNIEnv* env); +int register_android_server_dreams_McuHal(JNIEnv* env); +int register_android_server_hdmi_HdmiCecService(JNIEnv* env); }; using namespace android; @@ -67,7 +69,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) register_android_server_connectivity_Vpn(env); register_android_server_AssetAtlasService(env); register_android_server_ConsumerIrService(env); - + register_android_server_dreams_McuHal(env); + register_android_server_hdmi_HdmiCecService(env); return JNI_VERSION_1_4; } diff --git a/services/devicepolicy/Android.mk b/services/devicepolicy/Android.mk new file mode 100644 index 0000000..a55d138 --- /dev/null +++ b/services/devicepolicy/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.devicepolicy + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) + +LOCAL_JAVA_LIBRARIES := conscrypt + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2bb99d6..296d852 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.devicepolicy; import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; @@ -25,6 +25,7 @@ import com.android.internal.util.JournaledFile; import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; import com.android.org.conscrypt.TrustedCertificateStore; +import com.android.server.SystemService; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -117,7 +118,7 @@ import java.util.Set; */ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { - private static final String TAG = "DevicePolicyManagerService"; + private static final String LOG_TAG = "DevicePolicyManagerService"; private static final String DEVICE_POLICIES_XML = "device_policies.xml"; @@ -149,6 +150,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { */ private boolean mHasFeature; + public static final class Lifecycle extends SystemService { + private DevicePolicyManagerService mService; + + public Lifecycle(Context context) { + super(context); + mService = new DevicePolicyManagerService(context); + } + + @Override + public void onStart() { + publishBinderService(Context.DEVICE_POLICY_SERVICE, mService); + } + + @Override + public void onBootPhase(int phase) { + if (phase == PHASE_LOCK_SETTINGS_READY) { + mService.systemReady(); + } + } + } public static class DevicePolicyData { int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; int mActivePasswordLength = 0; @@ -186,7 +207,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getSendingUserId()); if (Intent.ACTION_BOOT_COMPLETED.equals(action) || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) { - if (DBG) Slog.v(TAG, "Sending password expiration notifications for action " + if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action " + action + " for user " + userHandle); mHandler.post(new Runnable() { public void run() { @@ -218,6 +239,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { }; static class ActiveAdmin { + private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features"; + private static final String TAG_DISABLE_CAMERA = "disable-camera"; + private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested"; + private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date"; + private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout"; + private static final String TAG_GLOBAL_PROXY_EXCLUSION_LIST = "global-proxy-exclusion-list"; + private static final String TAG_GLOBAL_PROXY_SPEC = "global-proxy-spec"; + private static final String TAG_SPECIFIES_GLOBAL_PROXY = "specifies-global-proxy"; + private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe"; + private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock"; + private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter"; + private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols"; + private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric"; + private static final String TAG_MIN_PASSWORD_LETTERS = "min-password-letters"; + private static final String TAG_MIN_PASSWORD_LOWERCASE = "min-password-lowercase"; + private static final String TAG_MIN_PASSWORD_UPPERCASE = "min-password-uppercase"; + private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length"; + private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length"; + private static final String ATTR_VALUE = "value"; + private static final String TAG_PASSWORD_QUALITY = "password-quality"; + private static final String TAG_POLICIES = "policies"; + final DeviceAdminInfo info; int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; @@ -281,103 +324,103 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { void writeToXml(XmlSerializer out) throws IllegalArgumentException, IllegalStateException, IOException { - out.startTag(null, "policies"); + out.startTag(null, TAG_POLICIES); info.writePoliciesToXml(out); - out.endTag(null, "policies"); + out.endTag(null, TAG_POLICIES); if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { - out.startTag(null, "password-quality"); - out.attribute(null, "value", Integer.toString(passwordQuality)); - out.endTag(null, "password-quality"); + out.startTag(null, TAG_PASSWORD_QUALITY); + out.attribute(null, ATTR_VALUE, Integer.toString(passwordQuality)); + out.endTag(null, TAG_PASSWORD_QUALITY); if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) { - out.startTag(null, "min-password-length"); - out.attribute(null, "value", Integer.toString(minimumPasswordLength)); - out.endTag(null, "min-password-length"); + out.startTag(null, TAG_MIN_PASSWORD_LENGTH); + out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLength)); + out.endTag(null, TAG_MIN_PASSWORD_LENGTH); } if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) { - out.startTag(null, "password-history-length"); - out.attribute(null, "value", Integer.toString(passwordHistoryLength)); - out.endTag(null, "password-history-length"); + out.startTag(null, TAG_PASSWORD_HISTORY_LENGTH); + out.attribute(null, ATTR_VALUE, Integer.toString(passwordHistoryLength)); + out.endTag(null, TAG_PASSWORD_HISTORY_LENGTH); } if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) { - out.startTag(null, "min-password-uppercase"); - out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase)); - out.endTag(null, "min-password-uppercase"); + out.startTag(null, TAG_MIN_PASSWORD_UPPERCASE); + out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordUpperCase)); + out.endTag(null, TAG_MIN_PASSWORD_UPPERCASE); } if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) { - out.startTag(null, "min-password-lowercase"); - out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase)); - out.endTag(null, "min-password-lowercase"); + out.startTag(null, TAG_MIN_PASSWORD_LOWERCASE); + out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLowerCase)); + out.endTag(null, TAG_MIN_PASSWORD_LOWERCASE); } if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) { - out.startTag(null, "min-password-letters"); - out.attribute(null, "value", Integer.toString(minimumPasswordLetters)); - out.endTag(null, "min-password-letters"); + out.startTag(null, TAG_MIN_PASSWORD_LETTERS); + out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLetters)); + out.endTag(null, TAG_MIN_PASSWORD_LETTERS); } if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) { - out.startTag(null, "min-password-numeric"); - out.attribute(null, "value", Integer.toString(minimumPasswordNumeric)); - out.endTag(null, "min-password-numeric"); + out.startTag(null, TAG_MIN_PASSWORD_NUMERIC); + out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordNumeric)); + out.endTag(null, TAG_MIN_PASSWORD_NUMERIC); } if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) { - out.startTag(null, "min-password-symbols"); - out.attribute(null, "value", Integer.toString(minimumPasswordSymbols)); - out.endTag(null, "min-password-symbols"); + out.startTag(null, TAG_MIN_PASSWORD_SYMBOLS); + out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordSymbols)); + out.endTag(null, TAG_MIN_PASSWORD_SYMBOLS); } if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) { - out.startTag(null, "min-password-nonletter"); - out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter)); - out.endTag(null, "min-password-nonletter"); + out.startTag(null, TAG_MIN_PASSWORD_NONLETTER); + out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordNonLetter)); + out.endTag(null, TAG_MIN_PASSWORD_NONLETTER); } } if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) { - out.startTag(null, "max-time-to-unlock"); - out.attribute(null, "value", Long.toString(maximumTimeToUnlock)); - out.endTag(null, "max-time-to-unlock"); + out.startTag(null, TAG_MAX_TIME_TO_UNLOCK); + out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock)); + out.endTag(null, TAG_MAX_TIME_TO_UNLOCK); } if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) { - out.startTag(null, "max-failed-password-wipe"); - out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe)); - out.endTag(null, "max-failed-password-wipe"); + out.startTag(null, TAG_MAX_FAILED_PASSWORD_WIPE); + out.attribute(null, ATTR_VALUE, Integer.toString(maximumFailedPasswordsForWipe)); + out.endTag(null, TAG_MAX_FAILED_PASSWORD_WIPE); } if (specifiesGlobalProxy) { - out.startTag(null, "specifies-global-proxy"); - out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy)); - out.endTag(null, "specifies_global_proxy"); + out.startTag(null, TAG_SPECIFIES_GLOBAL_PROXY); + out.attribute(null, ATTR_VALUE, Boolean.toString(specifiesGlobalProxy)); + out.endTag(null, TAG_SPECIFIES_GLOBAL_PROXY); if (globalProxySpec != null) { - out.startTag(null, "global-proxy-spec"); - out.attribute(null, "value", globalProxySpec); - out.endTag(null, "global-proxy-spec"); + out.startTag(null, TAG_GLOBAL_PROXY_SPEC); + out.attribute(null, ATTR_VALUE, globalProxySpec); + out.endTag(null, TAG_GLOBAL_PROXY_SPEC); } if (globalProxyExclusionList != null) { - out.startTag(null, "global-proxy-exclusion-list"); - out.attribute(null, "value", globalProxyExclusionList); - out.endTag(null, "global-proxy-exclusion-list"); + out.startTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST); + out.attribute(null, ATTR_VALUE, globalProxyExclusionList); + out.endTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST); } } if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) { - out.startTag(null, "password-expiration-timeout"); - out.attribute(null, "value", Long.toString(passwordExpirationTimeout)); - out.endTag(null, "password-expiration-timeout"); + out.startTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT); + out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationTimeout)); + out.endTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT); } if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) { - out.startTag(null, "password-expiration-date"); - out.attribute(null, "value", Long.toString(passwordExpirationDate)); - out.endTag(null, "password-expiration-date"); + out.startTag(null, TAG_PASSWORD_EXPIRATION_DATE); + out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationDate)); + out.endTag(null, TAG_PASSWORD_EXPIRATION_DATE); } if (encryptionRequested) { - out.startTag(null, "encryption-requested"); - out.attribute(null, "value", Boolean.toString(encryptionRequested)); - out.endTag(null, "encryption-requested"); + out.startTag(null, TAG_ENCRYPTION_REQUESTED); + out.attribute(null, ATTR_VALUE, Boolean.toString(encryptionRequested)); + out.endTag(null, TAG_ENCRYPTION_REQUESTED); } if (disableCamera) { - out.startTag(null, "disable-camera"); - out.attribute(null, "value", Boolean.toString(disableCamera)); - out.endTag(null, "disable-camera"); + out.startTag(null, TAG_DISABLE_CAMERA); + out.attribute(null, ATTR_VALUE, Boolean.toString(disableCamera)); + out.endTag(null, TAG_DISABLE_CAMERA); } if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) { - out.startTag(null, "disable-keyguard-features"); - out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures)); - out.endTag(null, "disable-keyguard-features"); + out.startTag(null, TAG_DISABLE_KEYGUARD_FEATURES); + out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures)); + out.endTag(null, TAG_DISABLE_KEYGUARD_FEATURES); } } @@ -391,67 +434,67 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { continue; } String tag = parser.getName(); - if ("policies".equals(tag)) { + if (TAG_POLICIES.equals(tag)) { info.readPoliciesFromXml(parser); - } else if ("password-quality".equals(tag)) { + } else if (TAG_PASSWORD_QUALITY.equals(tag)) { passwordQuality = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("min-password-length".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) { minimumPasswordLength = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("password-history-length".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) { passwordHistoryLength = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("min-password-uppercase".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) { minimumPasswordUpperCase = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("min-password-lowercase".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) { minimumPasswordLowerCase = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("min-password-letters".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) { minimumPasswordLetters = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("min-password-numeric".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) { minimumPasswordNumeric = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("min-password-symbols".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) { minimumPasswordSymbols = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("min-password-nonletter".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) { minimumPasswordNonLetter = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("max-time-to-unlock".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) { maximumTimeToUnlock = Long.parseLong( - parser.getAttributeValue(null, "value")); - } else if ("max-failed-password-wipe".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) { maximumFailedPasswordsForWipe = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("specifies-global-proxy".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) { specifiesGlobalProxy = Boolean.parseBoolean( - parser.getAttributeValue(null, "value")); - } else if ("global-proxy-spec".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) { globalProxySpec = - parser.getAttributeValue(null, "value"); - } else if ("global-proxy-exclusion-list".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE); + } else if (TAG_GLOBAL_PROXY_EXCLUSION_LIST.equals(tag)) { globalProxyExclusionList = - parser.getAttributeValue(null, "value"); - } else if ("password-expiration-timeout".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE); + } else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) { passwordExpirationTimeout = Long.parseLong( - parser.getAttributeValue(null, "value")); - } else if ("password-expiration-date".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) { passwordExpirationDate = Long.parseLong( - parser.getAttributeValue(null, "value")); - } else if ("encryption-requested".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) { encryptionRequested = Boolean.parseBoolean( - parser.getAttributeValue(null, "value")); - } else if ("disable-camera".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_CAMERA.equals(tag)) { disableCamera = Boolean.parseBoolean( - parser.getAttributeValue(null, "value")); - } else if ("disable-keyguard-features".equals(tag)) { + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) { disabledKeyguardFeatures = Integer.parseInt( - parser.getAttributeValue(null, "value")); + parser.getAttributeValue(null, ATTR_VALUE)); } else { - Slog.w(TAG, "Unknown admin tag: " + tag); + Slog.w(LOG_TAG, "Unknown admin tag: " + tag); } XmlUtils.skipCurrentTag(parser); } @@ -513,7 +556,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void handlePackagesChanged(int userHandle) { boolean removed = false; - if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle); + if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle); DevicePolicyData policy = getUserData(userHandle); IPackageManager pm = AppGlobals.getPackageManager(); for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { @@ -585,7 +628,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { void removeUserData(int userHandle) { synchronized (this) { if (userHandle == UserHandle.USER_OWNER) { - Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring."); + Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring."); return; } DevicePolicyData policy = mUserData.get(userHandle); @@ -595,7 +638,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { File policyFile = new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML); policyFile.delete(); - Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath()); + Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath()); } } @@ -792,10 +835,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try { return new DeviceAdminInfo(mContext, infos.get(0)); } catch (XmlPullParserException e) { - Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e); + Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, + e); return null; } catch (IOException e) { - Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e); + Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, + e); return null; } } @@ -922,7 +967,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ComponentName.unflattenFromString(name), userHandle); if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) != userHandle)) { - Slog.w(TAG, "findAdmin returned an incorrect uid " + Slog.w(LOG_TAG, "findAdmin returned an incorrect uid " + dai.getActivityInfo().applicationInfo.uid + " for user " + userHandle); } @@ -933,7 +978,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mAdminList.add(ap); } } catch (RuntimeException e) { - Slog.w(TAG, "Failed loading admin " + name, e); + Slog.w(LOG_TAG, "Failed loading admin " + name, e); } } else if ("failed-password-attempts".equals(tag)) { policy.mFailedPasswordAttempts = Integer.parseInt( @@ -962,22 +1007,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { parser.getAttributeValue(null, "nonletter")); XmlUtils.skipCurrentTag(parser); } else { - Slog.w(TAG, "Unknown tag: " + tag); + Slog.w(LOG_TAG, "Unknown tag: " + tag); XmlUtils.skipCurrentTag(parser); } } } catch (NullPointerException e) { - Slog.w(TAG, "failed parsing " + file + " " + e); + Slog.w(LOG_TAG, "failed parsing " + file + " " + e); } catch (NumberFormatException e) { - Slog.w(TAG, "failed parsing " + file + " " + e); + Slog.w(LOG_TAG, "failed parsing " + file + " " + e); } catch (XmlPullParserException e) { - Slog.w(TAG, "failed parsing " + file + " " + e); + Slog.w(LOG_TAG, "failed parsing " + file + " " + e); } catch (FileNotFoundException e) { // Don't be noisy, this is normal if we haven't defined any policies. } catch (IOException e) { - Slog.w(TAG, "failed parsing " + file + " " + e); + Slog.w(LOG_TAG, "failed parsing " + file + " " + e); } catch (IndexOutOfBoundsException e) { - Slog.w(TAG, "failed parsing " + file + " " + e); + Slog.w(LOG_TAG, "failed parsing " + file + " " + e); } try { if (stream != null) { @@ -993,7 +1038,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // never normally happen. LockPatternUtils utils = new LockPatternUtils(mContext); if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) { - Slog.w(TAG, "Active password quality 0x" + Slog.w(LOG_TAG, "Active password quality 0x" + Integer.toHexString(policy.mActivePasswordQuality) + " does not match actual quality 0x" + Integer.toHexString(utils.getActivePasswordQuality())); @@ -1037,7 +1082,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } if (!haveOwner) { - Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner + Slog.w(LOG_TAG, "Previous password owner " + policy.mPasswordOwner + " no longer active; disabling"); policy.mPasswordOwner = -1; } @@ -1057,7 +1102,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long token = Binder.clearCallingIdentity(); try { String value = cameraDisabled ? "1" : "0"; - if (DBG) Slog.v(TAG, "Change in camera state [" + if (DBG) Slog.v(LOG_TAG, "Change in camera state [" + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value); SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value); } finally { @@ -1173,7 +1218,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { long ident = Binder.clearCallingIdentity(); try { - if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) { + if (!refreshing + && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) { throw new IllegalArgumentException("Admin is already added"); } ActiveAdmin newAdmin = new ActiveAdmin(info); @@ -1443,7 +1489,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ap.passwordExpirationDate = expiration; ap.passwordExpirationTimeout = timeout; if (timeout > 0L) { - Slog.w(TAG, "setPasswordExpiration(): password will expire on " + Slog.w(LOG_TAG, "setPasswordExpiration(): password will expire on " + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT) .format(new Date(expiration))); } @@ -1789,11 +1835,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return true; } return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle) - && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle) - && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle) - && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle) - && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle) - && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle); + && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle) + && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle) + && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle) + && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle) + && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle); } } @@ -1871,7 +1917,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int realQuality = LockPatternUtils.computePasswordQuality(password); if (realQuality < quality && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { - Slog.w(TAG, "resetPassword: password quality 0x" + Slog.w(LOG_TAG, "resetPassword: password quality 0x" + Integer.toHexString(realQuality) + " does not meet required quality 0x" + Integer.toHexString(quality)); @@ -1881,7 +1927,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } int length = getPasswordMinimumLength(null, userHandle); if (password.length() < length) { - Slog.w(TAG, "resetPassword: password length " + password.length() + Slog.w(LOG_TAG, "resetPassword: password length " + password.length() + " does not meet required length " + length); return false; } @@ -1910,40 +1956,40 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } int neededLetters = getPasswordMinimumLetters(null, userHandle); if(letters < neededLetters) { - Slog.w(TAG, "resetPassword: number of letters " + letters + Slog.w(LOG_TAG, "resetPassword: number of letters " + letters + " does not meet required number of letters " + neededLetters); return false; } int neededNumbers = getPasswordMinimumNumeric(null, userHandle); if (numbers < neededNumbers) { - Slog.w(TAG, "resetPassword: number of numerical digits " + numbers + Slog.w(LOG_TAG, "resetPassword: number of numerical digits " + numbers + " does not meet required number of numerical digits " + neededNumbers); return false; } int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle); if (lowercase < neededLowerCase) { - Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase + Slog.w(LOG_TAG, "resetPassword: number of lowercase letters " + lowercase + " does not meet required number of lowercase letters " + neededLowerCase); return false; } int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle); if (uppercase < neededUpperCase) { - Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase + Slog.w(LOG_TAG, "resetPassword: number of uppercase letters " + uppercase + " does not meet required number of uppercase letters " + neededUpperCase); return false; } int neededSymbols = getPasswordMinimumSymbols(null, userHandle); if (symbols < neededSymbols) { - Slog.w(TAG, "resetPassword: number of special symbols " + symbols + Slog.w(LOG_TAG, "resetPassword: number of special symbols " + symbols + " does not meet required number of special symbols " + neededSymbols); return false; } int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle); if (nonletter < neededNonLetter) { - Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter + Slog.w(LOG_TAG, "resetPassword: number of non-letter characters " + nonletter + " does not meet required number of non-letter characters " + neededNonLetter); return false; @@ -1954,7 +2000,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int callingUid = Binder.getCallingUid(); DevicePolicyData policy = getUserData(userHandle); if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) { - Slog.w(TAG, "resetPassword: already set by another uid and not entered by user"); + Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user"); return false; } @@ -2020,7 +2066,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try { getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs); } catch (RemoteException e) { - Slog.w(TAG, "Failure talking with power manager", e); + Slog.w(LOG_TAG, "Failure talking with power manager", e); } } finally { Binder.restoreCallingIdentity(ident); @@ -2095,10 +2141,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { X509Certificate cert = parseCert(certBuffer); pemCert = Credentials.convertToPem(cert); } catch (CertificateException ce) { - Log.e(TAG, "Problem converting cert", ce); + Log.e(LOG_TAG, "Problem converting cert", ce); return false; } catch (IOException ioe) { - Log.e(TAG, "Problem reading cert", ioe); + Log.e(LOG_TAG, "Problem reading cert", ioe); return false; } try { @@ -2113,7 +2159,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } catch (InterruptedException e1) { - Log.w(TAG, "installCaCertsToKeyChain(): ", e1); + Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1); Thread.currentThread().interrupt(); } return false; @@ -2134,10 +2180,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { X509Certificate cert = parseCert(certBuffer); alias = certStore.getCertificateAlias(cert); } catch (CertificateException ce) { - Log.e(TAG, "Problem creating X509Certificate", ce); + Log.e(LOG_TAG, "Problem creating X509Certificate", ce); return; } catch (IOException ioe) { - Log.e(TAG, "Problem reading certificate", ioe); + Log.e(LOG_TAG, "Problem reading certificate", ioe); return; } try { @@ -2146,13 +2192,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try { service.deleteCaCertificate(alias); } catch (RemoteException e) { - Log.e(TAG, "from CaCertUninstaller: ", e); + Log.e(LOG_TAG, "from CaCertUninstaller: ", e); } finally { keyChainConnection.close(); keyChainConnection = null; } } catch (InterruptedException ie) { - Log.w(TAG, "CaCertUninstaller: ", ie); + Log.w(LOG_TAG, "CaCertUninstaller: ", ie); Thread.currentThread().interrupt(); } } @@ -2173,7 +2219,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try { RecoverySystem.rebootWipeUserData(mContext); } catch (IOException e) { - Slog.w(TAG, "Failed requesting data wipe", e); + Slog.w(LOG_TAG, "Failed requesting data wipe", e); } } } @@ -2264,8 +2310,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters || p.mActivePasswordUpperCase != uppercase - || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers - || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) { + || p.mActivePasswordLowerCase != lowercase + || p.mActivePasswordNumeric != numbers + || p.mActivePasswordSymbols != symbols + || p.mActivePasswordNonLetter != nonletter) { long ident = Binder.clearCallingIdentity(); try { p.mActivePasswordQuality = quality; @@ -2387,7 +2435,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // If the user is not the owner, don't set the global proxy. Fail silently. if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { - Slog.w(TAG, "Only the owner is allowed to set the global proxy. User " + Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User " + userHandle + " is not permitted."); return null; } @@ -2468,7 +2516,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList); if (!proxyProperties.isValid()) { - Slog.e(TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString()); + Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString()); return; } Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]); @@ -2494,7 +2542,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Only owner can set storage encryption if (userHandle != UserHandle.USER_OWNER || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { - Slog.w(TAG, "Only owner is allowed to set storage encryption. User " + Slog.w(LOG_TAG, "Only owner is allowed to set storage encryption. User " + UserHandle.getCallingUserId() + " is not permitted."); return 0; } @@ -2880,7 +2928,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } catch (NameNotFoundException nnfe) { - Slog.w(TAG, "Device Owner package " + packageName + " not installed."); + Slog.w(LOG_TAG, "Device Owner package " + packageName + " not installed."); } return false; } @@ -2905,9 +2953,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mOwnerName = parser.getAttributeValue(null, ATTR_NAME); input.close(); } catch (XmlPullParserException xppe) { - Slog.e(TAG, "Error parsing device-owner file\n" + xppe); + Slog.e(LOG_TAG, "Error parsing device-owner file\n" + xppe); } catch (IOException ioe) { - Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe); + Slog.e(LOG_TAG, "IO Exception when reading device-owner file\n" + ioe); } } @@ -2935,7 +2983,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.flush(); file.finishWrite(output); } catch (IOException ioe) { - Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe); + Slog.e(LOG_TAG, "IO Exception when writing device-owner file\n" + ioe); } } } diff --git a/services/input/Android.mk b/services/input/Android.mk deleted file mode 100644 index 6e944ef..0000000 --- a/services/input/Android.mk +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) 2010 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - EventHub.cpp \ - InputApplication.cpp \ - InputDispatcher.cpp \ - InputListener.cpp \ - InputManager.cpp \ - InputReader.cpp \ - InputWindow.cpp \ - PointerController.cpp \ - SpriteController.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - liblog \ - libandroidfw \ - libutils \ - libhardware \ - libhardware_legacy \ - libskia \ - libgui \ - libui \ - libinput - -LOCAL_C_INCLUDES := \ - external/skia/include/core - -LOCAL_MODULE:= libinputservice - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) - - -# Include subdirectory makefiles -# ============================================================ - -# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework -# team really wants is to build the stuff defined by this makefile. -ifeq (,$(ONE_SHOT_MAKEFILE)) -include $(call first-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp deleted file mode 100644 index 4d70d5f..0000000 --- a/services/input/EventHub.cpp +++ /dev/null @@ -1,1583 +0,0 @@ -/* - * Copyright (C) 2005 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "EventHub" - -// #define LOG_NDEBUG 0 - -#include "EventHub.h" - -#include <hardware_legacy/power.h> - -#include <cutils/properties.h> -#include <utils/Log.h> -#include <utils/Timers.h> -#include <utils/threads.h> -#include <utils/Errors.h> - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <memory.h> -#include <errno.h> -#include <assert.h> - -#include <input/KeyLayoutMap.h> -#include <input/KeyCharacterMap.h> -#include <input/VirtualKeyMap.h> - -#include <string.h> -#include <stdint.h> -#include <dirent.h> - -#include <sys/inotify.h> -#include <sys/epoll.h> -#include <sys/ioctl.h> -#include <sys/limits.h> -#include <sys/sha1.h> - -/* this macro is used to tell if "bit" is set in "array" - * it selects a byte from the array, and does a boolean AND - * operation with a byte that only has the relevant bit set. - * eg. to check for the 12th bit, we do (array[1] & 1<<4) - */ -#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) - -/* this macro computes the number of bytes needed to represent a bit array of the specified size */ -#define sizeof_bit_array(bits) ((bits + 7) / 8) - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " - -namespace android { - -static const char *WAKE_LOCK_ID = "KeyEvents"; -static const char *DEVICE_PATH = "/dev/input"; - -/* return the larger integer */ -static inline int max(int v1, int v2) -{ - return (v1 > v2) ? v1 : v2; -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static String8 sha1(const String8& in) { - SHA1_CTX ctx; - SHA1Init(&ctx); - SHA1Update(&ctx, reinterpret_cast<const u_char*>(in.string()), in.size()); - u_char digest[SHA1_DIGEST_LENGTH]; - SHA1Final(digest, &ctx); - - String8 out; - for (size_t i = 0; i < SHA1_DIGEST_LENGTH; i++) { - out.appendFormat("%02x", digest[i]); - } - return out; -} - -static void setDescriptor(InputDeviceIdentifier& identifier) { - // Compute a device descriptor that uniquely identifies the device. - // The descriptor is assumed to be a stable identifier. Its value should not - // change between reboots, reconnections, firmware updates or new releases of Android. - // Ideally, we also want the descriptor to be short and relatively opaque. - String8 rawDescriptor; - rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor, identifier.product); - if (!identifier.uniqueId.isEmpty()) { - rawDescriptor.append("uniqueId:"); - rawDescriptor.append(identifier.uniqueId); - } if (identifier.vendor == 0 && identifier.product == 0) { - // If we don't know the vendor and product id, then the device is probably - // built-in so we need to rely on other information to uniquely identify - // the input device. Usually we try to avoid relying on the device name or - // location but for built-in input device, they are unlikely to ever change. - if (!identifier.name.isEmpty()) { - rawDescriptor.append("name:"); - rawDescriptor.append(identifier.name); - } else if (!identifier.location.isEmpty()) { - rawDescriptor.append("location:"); - rawDescriptor.append(identifier.location); - } - } - identifier.descriptor = sha1(rawDescriptor); - ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.string(), - identifier.descriptor.string()); -} - -// --- Global Functions --- - -uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { - // Touch devices get dibs on touch-related axes. - if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) { - switch (axis) { - case ABS_X: - case ABS_Y: - case ABS_PRESSURE: - case ABS_TOOL_WIDTH: - case ABS_DISTANCE: - case ABS_TILT_X: - case ABS_TILT_Y: - case ABS_MT_SLOT: - case ABS_MT_TOUCH_MAJOR: - case ABS_MT_TOUCH_MINOR: - case ABS_MT_WIDTH_MAJOR: - case ABS_MT_WIDTH_MINOR: - case ABS_MT_ORIENTATION: - case ABS_MT_POSITION_X: - case ABS_MT_POSITION_Y: - case ABS_MT_TOOL_TYPE: - case ABS_MT_BLOB_ID: - case ABS_MT_TRACKING_ID: - case ABS_MT_PRESSURE: - case ABS_MT_DISTANCE: - return INPUT_DEVICE_CLASS_TOUCH; - } - } - - // Joystick devices get the rest. - return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK; -} - -// --- EventHub::Device --- - -EventHub::Device::Device(int fd, int32_t id, const String8& path, - const InputDeviceIdentifier& identifier) : - next(NULL), - fd(fd), id(id), path(path), identifier(identifier), - classes(0), configuration(NULL), virtualKeyMap(NULL), - ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0), - timestampOverrideSec(0), timestampOverrideUsec(0) { - memset(keyBitmask, 0, sizeof(keyBitmask)); - memset(absBitmask, 0, sizeof(absBitmask)); - memset(relBitmask, 0, sizeof(relBitmask)); - memset(swBitmask, 0, sizeof(swBitmask)); - memset(ledBitmask, 0, sizeof(ledBitmask)); - memset(ffBitmask, 0, sizeof(ffBitmask)); - memset(propBitmask, 0, sizeof(propBitmask)); -} - -EventHub::Device::~Device() { - close(); - delete configuration; - delete virtualKeyMap; -} - -void EventHub::Device::close() { - if (fd >= 0) { - ::close(fd); - fd = -1; - } -} - - -// --- EventHub --- - -const uint32_t EventHub::EPOLL_ID_INOTIFY; -const uint32_t EventHub::EPOLL_ID_WAKE; -const int EventHub::EPOLL_SIZE_HINT; -const int EventHub::EPOLL_MAX_EVENTS; - -EventHub::EventHub(void) : - mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(), - mOpeningDevices(0), mClosingDevices(0), - mNeedToSendFinishedDeviceScan(false), - mNeedToReopenDevices(false), mNeedToScanDevices(true), - mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) { - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); - - mEpollFd = epoll_create(EPOLL_SIZE_HINT); - LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); - - mINotifyFd = inotify_init(); - int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); - LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s. errno=%d", - DEVICE_PATH, errno); - - struct epoll_event eventItem; - memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = EPOLLIN; - eventItem.data.u32 = EPOLL_ID_INOTIFY; - result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno); - - int wakeFds[2]; - result = pipe(wakeFds); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); - - mWakeReadPipeFd = wakeFds[0]; - mWakeWritePipeFd = wakeFds[1]; - - result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", - errno); - - result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", - errno); - - eventItem.data.u32 = EPOLL_ID_WAKE; - result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", - errno); -} - -EventHub::~EventHub(void) { - closeAllDevicesLocked(); - - while (mClosingDevices) { - Device* device = mClosingDevices; - mClosingDevices = device->next; - delete device; - } - - ::close(mEpollFd); - ::close(mINotifyFd); - ::close(mWakeReadPipeFd); - ::close(mWakeWritePipeFd); - - release_wake_lock(WAKE_LOCK_ID); -} - -InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == NULL) return InputDeviceIdentifier(); - return device->identifier; -} - -uint32_t EventHub::getDeviceClasses(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == NULL) return 0; - return device->classes; -} - -int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == NULL) return 0; - return device->controllerNumber; -} - -void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && device->configuration) { - *outConfiguration = *device->configuration; - } else { - outConfiguration->clear(); - } -} - -status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const { - outAxisInfo->clear(); - - if (axis >= 0 && axis <= ABS_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { - struct input_absinfo info; - if(ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", - axis, device->identifier.name.string(), device->fd, errno); - return -errno; - } - - if (info.minimum != info.maximum) { - outAxisInfo->valid = true; - outAxisInfo->minValue = info.minimum; - outAxisInfo->maxValue = info.maximum; - outAxisInfo->flat = info.flat; - outAxisInfo->fuzz = info.fuzz; - outAxisInfo->resolution = info.resolution; - } - return OK; - } - } - return -1; -} - -bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const { - if (axis >= 0 && axis <= REL_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device) { - return test_bit(axis, device->relBitmask); - } - } - return false; -} - -bool EventHub::hasInputProperty(int32_t deviceId, int property) const { - if (property >= 0 && property <= INPUT_PROP_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device) { - return test_bit(property, device->propBitmask); - } - } - return false; -} - -int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { - if (scanCode >= 0 && scanCode <= KEY_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) { - uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; - memset(keyState, 0, sizeof(keyState)); - if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { - return test_bit(scanCode, keyState) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - } - } - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) { - Vector<int32_t> scanCodes; - device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes); - if (scanCodes.size() != 0) { - uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; - memset(keyState, 0, sizeof(keyState)); - if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { - for (size_t i = 0; i < scanCodes.size(); i++) { - int32_t sc = scanCodes.itemAt(i); - if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, keyState)) { - return AKEY_STATE_DOWN; - } - } - return AKEY_STATE_UP; - } - } - } - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { - if (sw >= 0 && sw <= SW_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) { - uint8_t swState[sizeof_bit_array(SW_MAX + 1)]; - memset(swState, 0, sizeof(swState)); - if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) { - return test_bit(sw, swState) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - } - } - return AKEY_STATE_UNKNOWN; -} - -status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { - *outValue = 0; - - if (axis >= 0 && axis <= ABS_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { - struct input_absinfo info; - if(ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", - axis, device->identifier.name.string(), device->fd, errno); - return -errno; - } - - *outValue = info.value; - return OK; - } - } - return -1; -} - -bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) const { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && device->keyMap.haveKeyLayout()) { - Vector<int32_t> scanCodes; - for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { - scanCodes.clear(); - - status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey( - keyCodes[codeIndex], &scanCodes); - if (! err) { - // check the possible scan codes identified by the layout map against the - // map of codes actually emitted by the driver - for (size_t sc = 0; sc < scanCodes.size(); sc++) { - if (test_bit(scanCodes[sc], device->keyBitmask)) { - outFlags[codeIndex] = 1; - break; - } - } - } - } - return true; - } - return false; -} - -status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t* outKeycode, uint32_t* outFlags) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - - if (device) { - // Check the key character map first. - sp<KeyCharacterMap> kcm = device->getKeyCharacterMap(); - if (kcm != NULL) { - if (!kcm->mapKey(scanCode, usageCode, outKeycode)) { - *outFlags = 0; - return NO_ERROR; - } - } - - // Check the key layout next. - if (device->keyMap.haveKeyLayout()) { - if (!device->keyMap.keyLayoutMap->mapKey( - scanCode, usageCode, outKeycode, outFlags)) { - return NO_ERROR; - } - } - } - - *outKeycode = 0; - *outFlags = 0; - return NAME_NOT_FOUND; -} - -status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - - if (device && device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo); - if (err == NO_ERROR) { - return NO_ERROR; - } - } - - return NAME_NOT_FOUND; -} - -void EventHub::setExcludedDevices(const Vector<String8>& devices) { - AutoMutex _l(mLock); - - mExcludedDevices = devices; -} - -bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && scanCode >= 0 && scanCode <= KEY_MAX) { - if (test_bit(scanCode, device->keyBitmask)) { - return true; - } - } - return false; -} - -bool EventHub::hasLed(int32_t deviceId, int32_t led) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && led >= 0 && led <= LED_MAX) { - if (test_bit(led, device->ledBitmask)) { - return true; - } - } - return false; -} - -void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && led >= 0 && led <= LED_MAX) { - struct input_event ev; - ev.time.tv_sec = 0; - ev.time.tv_usec = 0; - ev.type = EV_LED; - ev.code = led; - ev.value = on ? 1 : 0; - - ssize_t nWrite; - do { - nWrite = write(device->fd, &ev, sizeof(struct input_event)); - } while (nWrite == -1 && errno == EINTR); - } -} - -void EventHub::getVirtualKeyDefinitions(int32_t deviceId, - Vector<VirtualKeyDefinition>& outVirtualKeys) const { - outVirtualKeys.clear(); - - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && device->virtualKeyMap) { - outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys()); - } -} - -sp<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device) { - return device->getKeyCharacterMap(); - } - return NULL; -} - -bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, - const sp<KeyCharacterMap>& map) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device) { - if (map != device->overlayKeyMap) { - device->overlayKeyMap = map; - device->combinedKeyMap = KeyCharacterMap::combine( - device->keyMap.keyCharacterMap, map); - return true; - } - } - return false; -} - -void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual()) { - ff_effect effect; - memset(&effect, 0, sizeof(effect)); - effect.type = FF_RUMBLE; - effect.id = device->ffEffectId; - effect.u.rumble.strong_magnitude = 0xc000; - effect.u.rumble.weak_magnitude = 0xc000; - effect.replay.length = (duration + 999999LL) / 1000000LL; - effect.replay.delay = 0; - if (ioctl(device->fd, EVIOCSFF, &effect)) { - ALOGW("Could not upload force feedback effect to device %s due to error %d.", - device->identifier.name.string(), errno); - return; - } - device->ffEffectId = effect.id; - - struct input_event ev; - ev.time.tv_sec = 0; - ev.time.tv_usec = 0; - ev.type = EV_FF; - ev.code = device->ffEffectId; - ev.value = 1; - if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { - ALOGW("Could not start force feedback effect on device %s due to error %d.", - device->identifier.name.string(), errno); - return; - } - device->ffEffectPlaying = true; - } -} - -void EventHub::cancelVibrate(int32_t deviceId) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual()) { - if (device->ffEffectPlaying) { - device->ffEffectPlaying = false; - - struct input_event ev; - ev.time.tv_sec = 0; - ev.time.tv_usec = 0; - ev.type = EV_FF; - ev.code = device->ffEffectId; - ev.value = 0; - if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { - ALOGW("Could not stop force feedback effect on device %s due to error %d.", - device->identifier.name.string(), errno); - return; - } - } - } -} - -EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const { - if (deviceId == BUILT_IN_KEYBOARD_ID) { - deviceId = mBuiltInKeyboardId; - } - ssize_t index = mDevices.indexOfKey(deviceId); - return index >= 0 ? mDevices.valueAt(index) : NULL; -} - -EventHub::Device* EventHub::getDeviceByPathLocked(const char* devicePath) const { - for (size_t i = 0; i < mDevices.size(); i++) { - Device* device = mDevices.valueAt(i); - if (device->path == devicePath) { - return device; - } - } - return NULL; -} - -size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { - ALOG_ASSERT(bufferSize >= 1); - - AutoMutex _l(mLock); - - struct input_event readBuffer[bufferSize]; - - RawEvent* event = buffer; - size_t capacity = bufferSize; - bool awoken = false; - for (;;) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - - // Reopen input devices if needed. - if (mNeedToReopenDevices) { - mNeedToReopenDevices = false; - - ALOGI("Reopening all input devices due to a configuration change."); - - closeAllDevicesLocked(); - mNeedToScanDevices = true; - break; // return to the caller before we actually rescan - } - - // Report any devices that had last been added/removed. - while (mClosingDevices) { - Device* device = mClosingDevices; - ALOGV("Reporting device closed: id=%d, name=%s\n", - device->id, device->path.string()); - mClosingDevices = device->next; - event->when = now; - event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id; - event->type = DEVICE_REMOVED; - event += 1; - delete device; - mNeedToSendFinishedDeviceScan = true; - if (--capacity == 0) { - break; - } - } - - if (mNeedToScanDevices) { - mNeedToScanDevices = false; - scanDevicesLocked(); - mNeedToSendFinishedDeviceScan = true; - } - - while (mOpeningDevices != NULL) { - Device* device = mOpeningDevices; - ALOGV("Reporting device opened: id=%d, name=%s\n", - device->id, device->path.string()); - mOpeningDevices = device->next; - event->when = now; - event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; - event->type = DEVICE_ADDED; - event += 1; - mNeedToSendFinishedDeviceScan = true; - if (--capacity == 0) { - break; - } - } - - if (mNeedToSendFinishedDeviceScan) { - mNeedToSendFinishedDeviceScan = false; - event->when = now; - event->type = FINISHED_DEVICE_SCAN; - event += 1; - if (--capacity == 0) { - break; - } - } - - // Grab the next input event. - bool deviceChanged = false; - while (mPendingEventIndex < mPendingEventCount) { - const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; - if (eventItem.data.u32 == EPOLL_ID_INOTIFY) { - if (eventItem.events & EPOLLIN) { - mPendingINotify = true; - } else { - ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events); - } - continue; - } - - if (eventItem.data.u32 == EPOLL_ID_WAKE) { - if (eventItem.events & EPOLLIN) { - ALOGV("awoken after wake()"); - awoken = true; - char buffer[16]; - ssize_t nRead; - do { - nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); - } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); - } else { - ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.", - eventItem.events); - } - continue; - } - - ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32); - if (deviceIndex < 0) { - ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.", - eventItem.events, eventItem.data.u32); - continue; - } - - Device* device = mDevices.valueAt(deviceIndex); - if (eventItem.events & EPOLLIN) { - int32_t readSize = read(device->fd, readBuffer, - sizeof(struct input_event) * capacity); - if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { - // Device was removed before INotify noticed. - ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d " - "capacity: %d errno: %d)\n", - device->fd, readSize, bufferSize, capacity, errno); - deviceChanged = true; - closeDeviceLocked(device); - } else if (readSize < 0) { - if (errno != EAGAIN && errno != EINTR) { - ALOGW("could not get event (errno=%d)", errno); - } - } else if ((readSize % sizeof(struct input_event)) != 0) { - ALOGE("could not get event (wrong size: %d)", readSize); - } else { - int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; - - size_t count = size_t(readSize) / sizeof(struct input_event); - for (size_t i = 0; i < count; i++) { - struct input_event& iev = readBuffer[i]; - ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d", - device->path.string(), - (int) iev.time.tv_sec, (int) iev.time.tv_usec, - iev.type, iev.code, iev.value); - - // Some input devices may have a better concept of the time - // when an input event was actually generated than the kernel - // which simply timestamps all events on entry to evdev. - // This is a custom Android extension of the input protocol - // mainly intended for use with uinput based device drivers. - if (iev.type == EV_MSC) { - if (iev.code == MSC_ANDROID_TIME_SEC) { - device->timestampOverrideSec = iev.value; - continue; - } else if (iev.code == MSC_ANDROID_TIME_USEC) { - device->timestampOverrideUsec = iev.value; - continue; - } - } - if (device->timestampOverrideSec || device->timestampOverrideUsec) { - iev.time.tv_sec = device->timestampOverrideSec; - iev.time.tv_usec = device->timestampOverrideUsec; - if (iev.type == EV_SYN && iev.code == SYN_REPORT) { - device->timestampOverrideSec = 0; - device->timestampOverrideUsec = 0; - } - ALOGV("applied override time %d.%06d", - int(iev.time.tv_sec), int(iev.time.tv_usec)); - } - -#ifdef HAVE_POSIX_CLOCKS - // Use the time specified in the event instead of the current time - // so that downstream code can get more accurate estimates of - // event dispatch latency from the time the event is enqueued onto - // the evdev client buffer. - // - // The event's timestamp fortuitously uses the same monotonic clock - // time base as the rest of Android. The kernel event device driver - // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts(). - // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere - // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a - // system call that also queries ktime_get_ts(). - event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL - + nsecs_t(iev.time.tv_usec) * 1000LL; - ALOGV("event time %lld, now %lld", event->when, now); - - // Bug 7291243: Add a guard in case the kernel generates timestamps - // that appear to be far into the future because they were generated - // using the wrong clock source. - // - // This can happen because when the input device is initially opened - // it has a default clock source of CLOCK_REALTIME. Any input events - // enqueued right after the device is opened will have timestamps - // generated using CLOCK_REALTIME. We later set the clock source - // to CLOCK_MONOTONIC but it is already too late. - // - // Invalid input event timestamps can result in ANRs, crashes and - // and other issues that are hard to track down. We must not let them - // propagate through the system. - // - // Log a warning so that we notice the problem and recover gracefully. - if (event->when >= now + 10 * 1000000000LL) { - // Double-check. Time may have moved on. - nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC); - if (event->when > time) { - ALOGW("An input event from %s has a timestamp that appears to " - "have been generated using the wrong clock source " - "(expected CLOCK_MONOTONIC): " - "event time %lld, current time %lld, call time %lld. " - "Using current time instead.", - device->path.string(), event->when, time, now); - event->when = time; - } else { - ALOGV("Event time is ok but failed the fast path and required " - "an extra call to systemTime: " - "event time %lld, current time %lld, call time %lld.", - event->when, time, now); - } - } -#else - event->when = now; -#endif - event->deviceId = deviceId; - event->type = iev.type; - event->code = iev.code; - event->value = iev.value; - event += 1; - capacity -= 1; - } - if (capacity == 0) { - // The result buffer is full. Reset the pending event index - // so we will try to read the device again on the next iteration. - mPendingEventIndex -= 1; - break; - } - } - } else if (eventItem.events & EPOLLHUP) { - ALOGI("Removing device %s due to epoll hang-up event.", - device->identifier.name.string()); - deviceChanged = true; - closeDeviceLocked(device); - } else { - ALOGW("Received unexpected epoll event 0x%08x for device %s.", - eventItem.events, device->identifier.name.string()); - } - } - - // readNotify() will modify the list of devices so this must be done after - // processing all other events to ensure that we read all remaining events - // before closing the devices. - if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) { - mPendingINotify = false; - readNotifyLocked(); - deviceChanged = true; - } - - // Report added or removed devices immediately. - if (deviceChanged) { - continue; - } - - // Return now if we have collected any events or if we were explicitly awoken. - if (event != buffer || awoken) { - break; - } - - // Poll for events. Mind the wake lock dance! - // We hold a wake lock at all times except during epoll_wait(). This works due to some - // subtle choreography. When a device driver has pending (unread) events, it acquires - // a kernel wake lock. However, once the last pending event has been read, the device - // driver will release the kernel wake lock. To prevent the system from going to sleep - // when this happens, the EventHub holds onto its own user wake lock while the client - // is processing events. Thus the system can only sleep if there are no events - // pending or currently being processed. - // - // The timeout is advisory only. If the device is asleep, it will not wake just to - // service the timeout. - mPendingEventIndex = 0; - - mLock.unlock(); // release lock before poll, must be before release_wake_lock - release_wake_lock(WAKE_LOCK_ID); - - int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); - - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); - mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock - - if (pollResult == 0) { - // Timed out. - mPendingEventCount = 0; - break; - } - - if (pollResult < 0) { - // An error occurred. - mPendingEventCount = 0; - - // Sleep after errors to avoid locking up the system. - // Hopefully the error is transient. - if (errno != EINTR) { - ALOGW("poll failed (errno=%d)\n", errno); - usleep(100000); - } - } else { - // Some events occurred. - mPendingEventCount = size_t(pollResult); - } - } - - // All done, return the number of events we read. - return event - buffer; -} - -void EventHub::wake() { - ALOGV("wake() called"); - - ssize_t nWrite; - do { - nWrite = write(mWakeWritePipeFd, "W", 1); - } while (nWrite == -1 && errno == EINTR); - - if (nWrite != 1 && errno != EAGAIN) { - ALOGW("Could not write wake signal, errno=%d", errno); - } -} - -void EventHub::scanDevicesLocked() { - status_t res = scanDirLocked(DEVICE_PATH); - if(res < 0) { - ALOGE("scan dir failed for %s\n", DEVICE_PATH); - } - if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) { - createVirtualKeyboardLocked(); - } -} - -// ---------------------------------------------------------------------------- - -static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) { - const uint8_t* end = array + endIndex; - array += startIndex; - while (array != end) { - if (*(array++) != 0) { - return true; - } - } - return false; -} - -static const int32_t GAMEPAD_KEYCODES[] = { - AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, - AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, - AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, - AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, - AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, - AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, - AKEYCODE_BUTTON_1, AKEYCODE_BUTTON_2, AKEYCODE_BUTTON_3, AKEYCODE_BUTTON_4, - AKEYCODE_BUTTON_5, AKEYCODE_BUTTON_6, AKEYCODE_BUTTON_7, AKEYCODE_BUTTON_8, - AKEYCODE_BUTTON_9, AKEYCODE_BUTTON_10, AKEYCODE_BUTTON_11, AKEYCODE_BUTTON_12, - AKEYCODE_BUTTON_13, AKEYCODE_BUTTON_14, AKEYCODE_BUTTON_15, AKEYCODE_BUTTON_16, -}; - -status_t EventHub::openDeviceLocked(const char *devicePath) { - char buffer[80]; - - ALOGV("Opening device: %s", devicePath); - - int fd = open(devicePath, O_RDWR | O_CLOEXEC); - if(fd < 0) { - ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); - return -1; - } - - InputDeviceIdentifier identifier; - - // Get device name. - if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.name.setTo(buffer); - } - - // Check to see if the device is on our excluded list - for (size_t i = 0; i < mExcludedDevices.size(); i++) { - const String8& item = mExcludedDevices.itemAt(i); - if (identifier.name == item) { - ALOGI("ignoring event id %s driver %s\n", devicePath, item.string()); - close(fd); - return -1; - } - } - - // Get device driver version. - int driverVersion; - if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { - ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); - close(fd); - return -1; - } - - // Get device identifier. - struct input_id inputId; - if(ioctl(fd, EVIOCGID, &inputId)) { - ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); - close(fd); - return -1; - } - identifier.bus = inputId.bustype; - identifier.product = inputId.product; - identifier.vendor = inputId.vendor; - identifier.version = inputId.version; - - // Get device physical location. - if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.location.setTo(buffer); - } - - // Get device unique id. - if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.uniqueId.setTo(buffer); - } - - // Fill in the descriptor. - setDescriptor(identifier); - - // Make file descriptor non-blocking for use with poll(). - if (fcntl(fd, F_SETFL, O_NONBLOCK)) { - ALOGE("Error %d making device file descriptor non-blocking.", errno); - close(fd); - return -1; - } - - // Allocate device. (The device object takes ownership of the fd at this point.) - int32_t deviceId = mNextDeviceId++; - Device* device = new Device(fd, deviceId, String8(devicePath), identifier); - - ALOGV("add device %d: %s\n", deviceId, devicePath); - ALOGV(" bus: %04x\n" - " vendor %04x\n" - " product %04x\n" - " version %04x\n", - identifier.bus, identifier.vendor, identifier.product, identifier.version); - ALOGV(" name: \"%s\"\n", identifier.name.string()); - ALOGV(" location: \"%s\"\n", identifier.location.string()); - ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.string()); - ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.string()); - ALOGV(" driver: v%d.%d.%d\n", - driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); - - // Load the configuration file for the device. - loadConfigurationLocked(device); - - // Figure out the kinds of events the device reports. - ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask); - ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask); - ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask); - ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask); - ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask); - ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask); - ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask); - - // See if this is a keyboard. Ignore everything in the button range except for - // joystick and gamepad buttons which are handled like keyboards for the most part. - bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) - || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), - sizeof_bit_array(KEY_MAX + 1)); - bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), - sizeof_bit_array(BTN_MOUSE)) - || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), - sizeof_bit_array(BTN_DIGI)); - if (haveKeyboardKeys || haveGamepadButtons) { - device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; - } - - // See if this is a cursor device such as a trackball or mouse. - if (test_bit(BTN_MOUSE, device->keyBitmask) - && test_bit(REL_X, device->relBitmask) - && test_bit(REL_Y, device->relBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_CURSOR; - } - - // See if this is a touch pad. - // Is this a new modern multi-touch driver? - if (test_bit(ABS_MT_POSITION_X, device->absBitmask) - && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { - // Some joysticks such as the PS3 controller report axes that conflict - // with the ABS_MT range. Try to confirm that the device really is - // a touch screen. - if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { - device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; - } - // Is this an old style single-touch driver? - } else if (test_bit(BTN_TOUCH, device->keyBitmask) - && test_bit(ABS_X, device->absBitmask) - && test_bit(ABS_Y, device->absBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_TOUCH; - } - - // See if this device is a joystick. - // Assumes that joysticks always have gamepad buttons in order to distinguish them - // from other devices such as accelerometers that also have absolute axes. - if (haveGamepadButtons) { - uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; - for (int i = 0; i <= ABS_MAX; i++) { - if (test_bit(i, device->absBitmask) - && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { - device->classes = assumedClasses; - break; - } - } - } - - // Check whether this device has switches. - for (int i = 0; i <= SW_MAX; i++) { - if (test_bit(i, device->swBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_SWITCH; - break; - } - } - - // Check whether this device supports the vibrator. - if (test_bit(FF_RUMBLE, device->ffBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_VIBRATOR; - } - - // Configure virtual keys. - if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) { - // Load the virtual keys for the touch screen, if any. - // We do this now so that we can make sure to load the keymap if necessary. - status_t status = loadVirtualKeyMapLocked(device); - if (!status) { - device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; - } - } - - // Load the key map. - // We need to do this for joysticks too because the key layout may specify axes. - status_t keyMapStatus = NAME_NOT_FOUND; - if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { - // Load the keymap for the device. - keyMapStatus = loadKeyMapLocked(device); - } - - // Configure the keyboard, gamepad or virtual keyboard. - if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { - // Register the keyboard as a built-in keyboard if it is eligible. - if (!keyMapStatus - && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD - && isEligibleBuiltInKeyboard(device->identifier, - device->configuration, &device->keyMap)) { - mBuiltInKeyboardId = device->id; - } - - // 'Q' key support = cheap test of whether this is an alpha-capable kbd - if (hasKeycodeLocked(device, AKEYCODE_Q)) { - device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; - } - - // See if this device has a DPAD. - if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && - hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && - hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { - device->classes |= INPUT_DEVICE_CLASS_DPAD; - } - - // See if this device has a gamepad. - for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { - if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { - device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; - break; - } - } - - // Disable kernel key repeat since we handle it ourselves - unsigned int repeatRate[] = {0,0}; - if (ioctl(fd, EVIOCSREP, repeatRate)) { - ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno)); - } - } - - // If the device isn't recognized as something we handle, don't monitor it. - if (device->classes == 0) { - ALOGV("Dropping device: id=%d, path='%s', name='%s'", - deviceId, devicePath, device->identifier.name.string()); - delete device; - return -1; - } - - // Determine whether the device is external or internal. - if (isExternalDeviceLocked(device)) { - device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; - } - - if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_GAMEPAD)) { - device->controllerNumber = getNextControllerNumberLocked(device); - } - - // Register with epoll. - struct epoll_event eventItem; - memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = EPOLLIN; - eventItem.data.u32 = deviceId; - if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { - ALOGE("Could not add device fd to epoll instance. errno=%d", errno); - delete device; - return -1; - } - - // Enable wake-lock behavior on kernels that support it. - // TODO: Only need this for devices that can really wake the system. - bool usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1); - - // Tell the kernel that we want to use the monotonic clock for reporting timestamps - // associated with input events. This is important because the input system - // uses the timestamps extensively and assumes they were recorded using the monotonic - // clock. - // - // In older kernel, before Linux 3.4, there was no way to tell the kernel which - // clock to use to input event timestamps. The standard kernel behavior was to - // record a real time timestamp, which isn't what we want. Android kernels therefore - // contained a patch to the evdev_event() function in drivers/input/evdev.c to - // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic - // clock to be used instead of the real time clock. - // - // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock. - // Therefore, we no longer require the Android-specific kernel patch described above - // as long as we make sure to set select the monotonic clock. We do that here. - int clockId = CLOCK_MONOTONIC; - bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); - - ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " - "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, " - "usingSuspendBlockIoctl=%s, usingClockIoctl=%s", - deviceId, fd, devicePath, device->identifier.name.string(), - device->classes, - device->configurationFile.string(), - device->keyMap.keyLayoutFile.string(), - device->keyMap.keyCharacterMapFile.string(), - toString(mBuiltInKeyboardId == deviceId), - toString(usingSuspendBlockIoctl), toString(usingClockIoctl)); - - addDeviceLocked(device); - return 0; -} - -void EventHub::createVirtualKeyboardLocked() { - InputDeviceIdentifier identifier; - identifier.name = "Virtual"; - identifier.uniqueId = "<virtual>"; - setDescriptor(identifier); - - Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8("<virtual>"), identifier); - device->classes = INPUT_DEVICE_CLASS_KEYBOARD - | INPUT_DEVICE_CLASS_ALPHAKEY - | INPUT_DEVICE_CLASS_DPAD - | INPUT_DEVICE_CLASS_VIRTUAL; - loadKeyMapLocked(device); - addDeviceLocked(device); -} - -void EventHub::addDeviceLocked(Device* device) { - mDevices.add(device->id, device); - device->next = mOpeningDevices; - mOpeningDevices = device; -} - -void EventHub::loadConfigurationLocked(Device* device) { - device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( - device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); - if (device->configurationFile.isEmpty()) { - ALOGD("No input device configuration file found for device '%s'.", - device->identifier.name.string()); - } else { - status_t status = PropertyMap::load(device->configurationFile, - &device->configuration); - if (status) { - ALOGE("Error loading input device configuration file for device '%s'. " - "Using default configuration.", - device->identifier.name.string()); - } - } -} - -status_t EventHub::loadVirtualKeyMapLocked(Device* device) { - // The virtual key map is supplied by the kernel as a system board property file. - String8 path; - path.append("/sys/board_properties/virtualkeys."); - path.append(device->identifier.name); - if (access(path.string(), R_OK)) { - return NAME_NOT_FOUND; - } - return VirtualKeyMap::load(path, &device->virtualKeyMap); -} - -status_t EventHub::loadKeyMapLocked(Device* device) { - return device->keyMap.load(device->identifier, device->configuration); -} - -bool EventHub::isExternalDeviceLocked(Device* device) { - if (device->configuration) { - bool value; - if (device->configuration->tryGetProperty(String8("device.internal"), value)) { - return !value; - } - } - return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH; -} - -int32_t EventHub::getNextControllerNumberLocked(Device* device) { - if (mControllerNumbers.isFull()) { - ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s", - device->identifier.name.string()); - return 0; - } - // Since the controller number 0 is reserved for non-controllers, translate all numbers up by - // one - return static_cast<int32_t>(mControllerNumbers.markFirstUnmarkedBit() + 1); -} - -void EventHub::releaseControllerNumberLocked(Device* device) { - int32_t num = device->controllerNumber; - device->controllerNumber= 0; - if (num == 0) { - return; - } - mControllerNumbers.clearBit(static_cast<uint32_t>(num - 1)); -} - - -bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { - if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { - return false; - } - - Vector<int32_t> scanCodes; - device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes); - const size_t N = scanCodes.size(); - for (size_t i=0; i<N && i<=KEY_MAX; i++) { - int32_t sc = scanCodes.itemAt(i); - if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) { - return true; - } - } - - return false; -} - -status_t EventHub::closeDeviceByPathLocked(const char *devicePath) { - Device* device = getDeviceByPathLocked(devicePath); - if (device) { - closeDeviceLocked(device); - return 0; - } - ALOGV("Remove device: %s not found, device may already have been removed.", devicePath); - return -1; -} - -void EventHub::closeAllDevicesLocked() { - while (mDevices.size() > 0) { - closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1)); - } -} - -void EventHub::closeDeviceLocked(Device* device) { - ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n", - device->path.string(), device->identifier.name.string(), device->id, - device->fd, device->classes); - - if (device->id == mBuiltInKeyboardId) { - ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", - device->path.string(), mBuiltInKeyboardId); - mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD; - } - - if (!device->isVirtual()) { - if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) { - ALOGW("Could not remove device fd from epoll instance. errno=%d", errno); - } - } - - releaseControllerNumberLocked(device); - - mDevices.removeItem(device->id); - device->close(); - - // Unlink for opening devices list if it is present. - Device* pred = NULL; - bool found = false; - for (Device* entry = mOpeningDevices; entry != NULL; ) { - if (entry == device) { - found = true; - break; - } - pred = entry; - entry = entry->next; - } - if (found) { - // Unlink the device from the opening devices list then delete it. - // We don't need to tell the client that the device was closed because - // it does not even know it was opened in the first place. - ALOGI("Device %s was immediately closed after opening.", device->path.string()); - if (pred) { - pred->next = device->next; - } else { - mOpeningDevices = device->next; - } - delete device; - } else { - // Link into closing devices list. - // The device will be deleted later after we have informed the client. - device->next = mClosingDevices; - mClosingDevices = device; - } -} - -status_t EventHub::readNotifyLocked() { - int res; - char devname[PATH_MAX]; - char *filename; - char event_buf[512]; - int event_size; - int event_pos = 0; - struct inotify_event *event; - - ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd); - res = read(mINotifyFd, event_buf, sizeof(event_buf)); - if(res < (int)sizeof(*event)) { - if(errno == EINTR) - return 0; - ALOGW("could not get event, %s\n", strerror(errno)); - return -1; - } - //printf("got %d bytes of event information\n", res); - - strcpy(devname, DEVICE_PATH); - filename = devname + strlen(devname); - *filename++ = '/'; - - while(res >= (int)sizeof(*event)) { - event = (struct inotify_event *)(event_buf + event_pos); - //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); - if(event->len) { - strcpy(filename, event->name); - if(event->mask & IN_CREATE) { - openDeviceLocked(devname); - } else { - ALOGI("Removing device '%s' due to inotify event\n", devname); - closeDeviceByPathLocked(devname); - } - } - event_size = sizeof(*event) + event->len; - res -= event_size; - event_pos += event_size; - } - return 0; -} - -status_t EventHub::scanDirLocked(const char *dirname) -{ - char devname[PATH_MAX]; - char *filename; - DIR *dir; - struct dirent *de; - dir = opendir(dirname); - if(dir == NULL) - return -1; - strcpy(devname, dirname); - filename = devname + strlen(devname); - *filename++ = '/'; - while((de = readdir(dir))) { - if(de->d_name[0] == '.' && - (de->d_name[1] == '\0' || - (de->d_name[1] == '.' && de->d_name[2] == '\0'))) - continue; - strcpy(filename, de->d_name); - openDeviceLocked(devname); - } - closedir(dir); - return 0; -} - -void EventHub::requestReopenDevices() { - ALOGV("requestReopenDevices() called"); - - AutoMutex _l(mLock); - mNeedToReopenDevices = true; -} - -void EventHub::dump(String8& dump) { - dump.append("Event Hub State:\n"); - - { // acquire lock - AutoMutex _l(mLock); - - dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId); - - dump.append(INDENT "Devices:\n"); - - for (size_t i = 0; i < mDevices.size(); i++) { - const Device* device = mDevices.valueAt(i); - if (mBuiltInKeyboardId == device->id) { - dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", - device->id, device->identifier.name.string()); - } else { - dump.appendFormat(INDENT2 "%d: %s\n", device->id, - device->identifier.name.string()); - } - dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); - dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); - dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string()); - dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string()); - dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber); - dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string()); - dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " - "product=0x%04x, version=0x%04x\n", - device->identifier.bus, device->identifier.vendor, - device->identifier.product, device->identifier.version); - dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", - device->keyMap.keyLayoutFile.string()); - dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n", - device->keyMap.keyCharacterMapFile.string()); - dump.appendFormat(INDENT3 "ConfigurationFile: %s\n", - device->configurationFile.string()); - dump.appendFormat(INDENT3 "HaveKeyboardLayoutOverlay: %s\n", - toString(device->overlayKeyMap != NULL)); - } - } // release lock -} - -void EventHub::monitor() { - // Acquire and release the lock to ensure that the event hub has not deadlocked. - mLock.lock(); - mLock.unlock(); -} - - -}; // namespace android diff --git a/services/input/EventHub.h b/services/input/EventHub.h deleted file mode 100644 index ae28f01..0000000 --- a/services/input/EventHub.h +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (C) 2005 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -#ifndef _RUNTIME_EVENT_HUB_H -#define _RUNTIME_EVENT_HUB_H - -#include <input/Input.h> -#include <input/InputDevice.h> -#include <input/Keyboard.h> -#include <input/KeyLayoutMap.h> -#include <input/KeyCharacterMap.h> -#include <input/VirtualKeyMap.h> -#include <utils/String8.h> -#include <utils/threads.h> -#include <utils/Log.h> -#include <utils/threads.h> -#include <utils/List.h> -#include <utils/Errors.h> -#include <utils/PropertyMap.h> -#include <utils/Vector.h> -#include <utils/KeyedVector.h> -#include <utils/BitSet.h> - -#include <linux/input.h> -#include <sys/epoll.h> - -/* Convenience constants. */ - -#define BTN_FIRST 0x100 // first button code -#define BTN_LAST 0x15f // last button code - -/* - * These constants are used privately in Android to pass raw timestamps - * through evdev from uinput device drivers because there is currently no - * other way to transfer this information. The evdev driver automatically - * timestamps all input events with the time they were posted and clobbers - * whatever information was passed in. - * - * For the purposes of this hack, the timestamp is specified in the - * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying - * seconds and microseconds. - */ -#define MSC_ANDROID_TIME_SEC 0x6 -#define MSC_ANDROID_TIME_USEC 0x7 - -namespace android { - -enum { - // Device id of a special "virtual" keyboard that is always present. - VIRTUAL_KEYBOARD_ID = -1, - // Device id of the "built-in" keyboard if there is one. - BUILT_IN_KEYBOARD_ID = 0, -}; - -/* - * A raw event as retrieved from the EventHub. - */ -struct RawEvent { - nsecs_t when; - int32_t deviceId; - int32_t type; - int32_t code; - int32_t value; -}; - -/* Describes an absolute axis. */ -struct RawAbsoluteAxisInfo { - bool valid; // true if the information is valid, false otherwise - - int32_t minValue; // minimum value - int32_t maxValue; // maximum value - int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 - int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise - int32_t resolution; // resolution in units per mm or radians per mm - - inline void clear() { - valid = false; - minValue = 0; - maxValue = 0; - flat = 0; - fuzz = 0; - resolution = 0; - } -}; - -/* - * Input device classes. - */ -enum { - /* The input device is a keyboard or has buttons. */ - INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, - - /* The input device is an alpha-numeric keyboard (not just a dial pad). */ - INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, - - /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */ - INPUT_DEVICE_CLASS_TOUCH = 0x00000004, - - /* The input device is a cursor device such as a trackball or mouse. */ - INPUT_DEVICE_CLASS_CURSOR = 0x00000008, - - /* The input device is a multi-touch touchscreen. */ - INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, - - /* The input device is a directional pad (implies keyboard, has DPAD keys). */ - INPUT_DEVICE_CLASS_DPAD = 0x00000020, - - /* The input device is a gamepad (implies keyboard, has BUTTON keys). */ - INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, - - /* The input device has switches. */ - INPUT_DEVICE_CLASS_SWITCH = 0x00000080, - - /* The input device is a joystick (implies gamepad, has joystick absolute axes). */ - INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, - - /* The input device has a vibrator (supports FF_RUMBLE). */ - INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, - - /* The input device is virtual (not a real device, not part of UI configuration). */ - INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, - - /* The input device is external (not built-in). */ - INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, -}; - -/* - * Gets the class that owns an axis, in cases where multiple classes might claim - * the same axis for different purposes. - */ -extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses); - -/* - * Grand Central Station for events. - * - * The event hub aggregates input events received across all known input - * devices on the system, including devices that may be emulated by the simulator - * environment. In addition, the event hub generates fake input events to indicate - * when devices are added or removed. - * - * The event hub provides a stream of input events (via the getEvent function). - * It also supports querying the current actual state of input devices such as identifying - * which keys are currently down. Finally, the event hub keeps track of the capabilities of - * individual input devices, such as their class and the set of key codes that they support. - */ -class EventHubInterface : public virtual RefBase { -protected: - EventHubInterface() { } - virtual ~EventHubInterface() { } - -public: - // Synthetic raw event type codes produced when devices are added or removed. - enum { - // Sent when a device is added. - DEVICE_ADDED = 0x10000000, - // Sent when a device is removed. - DEVICE_REMOVED = 0x20000000, - // Sent when all added/removed devices from the most recent scan have been reported. - // This event is always sent at least once. - FINISHED_DEVICE_SCAN = 0x30000000, - - FIRST_SYNTHETIC_EVENT = DEVICE_ADDED, - }; - - virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; - - virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0; - - virtual int32_t getDeviceControllerNumber(int32_t deviceId) const = 0; - - virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0; - - virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const = 0; - - virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0; - - virtual bool hasInputProperty(int32_t deviceId, int property) const = 0; - - virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t* outKeycode, uint32_t* outFlags) const = 0; - - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, - AxisInfo* outAxisInfo) const = 0; - - // Sets devices that are excluded from opening. - // This can be used to ignore input devices for sensors. - virtual void setExcludedDevices(const Vector<String8>& devices) = 0; - - /* - * Wait for events to become available and returns them. - * After returning, the EventHub holds onto a wake lock until the next call to getEvent. - * This ensures that the device will not go to sleep while the event is being processed. - * If the device needs to remain awake longer than that, then the caller is responsible - * for taking care of it (say, by poking the power manager user activity timer). - * - * The timeout is advisory only. If the device is asleep, it will not wake just to - * service the timeout. - * - * Returns the number of events obtained, or 0 if the timeout expired. - */ - virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0; - - /* - * Query current input state. - */ - virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0; - virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; - virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; - virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, - int32_t* outValue) const = 0; - - /* - * Examine key input devices for specific framework keycode support - */ - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags) const = 0; - - virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0; - virtual bool hasLed(int32_t deviceId, int32_t led) const = 0; - virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0; - - virtual void getVirtualKeyDefinitions(int32_t deviceId, - Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0; - - virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0; - virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0; - - /* Control the vibrator. */ - virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0; - virtual void cancelVibrate(int32_t deviceId) = 0; - - /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */ - virtual void requestReopenDevices() = 0; - - /* Wakes up getEvents() if it is blocked on a read. */ - virtual void wake() = 0; - - /* Dump EventHub state to a string. */ - virtual void dump(String8& dump) = 0; - - /* Called by the heatbeat to ensures that the reader has not deadlocked. */ - virtual void monitor() = 0; -}; - -class EventHub : public EventHubInterface -{ -public: - EventHub(); - - virtual uint32_t getDeviceClasses(int32_t deviceId) const; - - virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const; - - virtual int32_t getDeviceControllerNumber(int32_t deviceId) const; - - virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const; - - virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const; - - virtual bool hasRelativeAxis(int32_t deviceId, int axis) const; - - virtual bool hasInputProperty(int32_t deviceId, int property) const; - - virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t* outKeycode, uint32_t* outFlags) const; - - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, - AxisInfo* outAxisInfo) const; - - virtual void setExcludedDevices(const Vector<String8>& devices); - - virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const; - virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const; - virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const; - virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const; - - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) const; - - virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize); - - virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const; - virtual bool hasLed(int32_t deviceId, int32_t led) const; - virtual void setLedState(int32_t deviceId, int32_t led, bool on); - - virtual void getVirtualKeyDefinitions(int32_t deviceId, - Vector<VirtualKeyDefinition>& outVirtualKeys) const; - - virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const; - virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map); - - virtual void vibrate(int32_t deviceId, nsecs_t duration); - virtual void cancelVibrate(int32_t deviceId); - - virtual void requestReopenDevices(); - - virtual void wake(); - - virtual void dump(String8& dump); - virtual void monitor(); - -protected: - virtual ~EventHub(); - -private: - struct Device { - Device* next; - - int fd; // may be -1 if device is virtual - const int32_t id; - const String8 path; - const InputDeviceIdentifier identifier; - - uint32_t classes; - - uint8_t keyBitmask[(KEY_MAX + 1) / 8]; - uint8_t absBitmask[(ABS_MAX + 1) / 8]; - uint8_t relBitmask[(REL_MAX + 1) / 8]; - uint8_t swBitmask[(SW_MAX + 1) / 8]; - uint8_t ledBitmask[(LED_MAX + 1) / 8]; - uint8_t ffBitmask[(FF_MAX + 1) / 8]; - uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8]; - - String8 configurationFile; - PropertyMap* configuration; - VirtualKeyMap* virtualKeyMap; - KeyMap keyMap; - - sp<KeyCharacterMap> overlayKeyMap; - sp<KeyCharacterMap> combinedKeyMap; - - bool ffEffectPlaying; - int16_t ffEffectId; // initially -1 - - int32_t controllerNumber; - - int32_t timestampOverrideSec; - int32_t timestampOverrideUsec; - - Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier); - ~Device(); - - void close(); - - inline bool isVirtual() const { return fd < 0; } - - const sp<KeyCharacterMap>& getKeyCharacterMap() const { - if (combinedKeyMap != NULL) { - return combinedKeyMap; - } - return keyMap.keyCharacterMap; - } - }; - - status_t openDeviceLocked(const char *devicePath); - void createVirtualKeyboardLocked(); - void addDeviceLocked(Device* device); - - status_t closeDeviceByPathLocked(const char *devicePath); - void closeDeviceLocked(Device* device); - void closeAllDevicesLocked(); - - status_t scanDirLocked(const char *dirname); - void scanDevicesLocked(); - status_t readNotifyLocked(); - - Device* getDeviceLocked(int32_t deviceId) const; - Device* getDeviceByPathLocked(const char* devicePath) const; - - bool hasKeycodeLocked(Device* device, int keycode) const; - - void loadConfigurationLocked(Device* device); - status_t loadVirtualKeyMapLocked(Device* device); - status_t loadKeyMapLocked(Device* device); - - bool isExternalDeviceLocked(Device* device); - - int32_t getNextControllerNumberLocked(Device* device); - void releaseControllerNumberLocked(Device* device); - - // Protect all internal state. - mutable Mutex mLock; - - // The actual id of the built-in keyboard, or NO_BUILT_IN_KEYBOARD if none. - // EventHub remaps the built-in keyboard to id 0 externally as required by the API. - enum { - // Must not conflict with any other assigned device ids, including - // the virtual keyboard id (-1). - NO_BUILT_IN_KEYBOARD = -2, - }; - int32_t mBuiltInKeyboardId; - - int32_t mNextDeviceId; - - BitSet32 mControllerNumbers; - - KeyedVector<int32_t, Device*> mDevices; - - Device *mOpeningDevices; - Device *mClosingDevices; - - bool mNeedToSendFinishedDeviceScan; - bool mNeedToReopenDevices; - bool mNeedToScanDevices; - Vector<String8> mExcludedDevices; - - int mEpollFd; - int mINotifyFd; - int mWakeReadPipeFd; - int mWakeWritePipeFd; - - // Ids used for epoll notifications not associated with devices. - static const uint32_t EPOLL_ID_INOTIFY = 0x80000001; - static const uint32_t EPOLL_ID_WAKE = 0x80000002; - - // Epoll FD list size hint. - static const int EPOLL_SIZE_HINT = 8; - - // Maximum number of signalled FDs to handle at a time. - static const int EPOLL_MAX_EVENTS = 16; - - // The array of pending epoll events and the index of the next event to be handled. - struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS]; - size_t mPendingEventCount; - size_t mPendingEventIndex; - bool mPendingINotify; -}; - -}; // namespace android - -#endif // _RUNTIME_EVENT_HUB_H diff --git a/services/input/InputApplication.cpp b/services/input/InputApplication.cpp deleted file mode 100644 index a99e637..0000000 --- a/services/input/InputApplication.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "InputApplication" - -#include "InputApplication.h" - -#include <cutils/log.h> - -namespace android { - -// --- InputApplicationHandle --- - -InputApplicationHandle::InputApplicationHandle() : - mInfo(NULL) { -} - -InputApplicationHandle::~InputApplicationHandle() { - delete mInfo; -} - -void InputApplicationHandle::releaseInfo() { - if (mInfo) { - delete mInfo; - mInfo = NULL; - } -} - -} // namespace android diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h deleted file mode 100644 index 1f5504c..0000000 --- a/services/input/InputApplication.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_APPLICATION_H -#define _UI_INPUT_APPLICATION_H - -#include <input/Input.h> - -#include <utils/RefBase.h> -#include <utils/Timers.h> -#include <utils/String8.h> - -namespace android { - -/* - * Describes the properties of an application that can receive input. - */ -struct InputApplicationInfo { - String8 name; - nsecs_t dispatchingTimeout; -}; - - -/* - * Handle for an application that can receive input. - * - * Used by the native input dispatcher as a handle for the window manager objects - * that describe an application. - */ -class InputApplicationHandle : public RefBase { -public: - inline const InputApplicationInfo* getInfo() const { - return mInfo; - } - - inline String8 getName() const { - return mInfo ? mInfo->name : String8("<invalid>"); - } - - inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { - return mInfo ? mInfo->dispatchingTimeout : defaultValue; - } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() = 0; - - /** - * Releases the storage used by the associated information when it is - * no longer needed. - */ - void releaseInfo(); - -protected: - InputApplicationHandle(); - virtual ~InputApplicationHandle(); - - InputApplicationInfo* mInfo; -}; - -} // namespace android - -#endif // _UI_INPUT_APPLICATION_H diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp deleted file mode 100644 index 10a639e..0000000 --- a/services/input/InputDispatcher.cpp +++ /dev/null @@ -1,4470 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "InputDispatcher" -#define ATRACE_TAG ATRACE_TAG_INPUT - -//#define LOG_NDEBUG 0 - -// Log detailed debug messages about each inbound event notification to the dispatcher. -#define DEBUG_INBOUND_EVENT_DETAILS 0 - -// Log detailed debug messages about each outbound event processed by the dispatcher. -#define DEBUG_OUTBOUND_EVENT_DETAILS 0 - -// Log debug messages about the dispatch cycle. -#define DEBUG_DISPATCH_CYCLE 0 - -// Log debug messages about registrations. -#define DEBUG_REGISTRATION 0 - -// Log debug messages about input event injection. -#define DEBUG_INJECTION 0 - -// Log debug messages about input focus tracking. -#define DEBUG_FOCUS 0 - -// Log debug messages about the app switch latency optimization. -#define DEBUG_APP_SWITCH 0 - -// Log debug messages about hover events. -#define DEBUG_HOVER 0 - -#include "InputDispatcher.h" - -#include <utils/Trace.h> -#include <cutils/log.h> -#include <androidfw/PowerManager.h> - -#include <stddef.h> -#include <unistd.h> -#include <errno.h> -#include <limits.h> -#include <time.h> - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " -#define INDENT4 " " - -namespace android { - -// Default input dispatching timeout if there is no focused application or paused window -// from which to determine an appropriate dispatching timeout. -const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec - -// Amount of time to allow for all pending events to be processed when an app switch -// key is on the way. This is used to preempt input dispatch and drop input events -// when an application takes too long to respond and the user has pressed an app switch key. -const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec - -// Amount of time to allow for an event to be dispatched (measured since its eventTime) -// before considering it stale and dropping it. -const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec - -// Amount of time to allow touch events to be streamed out to a connection before requiring -// that the first event be finished. This value extends the ANR timeout by the specified -// amount. For example, if streaming is allowed to get ahead by one second relative to the -// queue of waiting unfinished events, then ANRs will similarly be delayed by one second. -const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec - -// Log a warning when an event takes longer than this to process, even if an ANR does not occur. -const nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec - -// Number of recent events to keep for debugging purposes. -const size_t RECENT_QUEUE_MAX_SIZE = 10; - -static inline nsecs_t now() { - return systemTime(SYSTEM_TIME_MONOTONIC); -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static inline int32_t getMotionEventActionPointerIndex(int32_t action) { - return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; -} - -static bool isValidKeyAction(int32_t action) { - switch (action) { - case AKEY_EVENT_ACTION_DOWN: - case AKEY_EVENT_ACTION_UP: - return true; - default: - return false; - } -} - -static bool validateKeyEvent(int32_t action) { - if (! isValidKeyAction(action)) { - ALOGE("Key event has invalid action code 0x%x", action); - return false; - } - return true; -} - -static bool isValidMotionAction(int32_t action, size_t pointerCount) { - switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_OUTSIDE: - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: - case AMOTION_EVENT_ACTION_HOVER_EXIT: - case AMOTION_EVENT_ACTION_SCROLL: - return true; - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: { - int32_t index = getMotionEventActionPointerIndex(action); - return index >= 0 && size_t(index) < pointerCount; - } - default: - return false; - } -} - -static bool validateMotionEvent(int32_t action, size_t pointerCount, - const PointerProperties* pointerProperties) { - if (! isValidMotionAction(action, pointerCount)) { - ALOGE("Motion event has invalid action code 0x%x", action); - return false; - } - if (pointerCount < 1 || pointerCount > MAX_POINTERS) { - ALOGE("Motion event has invalid pointer count %d; value must be between 1 and %d.", - pointerCount, MAX_POINTERS); - return false; - } - BitSet32 pointerIdBits; - for (size_t i = 0; i < pointerCount; i++) { - int32_t id = pointerProperties[i].id; - if (id < 0 || id > MAX_POINTER_ID) { - ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", - id, MAX_POINTER_ID); - return false; - } - if (pointerIdBits.hasBit(id)) { - ALOGE("Motion event has duplicate pointer id %d", id); - return false; - } - pointerIdBits.markBit(id); - } - return true; -} - -static bool isMainDisplay(int32_t displayId) { - return displayId == ADISPLAY_ID_DEFAULT || displayId == ADISPLAY_ID_NONE; -} - -static void dumpRegion(String8& dump, const SkRegion& region) { - if (region.isEmpty()) { - dump.append("<empty>"); - return; - } - - bool first = true; - for (SkRegion::Iterator it(region); !it.done(); it.next()) { - if (first) { - first = false; - } else { - dump.append("|"); - } - const SkIRect& rect = it.rect(); - dump.appendFormat("[%d,%d][%d,%d]", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); - } -} - - -// --- InputDispatcher --- - -InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : - mPolicy(policy), - mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), - mNextUnblockedEvent(NULL), - mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { - mLooper = new Looper(false); - - mKeyRepeatState.lastKeyEntry = NULL; - - policy->getDispatcherConfiguration(&mConfig); -} - -InputDispatcher::~InputDispatcher() { - { // acquire lock - AutoMutex _l(mLock); - - resetKeyRepeatLocked(); - releasePendingEventLocked(); - drainInboundQueueLocked(); - } - - while (mConnectionsByFd.size() != 0) { - unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel); - } -} - -void InputDispatcher::dispatchOnce() { - nsecs_t nextWakeupTime = LONG_LONG_MAX; - { // acquire lock - AutoMutex _l(mLock); - mDispatcherIsAliveCondition.broadcast(); - - // Run a dispatch loop if there are no pending commands. - // The dispatch loop might enqueue commands to run afterwards. - if (!haveCommandsLocked()) { - dispatchOnceInnerLocked(&nextWakeupTime); - } - - // Run all pending commands if there are any. - // If any commands were run then force the next poll to wake up immediately. - if (runCommandsLockedInterruptible()) { - nextWakeupTime = LONG_LONG_MIN; - } - } // release lock - - // Wait for callback or timeout or wake. (make sure we round up, not down) - nsecs_t currentTime = now(); - int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); - mLooper->pollOnce(timeoutMillis); -} - -void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { - nsecs_t currentTime = now(); - - // Reset the key repeat timer whenever we disallow key events, even if the next event - // is not a key. This is to ensure that we abort a key repeat if the device is just coming - // out of sleep. - if (!mPolicy->isKeyRepeatEnabled()) { - resetKeyRepeatLocked(); - } - - // If dispatching is frozen, do not process timeouts or try to deliver any new events. - if (mDispatchFrozen) { -#if DEBUG_FOCUS - ALOGD("Dispatch frozen. Waiting some more."); -#endif - return; - } - - // Optimize latency of app switches. - // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has - // been pressed. When it expires, we preempt dispatch and drop all other pending events. - bool isAppSwitchDue = mAppSwitchDueTime <= currentTime; - if (mAppSwitchDueTime < *nextWakeupTime) { - *nextWakeupTime = mAppSwitchDueTime; - } - - // Ready to start a new event. - // If we don't already have a pending event, go grab one. - if (! mPendingEvent) { - if (mInboundQueue.isEmpty()) { - if (isAppSwitchDue) { - // The inbound queue is empty so the app switch key we were waiting - // for will never arrive. Stop waiting for it. - resetPendingAppSwitchLocked(false); - isAppSwitchDue = false; - } - - // Synthesize a key repeat if appropriate. - if (mKeyRepeatState.lastKeyEntry) { - if (currentTime >= mKeyRepeatState.nextRepeatTime) { - mPendingEvent = synthesizeKeyRepeatLocked(currentTime); - } else { - if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { - *nextWakeupTime = mKeyRepeatState.nextRepeatTime; - } - } - } - - // Nothing to do if there is no pending event. - if (!mPendingEvent) { - return; - } - } else { - // Inbound queue has at least one entry. - mPendingEvent = mInboundQueue.dequeueAtHead(); - traceInboundQueueLengthLocked(); - } - - // Poke user activity for this event. - if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { - pokeUserActivityLocked(mPendingEvent); - } - - // Get ready to dispatch the event. - resetANRTimeoutsLocked(); - } - - // Now we have an event to dispatch. - // All events are eventually dequeued and processed this way, even if we intend to drop them. - ALOG_ASSERT(mPendingEvent != NULL); - bool done = false; - DropReason dropReason = DROP_REASON_NOT_DROPPED; - if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { - dropReason = DROP_REASON_POLICY; - } else if (!mDispatchEnabled) { - dropReason = DROP_REASON_DISABLED; - } - - if (mNextUnblockedEvent == mPendingEvent) { - mNextUnblockedEvent = NULL; - } - - switch (mPendingEvent->type) { - case EventEntry::TYPE_CONFIGURATION_CHANGED: { - ConfigurationChangedEntry* typedEntry = - static_cast<ConfigurationChangedEntry*>(mPendingEvent); - done = dispatchConfigurationChangedLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped - break; - } - - case EventEntry::TYPE_DEVICE_RESET: { - DeviceResetEntry* typedEntry = - static_cast<DeviceResetEntry*>(mPendingEvent); - done = dispatchDeviceResetLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped - break; - } - - case EventEntry::TYPE_KEY: { - KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); - if (isAppSwitchDue) { - if (isAppSwitchKeyEventLocked(typedEntry)) { - resetPendingAppSwitchLocked(true); - isAppSwitchDue = false; - } else if (dropReason == DROP_REASON_NOT_DROPPED) { - dropReason = DROP_REASON_APP_SWITCH; - } - } - if (dropReason == DROP_REASON_NOT_DROPPED - && isStaleEventLocked(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; - } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; - } - done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); - if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { - dropReason = DROP_REASON_APP_SWITCH; - } - if (dropReason == DROP_REASON_NOT_DROPPED - && isStaleEventLocked(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; - } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; - } - done = dispatchMotionLocked(currentTime, typedEntry, - &dropReason, nextWakeupTime); - break; - } - - default: - ALOG_ASSERT(false); - break; - } - - if (done) { - if (dropReason != DROP_REASON_NOT_DROPPED) { - dropInboundEventLocked(mPendingEvent, dropReason); - } - - releasePendingEventLocked(); - *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately - } -} - -bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { - bool needWake = mInboundQueue.isEmpty(); - mInboundQueue.enqueueAtTail(entry); - traceInboundQueueLengthLocked(); - - switch (entry->type) { - case EventEntry::TYPE_KEY: { - // Optimize app switch latency. - // If the application takes too long to catch up then we drop all events preceding - // the app switch key. - KeyEntry* keyEntry = static_cast<KeyEntry*>(entry); - if (isAppSwitchKeyEventLocked(keyEntry)) { - if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { - mAppSwitchSawKeyDown = true; - } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - if (mAppSwitchSawKeyDown) { -#if DEBUG_APP_SWITCH - ALOGD("App switch is pending!"); -#endif - mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; - mAppSwitchSawKeyDown = false; - needWake = true; - } - } - } - break; - } - - case EventEntry::TYPE_MOTION: { - // Optimize case where the current application is unresponsive and the user - // decides to touch a window in a different application. - // If the application takes too long to catch up then we drop all events preceding - // the touch into the other window. - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN - && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) - && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY - && mInputTargetWaitApplicationHandle != NULL) { - int32_t displayId = motionEntry->displayId; - int32_t x = int32_t(motionEntry->pointerCoords[0]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(motionEntry->pointerCoords[0]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); - if (touchedWindowHandle != NULL - && touchedWindowHandle->inputApplicationHandle - != mInputTargetWaitApplicationHandle) { - // User touched a different application than the one we are waiting on. - // Flag the event, and start pruning the input queue. - mNextUnblockedEvent = motionEntry; - needWake = true; - } - } - break; - } - } - - return needWake; -} - -void InputDispatcher::addRecentEventLocked(EventEntry* entry) { - entry->refCount += 1; - mRecentQueue.enqueueAtTail(entry); - if (mRecentQueue.count() > RECENT_QUEUE_MAX_SIZE) { - mRecentQueue.dequeueAtHead()->release(); - } -} - -sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, - int32_t x, int32_t y) { - // Traverse windows from front to back to find touched window. - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - if (windowInfo->displayId == displayId) { - int32_t flags = windowInfo->layoutParamsFlags; - int32_t privateFlags = windowInfo->layoutParamsPrivateFlags; - - if (windowInfo->visible) { - if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { - bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE - | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { - // Found window. - return windowHandle; - } - } - } - - if (privateFlags & InputWindowInfo::PRIVATE_FLAG_SYSTEM_ERROR) { - // Error window is on top but not visible, so touch is dropped. - return NULL; - } - } - } - return NULL; -} - -void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { - const char* reason; - switch (dropReason) { - case DROP_REASON_POLICY: -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("Dropped event because policy consumed it."); -#endif - reason = "inbound event was dropped because the policy consumed it"; - break; - case DROP_REASON_DISABLED: - ALOGI("Dropped event because input dispatch is disabled."); - reason = "inbound event was dropped because input dispatch is disabled"; - break; - case DROP_REASON_APP_SWITCH: - ALOGI("Dropped event because of pending overdue app switch."); - reason = "inbound event was dropped because of pending overdue app switch"; - break; - case DROP_REASON_BLOCKED: - ALOGI("Dropped event because the current application is not responding and the user " - "has started interacting with a different application."); - reason = "inbound event was dropped because the current application is not responding " - "and the user has started interacting with a different application"; - break; - case DROP_REASON_STALE: - ALOGI("Dropped event because it is stale."); - reason = "inbound event was dropped because it is stale"; - break; - default: - ALOG_ASSERT(false); - return; - } - - switch (entry->type) { - case EventEntry::TYPE_KEY: { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - break; - } - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } else { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } - break; - } - } -} - -bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) { - return keyCode == AKEYCODE_HOME - || keyCode == AKEYCODE_ENDCALL - || keyCode == AKEYCODE_APP_SWITCH; -} - -bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) { - return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) - && isAppSwitchKeyCode(keyEntry->keyCode) - && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) - && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); -} - -bool InputDispatcher::isAppSwitchPendingLocked() { - return mAppSwitchDueTime != LONG_LONG_MAX; -} - -void InputDispatcher::resetPendingAppSwitchLocked(bool handled) { - mAppSwitchDueTime = LONG_LONG_MAX; - -#if DEBUG_APP_SWITCH - if (handled) { - ALOGD("App switch has arrived."); - } else { - ALOGD("App switch was abandoned."); - } -#endif -} - -bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) { - return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT; -} - -bool InputDispatcher::haveCommandsLocked() const { - return !mCommandQueue.isEmpty(); -} - -bool InputDispatcher::runCommandsLockedInterruptible() { - if (mCommandQueue.isEmpty()) { - return false; - } - - do { - CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); - - Command command = commandEntry->command; - (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' - - commandEntry->connection.clear(); - delete commandEntry; - } while (! mCommandQueue.isEmpty()); - return true; -} - -InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { - CommandEntry* commandEntry = new CommandEntry(command); - mCommandQueue.enqueueAtTail(commandEntry); - return commandEntry; -} - -void InputDispatcher::drainInboundQueueLocked() { - while (! mInboundQueue.isEmpty()) { - EventEntry* entry = mInboundQueue.dequeueAtHead(); - releaseInboundEventLocked(entry); - } - traceInboundQueueLengthLocked(); -} - -void InputDispatcher::releasePendingEventLocked() { - if (mPendingEvent) { - resetANRTimeoutsLocked(); - releaseInboundEventLocked(mPendingEvent); - mPendingEvent = NULL; - } -} - -void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState && injectionState->injectionResult == INPUT_EVENT_INJECTION_PENDING) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("Injected inbound event was dropped."); -#endif - setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED); - } - if (entry == mNextUnblockedEvent) { - mNextUnblockedEvent = NULL; - } - addRecentEventLocked(entry); - entry->release(); -} - -void InputDispatcher::resetKeyRepeatLocked() { - if (mKeyRepeatState.lastKeyEntry) { - mKeyRepeatState.lastKeyEntry->release(); - mKeyRepeatState.lastKeyEntry = NULL; - } -} - -InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { - KeyEntry* entry = mKeyRepeatState.lastKeyEntry; - - // Reuse the repeated key entry if it is otherwise unreferenced. - uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK) - | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED; - if (entry->refCount == 1) { - entry->recycle(); - entry->eventTime = currentTime; - entry->policyFlags = policyFlags; - entry->repeatCount += 1; - } else { - KeyEntry* newEntry = new KeyEntry(currentTime, - entry->deviceId, entry->source, policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, - entry->metaState, entry->repeatCount + 1, entry->downTime); - - mKeyRepeatState.lastKeyEntry = newEntry; - entry->release(); - - entry = newEntry; - } - entry->syntheticRepeat = true; - - // Increment reference count since we keep a reference to the event in - // mKeyRepeatState.lastKeyEntry in addition to the one we return. - entry->refCount += 1; - - mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay; - return entry; -} - -bool InputDispatcher::dispatchConfigurationChangedLocked( - nsecs_t currentTime, ConfigurationChangedEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime); -#endif - - // Reset key repeating in case a keyboard device was added or removed or something. - resetKeyRepeatLocked(); - - // Enqueue a command to run outside the lock to tell the policy that the configuration changed. - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyConfigurationChangedInterruptible); - commandEntry->eventTime = entry->eventTime; - return true; -} - -bool InputDispatcher::dispatchDeviceResetLocked( - nsecs_t currentTime, DeviceResetEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId); -#endif - - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "device was reset"); - options.deviceId = entry->deviceId; - synthesizeCancelationEventsForAllConnectionsLocked(options); - return true; -} - -bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime) { - // Preprocessing. - if (! entry->dispatchInProgress) { - if (entry->repeatCount == 0 - && entry->action == AKEY_EVENT_ACTION_DOWN - && (entry->policyFlags & POLICY_FLAG_TRUSTED) - && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { - if (mKeyRepeatState.lastKeyEntry - && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { - // We have seen two identical key downs in a row which indicates that the device - // driver is automatically generating key repeats itself. We take note of the - // repeat here, but we disable our own next key repeat timer since it is clear that - // we will not need to synthesize key repeats ourselves. - entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1; - resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves - } else { - // Not a repeat. Save key down state in case we do see a repeat later. - resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout; - } - mKeyRepeatState.lastKeyEntry = entry; - entry->refCount += 1; - } else if (! entry->syntheticRepeat) { - resetKeyRepeatLocked(); - } - - if (entry->repeatCount == 1) { - entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS; - } else { - entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS; - } - - entry->dispatchInProgress = true; - - logOutboundKeyDetailsLocked("dispatchKey - ", entry); - } - - // Handle case where the policy asked us to try again later last time. - if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) { - if (currentTime < entry->interceptKeyWakeupTime) { - if (entry->interceptKeyWakeupTime < *nextWakeupTime) { - *nextWakeupTime = entry->interceptKeyWakeupTime; - } - return false; // wait until next wakeup - } - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; - entry->interceptKeyWakeupTime = 0; - } - - // Give the policy a chance to intercept the key. - if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { - if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); - if (mFocusedWindowHandle != NULL) { - commandEntry->inputWindowHandle = mFocusedWindowHandle; - } - commandEntry->keyEntry = entry; - entry->refCount += 1; - return false; // wait for the command to run - } else { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; - } - } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { - if (*dropReason == DROP_REASON_NOT_DROPPED) { - *dropReason = DROP_REASON_POLICY; - } - } - - // Clean up if dropping the event. - if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); - return true; - } - - // Identify targets. - Vector<InputTarget> inputTargets; - int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime); - if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { - return false; - } - - setInjectionResultLocked(entry, injectionResult); - if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { - return true; - } - - addMonitoringTargetsLocked(inputTargets); - - // Dispatch the key. - dispatchEventLocked(currentTime, entry, inputTargets); - return true; -} - -void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, " - "repeatCount=%d, downTime=%lld", - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, - entry->repeatCount, entry->downTime); -#endif -} - -bool InputDispatcher::dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { - // Preprocessing. - if (! entry->dispatchInProgress) { - entry->dispatchInProgress = true; - - logOutboundMotionDetailsLocked("dispatchMotion - ", entry); - } - - // Clean up if dropping the event. - if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); - return true; - } - - bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; - - // Identify targets. - Vector<InputTarget> inputTargets; - - bool conflictingPointerActions = false; - int32_t injectionResult; - if (isPointerEvent) { - // Pointer event. (eg. touchscreen) - injectionResult = findTouchedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime, &conflictingPointerActions); - } else { - // Non touch event. (eg. trackball) - injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime); - } - if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { - return false; - } - - setInjectionResultLocked(entry, injectionResult); - if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { - return true; - } - - // TODO: support sending secondary display events to input monitors - if (isMainDisplay(entry->displayId)) { - addMonitoringTargetsLocked(inputTargets); - } - - // Dispatch the motion. - if (conflictingPointerActions) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "conflicting pointer actions"); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } - dispatchEventLocked(currentTime, entry, inputTargets); - return true; -} - - -void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, " - "metaState=0x%x, buttonState=0x%x, " - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, - entry->metaState, entry->buttonState, - entry->edgeFlags, entry->xPrecision, entry->yPrecision, - entry->downTime); - - for (uint32_t i = 0; i < entry->pointerCount; i++) { - ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, entry->pointerProperties[i].id, - entry->pointerProperties[i].toolType, - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); - } -#endif -} - -void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, - EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("dispatchEventToCurrentInputTargets"); -#endif - - ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true - - pokeUserActivityLocked(eventEntry); - - for (size_t i = 0; i < inputTargets.size(); i++) { - const InputTarget& inputTarget = inputTargets.itemAt(i); - - ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); - prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); - } else { -#if DEBUG_FOCUS - ALOGD("Dropping event delivery to target with channel '%s' because it " - "is no longer registered with the input dispatcher.", - inputTarget.inputChannel->getName().string()); -#endif - } - } -} - -int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, - const EventEntry* entry, - const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t* nextWakeupTime, const char* reason) { - if (applicationHandle == NULL && windowHandle == NULL) { - if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { -#if DEBUG_FOCUS - ALOGD("Waiting for system to become ready for input. Reason: %s", reason); -#endif - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY; - mInputTargetWaitStartTime = currentTime; - mInputTargetWaitTimeoutTime = LONG_LONG_MAX; - mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplicationHandle.clear(); - } - } else { - if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { -#if DEBUG_FOCUS - ALOGD("Waiting for application to become ready for input: %s. Reason: %s", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), - reason); -#endif - nsecs_t timeout; - if (windowHandle != NULL) { - timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); - } else if (applicationHandle != NULL) { - timeout = applicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT); - } else { - timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; - } - - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; - mInputTargetWaitStartTime = currentTime; - mInputTargetWaitTimeoutTime = currentTime + timeout; - mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplicationHandle.clear(); - - if (windowHandle != NULL) { - mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle; - } - if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) { - mInputTargetWaitApplicationHandle = applicationHandle; - } - } - } - - if (mInputTargetWaitTimeoutExpired) { - return INPUT_EVENT_INJECTION_TIMED_OUT; - } - - if (currentTime >= mInputTargetWaitTimeoutTime) { - onANRLocked(currentTime, applicationHandle, windowHandle, - entry->eventTime, mInputTargetWaitStartTime, reason); - - // Force poll loop to wake up immediately on next iteration once we get the - // ANR response back from the policy. - *nextWakeupTime = LONG_LONG_MIN; - return INPUT_EVENT_INJECTION_PENDING; - } else { - // Force poll loop to wake up when timeout is due. - if (mInputTargetWaitTimeoutTime < *nextWakeupTime) { - *nextWakeupTime = mInputTargetWaitTimeoutTime; - } - return INPUT_EVENT_INJECTION_PENDING; - } -} - -void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp<InputChannel>& inputChannel) { - if (newTimeout > 0) { - // Extend the timeout. - mInputTargetWaitTimeoutTime = now() + newTimeout; - } else { - // Give up. - mInputTargetWaitTimeoutExpired = true; - - // Input state will not be realistic. Mark it out of sync. - if (inputChannel.get()) { - ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); - sp<InputWindowHandle> windowHandle = connection->inputWindowHandle; - - if (windowHandle != NULL) { - mTouchState.removeWindow(windowHandle); - } - - if (connection->status == Connection::STATUS_NORMAL) { - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "application not responding"); - synthesizeCancelationEventsForConnectionLocked(connection, options); - } - } - } - } -} - -nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( - nsecs_t currentTime) { - if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { - return currentTime - mInputTargetWaitStartTime; - } - return 0; -} - -void InputDispatcher::resetANRTimeoutsLocked() { -#if DEBUG_FOCUS - ALOGD("Resetting ANR timeouts."); -#endif - - // Reset input target wait timeout. - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; - mInputTargetWaitApplicationHandle.clear(); -} - -int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, - const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { - int32_t injectionResult; - - // If there is no currently focused window and no focused application - // then drop the event. - if (mFocusedWindowHandle == NULL) { - if (mFocusedApplicationHandle != NULL) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, NULL, nextWakeupTime, - "Waiting because no window has focus but there is a " - "focused application that may eventually add a window " - "when it finishes starting up."); - goto Unresponsive; - } - - ALOGI("Dropping event because there is no focused window or focused application."); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Check permissions. - if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) { - injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; - goto Failed; - } - - // If the currently focused window is paused then keep waiting. - if (mFocusedWindowHandle->getInfo()->paused) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, - "Waiting because the focused window is paused."); - goto Unresponsive; - } - - // If the currently focused window is still working on previous events then keep waiting. - if (!isWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry)) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, - "Waiting because the focused window has not finished " - "processing the input events that were previously delivered to it."); - goto Unresponsive; - } - - // Success! Output targets. - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - addWindowTargetLocked(mFocusedWindowHandle, - InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), - inputTargets); - - // Done. -Failed: -Unresponsive: - nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); - updateDispatchStatisticsLocked(currentTime, entry, - injectionResult, timeSpentWaitingForApplication); -#if DEBUG_FOCUS - ALOGD("findFocusedWindow finished: injectionResult=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, timeSpentWaitingForApplication / 1000000.0); -#endif - return injectionResult; -} - -int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, - const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions) { - enum InjectionPermission { - INJECTION_PERMISSION_UNKNOWN, - INJECTION_PERMISSION_GRANTED, - INJECTION_PERMISSION_DENIED - }; - - nsecs_t startTime = now(); - - // For security reasons, we defer updating the touch state until we are sure that - // event injection will be allowed. - // - // FIXME In the original code, screenWasOff could never be set to true. - // The reason is that the POLICY_FLAG_WOKE_HERE - // and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw - // EV_KEY, EV_REL and EV_ABS events. As it happens, the touch event was - // actually enqueued using the policyFlags that appeared in the final EV_SYN - // events upon which no preprocessing took place. So policyFlags was always 0. - // In the new native input dispatcher we're a bit more careful about event - // preprocessing so the touches we receive can actually have non-zero policyFlags. - // Unfortunately we obtain undesirable behavior. - // - // Here's what happens: - // - // When the device dims in anticipation of going to sleep, touches - // in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause - // the device to brighten and reset the user activity timer. - // Touches on other windows (such as the launcher window) - // are dropped. Then after a moment, the device goes to sleep. Oops. - // - // Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE - // instead of POLICY_FLAG_WOKE_HERE... - // - bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE; - - int32_t displayId = entry->displayId; - int32_t action = entry->action; - int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - - // Update the touch state as needed based on the properties of the touch event. - int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING; - InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; - sp<InputWindowHandle> newHoverWindowHandle; - - bool isSplit = mTouchState.split; - bool switchedDevice = mTouchState.deviceId >= 0 && mTouchState.displayId >= 0 - && (mTouchState.deviceId != entry->deviceId - || mTouchState.source != entry->source - || mTouchState.displayId != displayId); - bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER - || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); - bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN - || maskedAction == AMOTION_EVENT_ACTION_SCROLL - || isHoverAction); - bool wrongDevice = false; - if (newGesture) { - bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; - if (switchedDevice && mTouchState.down && !down) { -#if DEBUG_FOCUS - ALOGD("Dropping event because a pointer for a different device is already down."); -#endif - mTempTouchState.copyFrom(mTouchState); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - switchedDevice = false; - wrongDevice = true; - goto Failed; - } - mTempTouchState.reset(); - mTempTouchState.down = down; - mTempTouchState.deviceId = entry->deviceId; - mTempTouchState.source = entry->source; - mTempTouchState.displayId = displayId; - isSplit = false; - } else { - mTempTouchState.copyFrom(mTouchState); - } - - if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { - /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ - - int32_t pointerIndex = getMotionEventActionPointerIndex(action); - int32_t x = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp<InputWindowHandle> newTouchedWindowHandle; - sp<InputWindowHandle> topErrorWindowHandle; - bool isTouchModal = false; - - // Traverse windows from front to back to find touched window and outside targets. - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - if (windowInfo->displayId != displayId) { - continue; // wrong display - } - - int32_t privateFlags = windowInfo->layoutParamsPrivateFlags; - if (privateFlags & InputWindowInfo::PRIVATE_FLAG_SYSTEM_ERROR) { - if (topErrorWindowHandle == NULL) { - topErrorWindowHandle = windowHandle; - } - } - - int32_t flags = windowInfo->layoutParamsFlags; - if (windowInfo->visible) { - if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { - isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE - | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { - if (! screenWasOff - || (flags & InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING)) { - newTouchedWindowHandle = windowHandle; - } - break; // found touched window, exit window loop - } - } - - if (maskedAction == AMOTION_EVENT_ACTION_DOWN - && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { - int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; - if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { - outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - mTempTouchState.addOrUpdateWindow( - windowHandle, outsideTargetFlags, BitSet32(0)); - } - } - } - - // If there is an error window but it is not taking focus (typically because - // it is invisible) then wait for it. Any other focused window may in - // fact be in ANR state. - if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, NULL, nextWakeupTime, - "Waiting because a system error window is about to be displayed."); - injectionPermission = INJECTION_PERMISSION_UNKNOWN; - goto Unresponsive; - } - - // Figure out whether splitting will be allowed for this window. - if (newTouchedWindowHandle != NULL - && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { - // New window supports splitting. - isSplit = true; - } else if (isSplit) { - // New window does not support splitting but we have already split events. - // Ignore the new window. - newTouchedWindowHandle = NULL; - } - - // Handle the case where we did not find a window. - if (newTouchedWindowHandle == NULL) { - // Try to assign the pointer to the first foreground window we find, if there is one. - newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); - if (newTouchedWindowHandle == NULL) { - ALOGI("Dropping event because there is no touchable window at (%d, %d).", x, y); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - } - - // Set target flags. - int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS; - if (isSplit) { - targetFlags |= InputTarget::FLAG_SPLIT; - } - if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { - targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - // Update hover state. - if (isHoverAction) { - newHoverWindowHandle = newTouchedWindowHandle; - } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { - newHoverWindowHandle = mLastHoverWindowHandle; - } - - // Update the temporary touch state. - BitSet32 pointerIds; - if (isSplit) { - uint32_t pointerId = entry->pointerProperties[pointerIndex].id; - pointerIds.markBit(pointerId); - } - mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); - } else { - /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ - - // If the pointer is not currently down, then ignore the event. - if (! mTempTouchState.down) { -#if DEBUG_FOCUS - ALOGD("Dropping event because the pointer is not down or we previously " - "dropped the pointer down event."); -#endif - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Check whether touches should slip outside of the current foreground window. - if (maskedAction == AMOTION_EVENT_ACTION_MOVE - && entry->pointerCount == 1 - && mTempTouchState.isSlippery()) { - int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); - - sp<InputWindowHandle> oldTouchedWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); - sp<InputWindowHandle> newTouchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y); - if (oldTouchedWindowHandle != newTouchedWindowHandle - && newTouchedWindowHandle != NULL) { -#if DEBUG_FOCUS - ALOGD("Touch is slipping out of window %s into window %s.", - oldTouchedWindowHandle->getName().string(), - newTouchedWindowHandle->getName().string()); -#endif - // Make a slippery exit from the old window. - mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0)); - - // Make a slippery entrance into the new window. - if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { - isSplit = true; - } - - int32_t targetFlags = InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; - if (isSplit) { - targetFlags |= InputTarget::FLAG_SPLIT; - } - if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { - targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - BitSet32 pointerIds; - if (isSplit) { - pointerIds.markBit(entry->pointerProperties[0].id); - } - mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); - } - } - } - - if (newHoverWindowHandle != mLastHoverWindowHandle) { - // Let the previous window know that the hover sequence is over. - if (mLastHoverWindowHandle != NULL) { -#if DEBUG_HOVER - ALOGD("Sending hover exit event to window %s.", - mLastHoverWindowHandle->getName().string()); -#endif - mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); - } - - // Let the new window know that the hover sequence is starting. - if (newHoverWindowHandle != NULL) { -#if DEBUG_HOVER - ALOGD("Sending hover enter event to window %s.", - newHoverWindowHandle->getName().string()); -#endif - mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0)); - } - } - - // Check permission to inject into all touched foreground windows and ensure there - // is at least one touched foreground window. - { - bool haveForegroundWindow = false; - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { - haveForegroundWindow = true; - if (! checkInjectionPermission(touchedWindow.windowHandle, - entry->injectionState)) { - injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; - injectionPermission = INJECTION_PERMISSION_DENIED; - goto Failed; - } - } - } - if (! haveForegroundWindow) { -#if DEBUG_FOCUS - ALOGD("Dropping event because there is no touched foreground window to receive it."); -#endif - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Permission granted to injection into all touched foreground windows. - injectionPermission = INJECTION_PERMISSION_GRANTED; - } - - // Check whether windows listening for outside touches are owned by the same UID. If it is - // set the policy flag that we will not reveal coordinate information to this window. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - sp<InputWindowHandle> foregroundWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); - const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid; - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle; - if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { - mTempTouchState.addOrUpdateWindow(inputWindowHandle, - InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); - } - } - } - } - - // Ensure all touched foreground windows are ready for new input. - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { - // If the touched window is paused then keep waiting. - if (touchedWindow.windowHandle->getInfo()->paused) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.windowHandle, nextWakeupTime, - "Waiting because the touched window is paused."); - goto Unresponsive; - } - - // If the touched window is still working on previous events then keep waiting. - if (!isWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry)) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.windowHandle, nextWakeupTime, - "Waiting because the touched window has not finished " - "processing the input events that were previously delivered to it."); - goto Unresponsive; - } - } - } - - // If this is the first pointer going down and the touched window has a wallpaper - // then also add the touched wallpaper windows so they are locked in for the duration - // of the touch gesture. - // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper - // engine only supports touch events. We would need to add a mechanism similar - // to View.onGenericMotionEvent to enable wallpapers to handle these events. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - sp<InputWindowHandle> foregroundWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); - if (foregroundWindowHandle->getInfo()->hasWallpaper) { - for (size_t i = 0; i < mWindowHandles.size(); i++) { - sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* info = windowHandle->getInfo(); - if (info->displayId == displayId - && windowHandle->getInfo()->layoutParamsType - == InputWindowInfo::TYPE_WALLPAPER) { - mTempTouchState.addOrUpdateWindow(windowHandle, - InputTarget::FLAG_WINDOW_IS_OBSCURED - | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0)); - } - } - } - } - - // Success! Output targets. - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i); - addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.pointerIds, inputTargets); - } - - // Drop the outside or hover touch windows since we will not care about them - // in the next iteration. - mTempTouchState.filterNonAsIsTouchWindows(); - -Failed: - // Check injection permission once and for all. - if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) { - if (checkInjectionPermission(NULL, entry->injectionState)) { - injectionPermission = INJECTION_PERMISSION_GRANTED; - } else { - injectionPermission = INJECTION_PERMISSION_DENIED; - } - } - - // Update final pieces of touch state if the injector had permission. - if (injectionPermission == INJECTION_PERMISSION_GRANTED) { - if (!wrongDevice) { - if (switchedDevice) { -#if DEBUG_FOCUS - ALOGD("Conflicting pointer actions: Switched to a different device."); -#endif - *outConflictingPointerActions = true; - } - - if (isHoverAction) { - // Started hovering, therefore no longer down. - if (mTouchState.down) { -#if DEBUG_FOCUS - ALOGD("Conflicting pointer actions: Hover received while pointer was down."); -#endif - *outConflictingPointerActions = true; - } - mTouchState.reset(); - if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER - || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { - mTouchState.deviceId = entry->deviceId; - mTouchState.source = entry->source; - mTouchState.displayId = displayId; - } - } else if (maskedAction == AMOTION_EVENT_ACTION_UP - || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { - // All pointers up or canceled. - mTouchState.reset(); - } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - // First pointer went down. - if (mTouchState.down) { -#if DEBUG_FOCUS - ALOGD("Conflicting pointer actions: Down received while already down."); -#endif - *outConflictingPointerActions = true; - } - mTouchState.copyFrom(mTempTouchState); - } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { - // One pointer went up. - if (isSplit) { - int32_t pointerIndex = getMotionEventActionPointerIndex(action); - uint32_t pointerId = entry->pointerProperties[pointerIndex].id; - - for (size_t i = 0; i < mTempTouchState.windows.size(); ) { - TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i); - if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) { - touchedWindow.pointerIds.clearBit(pointerId); - if (touchedWindow.pointerIds.isEmpty()) { - mTempTouchState.windows.removeAt(i); - continue; - } - } - i += 1; - } - } - mTouchState.copyFrom(mTempTouchState); - } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { - // Discard temporary touch state since it was only valid for this action. - } else { - // Save changes to touch state as-is for all other actions. - mTouchState.copyFrom(mTempTouchState); - } - - // Update hover state. - mLastHoverWindowHandle = newHoverWindowHandle; - } - } else { -#if DEBUG_FOCUS - ALOGD("Not updating touch focus because injection was denied."); -#endif - } - -Unresponsive: - // Reset temporary touch state to ensure we release unnecessary references to input channels. - mTempTouchState.reset(); - - nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); - updateDispatchStatisticsLocked(currentTime, entry, - injectionResult, timeSpentWaitingForApplication); -#if DEBUG_FOCUS - ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); -#endif - return injectionResult; -} - -void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) { - inputTargets.push(); - - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - InputTarget& target = inputTargets.editTop(); - target.inputChannel = windowInfo->inputChannel; - target.flags = targetFlags; - target.xOffset = - windowInfo->frameLeft; - target.yOffset = - windowInfo->frameTop; - target.scaleFactor = windowInfo->scaleFactor; - target.pointerIds = pointerIds; -} - -void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets) { - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - inputTargets.push(); - - InputTarget& target = inputTargets.editTop(); - target.inputChannel = mMonitoringChannels[i]; - target.flags = InputTarget::FLAG_DISPATCH_AS_IS; - target.xOffset = 0; - target.yOffset = 0; - target.pointerIds.clear(); - target.scaleFactor = 1.0f; - } -} - -bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, - const InjectionState* injectionState) { - if (injectionState - && (windowHandle == NULL - || windowHandle->getInfo()->ownerUid != injectionState->injectorUid) - && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { - if (windowHandle != NULL) { - ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " - "owned by uid %d", - injectionState->injectorPid, injectionState->injectorUid, - windowHandle->getName().string(), - windowHandle->getInfo()->ownerUid); - } else { - ALOGW("Permission denied: injecting event from pid %d uid %d", - injectionState->injectorPid, injectionState->injectorUid); - } - return false; - } - return true; -} - -bool InputDispatcher::isWindowObscuredAtPointLocked( - const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const { - int32_t displayId = windowHandle->getInfo()->displayId; - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i); - if (otherHandle == windowHandle) { - break; - } - - const InputWindowInfo* otherInfo = otherHandle->getInfo(); - if (otherInfo->displayId == displayId - && otherInfo->visible && !otherInfo->isTrustedOverlay() - && otherInfo->frameContainsPoint(x, y)) { - return true; - } - } - return false; -} - -bool InputDispatcher::isWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry) { - ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel()); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); - if (connection->inputPublisherBlocked) { - return false; - } - if (eventEntry->type == EventEntry::TYPE_KEY) { - // If the event is a key event, then we must wait for all previous events to - // complete before delivering it because previous events may have the - // side-effect of transferring focus to a different window and we want to - // ensure that the following keys are sent to the new window. - // - // Suppose the user touches a button in a window then immediately presses "A". - // If the button causes a pop-up window to appear then we want to ensure that - // the "A" key is delivered to the new pop-up window. This is because users - // often anticipate pending UI changes when typing on a keyboard. - // To obtain this behavior, we must serialize key events with respect to all - // prior input events. - return connection->outboundQueue.isEmpty() - && connection->waitQueue.isEmpty(); - } - // Touch events can always be sent to a window immediately because the user intended - // to touch whatever was visible at the time. Even if focus changes or a new - // window appears moments later, the touch event was meant to be delivered to - // whatever window happened to be on screen at the time. - // - // Generic motion events, such as trackball or joystick events are a little trickier. - // Like key events, generic motion events are delivered to the focused window. - // Unlike key events, generic motion events don't tend to transfer focus to other - // windows and it is not important for them to be serialized. So we prefer to deliver - // generic motion events as soon as possible to improve efficiency and reduce lag - // through batching. - // - // The one case where we pause input event delivery is when the wait queue is piling - // up with lots of events because the application is not responding. - // This condition ensures that ANRs are detected reliably. - if (!connection->waitQueue.isEmpty() - && currentTime >= connection->waitQueue.head->deliveryTime - + STREAM_AHEAD_EVENT_TIMEOUT) { - return false; - } - } - return true; -} - -String8 InputDispatcher::getApplicationWindowLabelLocked( - const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle) { - if (applicationHandle != NULL) { - if (windowHandle != NULL) { - String8 label(applicationHandle->getName()); - label.append(" - "); - label.append(windowHandle->getName()); - return label; - } else { - return applicationHandle->getName(); - } - } else if (windowHandle != NULL) { - return windowHandle->getName(); - } else { - return String8("<unknown application or window>"); - } -} - -void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { - if (mFocusedWindowHandle != NULL) { - const InputWindowInfo* info = mFocusedWindowHandle->getInfo(); - if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("Not poking user activity: disabled by window '%s'.", info->name.string()); -#endif - return; - } - } - - int32_t eventType = USER_ACTIVITY_EVENT_OTHER; - switch (eventEntry->type) { - case EventEntry::TYPE_MOTION: { - const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry); - if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { - return; - } - - if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { - eventType = USER_ACTIVITY_EVENT_TOUCH; - } - break; - } - case EventEntry::TYPE_KEY: { - const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry); - if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { - return; - } - eventType = USER_ACTIVITY_EVENT_BUTTON; - break; - } - } - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doPokeUserActivityLockedInterruptible); - commandEntry->eventTime = eventEntry->eventTime; - commandEntry->userActivityEventType = eventType; -} - -void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " - "xOffset=%f, yOffset=%f, scaleFactor=%f, " - "pointerIds=0x%x", - connection->getInputChannelName(), inputTarget->flags, - inputTarget->xOffset, inputTarget->yOffset, - inputTarget->scaleFactor, inputTarget->pointerIds.value); -#endif - - // Skip this event if the connection status is not normal. - // We don't want to enqueue additional outbound events if the connection is broken. - if (connection->status != Connection::STATUS_NORMAL) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ Dropping event because the channel status is %s", - connection->getInputChannelName(), connection->getStatusLabel()); -#endif - return; - } - - // Split a motion event if needed. - if (inputTarget->flags & InputTarget::FLAG_SPLIT) { - ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION); - - MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry); - if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) { - MotionEntry* splitMotionEntry = splitMotionEvent( - originalMotionEntry, inputTarget->pointerIds); - if (!splitMotionEntry) { - return; // split event was dropped - } -#if DEBUG_FOCUS - ALOGD("channel '%s' ~ Split motion event.", - connection->getInputChannelName()); - logOutboundMotionDetailsLocked(" ", splitMotionEntry); -#endif - enqueueDispatchEntriesLocked(currentTime, connection, - splitMotionEntry, inputTarget); - splitMotionEntry->release(); - return; - } - } - - // Not splitting. Enqueue dispatch entries for the event as is. - enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget); -} - -void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, - const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { - bool wasEmpty = connection->outboundQueue.isEmpty(); - - // Enqueue dispatch entries for the requested modes. - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_OUTSIDE); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_IS); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); - - // If the outbound queue was previously empty, start the dispatch cycle going. - if (wasEmpty && !connection->outboundQueue.isEmpty()) { - startDispatchCycleLocked(currentTime, connection); - } -} - -void InputDispatcher::enqueueDispatchEntryLocked( - const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, - int32_t dispatchMode) { - int32_t inputTargetFlags = inputTarget->flags; - if (!(inputTargetFlags & dispatchMode)) { - return; - } - inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode; - - // This is a new event. - // Enqueue a new dispatch entry onto the outbound queue for this connection. - DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref - inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, - inputTarget->scaleFactor); - - // Apply target flags and update the connection's input state. - switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); - dispatchEntry->resolvedAction = keyEntry->action; - dispatchEntry->resolvedFlags = keyEntry->flags; - - if (!connection->inputState.trackKey(keyEntry, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", - connection->getInputChannelName()); -#endif - delete dispatchEntry; - return; // skip the inconsistent event - } - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); - if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; - } else { - dispatchEntry->resolvedAction = motionEntry->action; - } - if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - && !connection->inputState.isHovering( - motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event", - connection->getInputChannelName()); -#endif - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } - - dispatchEntry->resolvedFlags = motionEntry->flags; - if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { - dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; - } - - if (!connection->inputState.trackMotion(motionEntry, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event", - connection->getInputChannelName()); -#endif - delete dispatchEntry; - return; // skip the inconsistent event - } - break; - } - } - - // Remember that we are waiting for this dispatch to complete. - if (dispatchEntry->hasForegroundTarget()) { - incrementPendingForegroundDispatchesLocked(eventEntry); - } - - // Enqueue the dispatch entry. - connection->outboundQueue.enqueueAtTail(dispatchEntry); - traceOutboundQueueLengthLocked(connection); -} - -void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ startDispatchCycle", - connection->getInputChannelName()); -#endif - - while (connection->status == Connection::STATUS_NORMAL - && !connection->outboundQueue.isEmpty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.head; - dispatchEntry->deliveryTime = currentTime; - - // Publish the event. - status_t status; - EventEntry* eventEntry = dispatchEntry->eventEntry; - switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); - - // Publish the key event. - status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, - keyEntry->deviceId, keyEntry->source, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, - keyEntry->keyCode, keyEntry->scanCode, - keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, - keyEntry->eventTime); - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); - - PointerCoords scaledCoords[MAX_POINTERS]; - const PointerCoords* usingCoords = motionEntry->pointerCoords; - - // Set the X and Y offset depending on the input source. - float xOffset, yOffset, scaleFactor; - if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) - && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { - scaleFactor = dispatchEntry->scaleFactor; - xOffset = dispatchEntry->xOffset * scaleFactor; - yOffset = dispatchEntry->yOffset * scaleFactor; - if (scaleFactor != 1.0f) { - for (size_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i] = motionEntry->pointerCoords[i]; - scaledCoords[i].scale(scaleFactor); - } - usingCoords = scaledCoords; - } - } else { - xOffset = 0.0f; - yOffset = 0.0f; - scaleFactor = 1.0f; - - // We don't want the dispatch target to know. - if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { - for (size_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i].clear(); - } - usingCoords = scaledCoords; - } - } - - // Publish the motion event. - status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, - motionEntry->deviceId, motionEntry->source, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, - motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, - xOffset, yOffset, - motionEntry->xPrecision, motionEntry->yPrecision, - motionEntry->downTime, motionEntry->eventTime, - motionEntry->pointerCount, motionEntry->pointerProperties, - usingCoords); - break; - } - - default: - ALOG_ASSERT(false); - return; - } - - // Check the result. - if (status) { - if (status == WOULD_BLOCK) { - if (connection->waitQueue.isEmpty()) { - ALOGE("channel '%s' ~ Could not publish event because the pipe is full. " - "This is unexpected because the wait queue is empty, so the pipe " - "should be empty and we shouldn't have any problems writing an " - "event to it, status=%d", connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); - } else { - // Pipe is full and we are waiting for the app to finish process some events - // before sending more events to it. -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ Could not publish event because the pipe is full, " - "waiting for the application to catch up", - connection->getInputChannelName()); -#endif - connection->inputPublisherBlocked = true; - } - } else { - ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " - "status=%d", connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); - } - return; - } - - // Re-enqueue the event on the wait queue. - connection->outboundQueue.dequeue(dispatchEntry); - traceOutboundQueueLengthLocked(connection); - connection->waitQueue.enqueueAtTail(dispatchEntry); - traceWaitQueueLengthLocked(connection); - } -} - -void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, uint32_t seq, bool handled) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s", - connection->getInputChannelName(), seq, toString(handled)); -#endif - - connection->inputPublisherBlocked = false; - - if (connection->status == Connection::STATUS_BROKEN - || connection->status == Connection::STATUS_ZOMBIE) { - return; - } - - // Notify other system components and prepare to start the next dispatch cycle. - onDispatchCycleFinishedLocked(currentTime, connection, seq, handled); -} - -void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, bool notify) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s", - connection->getInputChannelName(), toString(notify)); -#endif - - // Clear the dispatch queues. - drainDispatchQueueLocked(&connection->outboundQueue); - traceOutboundQueueLengthLocked(connection); - drainDispatchQueueLocked(&connection->waitQueue); - traceWaitQueueLengthLocked(connection); - - // The connection appears to be unrecoverably broken. - // Ignore already broken or zombie connections. - if (connection->status == Connection::STATUS_NORMAL) { - connection->status = Connection::STATUS_BROKEN; - - if (notify) { - // Notify other system components. - onDispatchCycleBrokenLocked(currentTime, connection); - } - } -} - -void InputDispatcher::drainDispatchQueueLocked(Queue<DispatchEntry>* queue) { - while (!queue->isEmpty()) { - DispatchEntry* dispatchEntry = queue->dequeueAtHead(); - releaseDispatchEntryLocked(dispatchEntry); - } -} - -void InputDispatcher::releaseDispatchEntryLocked(DispatchEntry* dispatchEntry) { - if (dispatchEntry->hasForegroundTarget()) { - decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry); - } - delete dispatchEntry; -} - -int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { - InputDispatcher* d = static_cast<InputDispatcher*>(data); - - { // acquire lock - AutoMutex _l(d->mLock); - - ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); - if (connectionIndex < 0) { - ALOGE("Received spurious receive callback for unknown input channel. " - "fd=%d, events=0x%x", fd, events); - return 0; // remove the callback - } - - bool notify; - sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex); - if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { - if (!(events & ALOOPER_EVENT_INPUT)) { - ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " - "events=0x%x", connection->getInputChannelName(), events); - return 1; - } - - nsecs_t currentTime = now(); - bool gotOne = false; - status_t status; - for (;;) { - uint32_t seq; - bool handled; - status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled); - if (status) { - break; - } - d->finishDispatchCycleLocked(currentTime, connection, seq, handled); - gotOne = true; - } - if (gotOne) { - d->runCommandsLockedInterruptible(); - if (status == WOULD_BLOCK) { - return 1; - } - } - - notify = status != DEAD_OBJECT || !connection->monitor; - if (notify) { - ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d", - connection->getInputChannelName(), status); - } - } else { - // Monitor channels are never explicitly unregistered. - // We do it automatically when the remote endpoint is closed so don't warn - // about them. - notify = !connection->monitor; - if (notify) { - ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. " - "events=0x%x", connection->getInputChannelName(), events); - } - } - - // Unregister the channel. - d->unregisterInputChannelLocked(connection->inputChannel, notify); - return 0; // remove the callback - } // release lock -} - -void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( - const CancelationOptions& options) { - for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByFd.valueAt(i), options); - } -} - -void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( - const sp<InputChannel>& channel, const CancelationOptions& options) { - ssize_t index = getConnectionIndexLocked(channel); - if (index >= 0) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByFd.valueAt(index), options); - } -} - -void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( - const sp<Connection>& connection, const CancelationOptions& options) { - if (connection->status == Connection::STATUS_BROKEN) { - return; - } - - nsecs_t currentTime = now(); - - Vector<EventEntry*> cancelationEvents; - connection->inputState.synthesizeCancelationEvents(currentTime, - cancelationEvents, options); - - if (!cancelationEvents.isEmpty()) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync " - "with reality: %s, mode=%d.", - connection->getInputChannelName(), cancelationEvents.size(), - options.reason, options.mode); -#endif - for (size_t i = 0; i < cancelationEvents.size(); i++) { - EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i); - switch (cancelationEventEntry->type) { - case EventEntry::TYPE_KEY: - logOutboundKeyDetailsLocked("cancel - ", - static_cast<KeyEntry*>(cancelationEventEntry)); - break; - case EventEntry::TYPE_MOTION: - logOutboundMotionDetailsLocked("cancel - ", - static_cast<MotionEntry*>(cancelationEventEntry)); - break; - } - - InputTarget target; - sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel); - if (windowHandle != NULL) { - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - target.xOffset = -windowInfo->frameLeft; - target.yOffset = -windowInfo->frameTop; - target.scaleFactor = windowInfo->scaleFactor; - } else { - target.xOffset = 0; - target.yOffset = 0; - target.scaleFactor = 1.0f; - } - target.inputChannel = connection->inputChannel; - target.flags = InputTarget::FLAG_DISPATCH_AS_IS; - - enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref - &target, InputTarget::FLAG_DISPATCH_AS_IS); - - cancelationEventEntry->release(); - } - - startDispatchCycleLocked(currentTime, connection); - } -} - -InputDispatcher::MotionEntry* -InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { - ALOG_ASSERT(pointerIds.value != 0); - - uint32_t splitPointerIndexMap[MAX_POINTERS]; - PointerProperties splitPointerProperties[MAX_POINTERS]; - PointerCoords splitPointerCoords[MAX_POINTERS]; - - uint32_t originalPointerCount = originalMotionEntry->pointerCount; - uint32_t splitPointerCount = 0; - - for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; - originalPointerIndex++) { - const PointerProperties& pointerProperties = - originalMotionEntry->pointerProperties[originalPointerIndex]; - uint32_t pointerId = uint32_t(pointerProperties.id); - if (pointerIds.hasBit(pointerId)) { - splitPointerIndexMap[splitPointerCount] = originalPointerIndex; - splitPointerProperties[splitPointerCount].copyFrom(pointerProperties); - splitPointerCoords[splitPointerCount].copyFrom( - originalMotionEntry->pointerCoords[originalPointerIndex]); - splitPointerCount += 1; - } - } - - if (splitPointerCount != pointerIds.count()) { - // This is bad. We are missing some of the pointers that we expected to deliver. - // Most likely this indicates that we received an ACTION_MOVE events that has - // different pointer ids than we expected based on the previous ACTION_DOWN - // or ACTION_POINTER_DOWN events that caused us to decide to split the pointers - // in this way. - ALOGW("Dropping split motion event because the pointer count is %d but " - "we expected there to be %d pointers. This probably means we received " - "a broken sequence of pointer ids from the input device.", - splitPointerCount, pointerIds.count()); - return NULL; - } - - int32_t action = originalMotionEntry->action; - int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { - int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); - const PointerProperties& pointerProperties = - originalMotionEntry->pointerProperties[originalPointerIndex]; - uint32_t pointerId = uint32_t(pointerProperties.id); - if (pointerIds.hasBit(pointerId)) { - if (pointerIds.count() == 1) { - // The first/last pointer went down/up. - action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else { - // A secondary pointer went down/up. - uint32_t splitPointerIndex = 0; - while (pointerId != uint32_t(splitPointerProperties[splitPointerIndex].id)) { - splitPointerIndex += 1; - } - action = maskedAction | (splitPointerIndex - << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); - } - } else { - // An unrelated pointer changed. - action = AMOTION_EVENT_ACTION_MOVE; - } - } - - MotionEntry* splitMotionEntry = new MotionEntry( - originalMotionEntry->eventTime, - originalMotionEntry->deviceId, - originalMotionEntry->source, - originalMotionEntry->policyFlags, - action, - originalMotionEntry->flags, - originalMotionEntry->metaState, - originalMotionEntry->buttonState, - originalMotionEntry->edgeFlags, - originalMotionEntry->xPrecision, - originalMotionEntry->yPrecision, - originalMotionEntry->downTime, - originalMotionEntry->displayId, - splitPointerCount, splitPointerProperties, splitPointerCoords); - - if (originalMotionEntry->injectionState) { - splitMotionEntry->injectionState = originalMotionEntry->injectionState; - splitMotionEntry->injectionState->refCount += 1; - } - - return splitMotionEntry; -} - -void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyConfigurationChanged - eventTime=%lld", args->eventTime); -#endif - - bool needWake; - { // acquire lock - AutoMutex _l(mLock); - - ConfigurationChangedEntry* newEntry = new ConfigurationChangedEntry(args->eventTime); - needWake = enqueueInboundEventLocked(newEntry); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, " - "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", - args->eventTime, args->deviceId, args->source, args->policyFlags, - args->action, args->flags, args->keyCode, args->scanCode, - args->metaState, args->downTime); -#endif - if (!validateKeyEvent(args->action)) { - return; - } - - uint32_t policyFlags = args->policyFlags; - int32_t flags = args->flags; - int32_t metaState = args->metaState; - if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) { - policyFlags |= POLICY_FLAG_VIRTUAL; - flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; - } - if (policyFlags & POLICY_FLAG_ALT) { - metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON; - } - if (policyFlags & POLICY_FLAG_ALT_GR) { - metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON; - } - if (policyFlags & POLICY_FLAG_SHIFT) { - metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON; - } - if (policyFlags & POLICY_FLAG_CAPS_LOCK) { - metaState |= AMETA_CAPS_LOCK_ON; - } - if (policyFlags & POLICY_FLAG_FUNCTION) { - metaState |= AMETA_FUNCTION_ON; - } - - policyFlags |= POLICY_FLAG_TRUSTED; - - KeyEvent event; - event.initialize(args->deviceId, args->source, args->action, - flags, args->keyCode, args->scanCode, metaState, 0, - args->downTime, args->eventTime); - - mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); - - if (policyFlags & POLICY_FLAG_WOKE_HERE) { - flags |= AKEY_EVENT_FLAG_WOKE_HERE; - } - - bool needWake; - { // acquire lock - mLock.lock(); - - if (shouldSendKeyToInputFilterLocked(args)) { - mLock.unlock(); - - policyFlags |= POLICY_FLAG_FILTERED; - if (!mPolicy->filterInputEvent(&event, policyFlags)) { - return; // event was consumed by the filter - } - - mLock.lock(); - } - - int32_t repeatCount = 0; - KeyEntry* newEntry = new KeyEntry(args->eventTime, - args->deviceId, args->source, policyFlags, - args->action, flags, args->keyCode, args->scanCode, - metaState, repeatCount, args->downTime); - - needWake = enqueueInboundEventLocked(newEntry); - mLock.unlock(); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) { - return mInputFilterEnabled; -} - -void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, " - "xPrecision=%f, yPrecision=%f, downTime=%lld", - args->eventTime, args->deviceId, args->source, args->policyFlags, - args->action, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); - for (uint32_t i = 0; i < args->pointerCount; i++) { - ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, args->pointerProperties[i].id, - args->pointerProperties[i].toolType, - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); - } -#endif - if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) { - return; - } - - uint32_t policyFlags = args->policyFlags; - policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags); - - bool needWake; - { // acquire lock - mLock.lock(); - - if (shouldSendMotionToInputFilterLocked(args)) { - mLock.unlock(); - - MotionEvent event; - event.initialize(args->deviceId, args->source, args->action, args->flags, - args->edgeFlags, args->metaState, args->buttonState, 0, 0, - args->xPrecision, args->yPrecision, - args->downTime, args->eventTime, - args->pointerCount, args->pointerProperties, args->pointerCoords); - - policyFlags |= POLICY_FLAG_FILTERED; - if (!mPolicy->filterInputEvent(&event, policyFlags)) { - return; // event was consumed by the filter - } - - mLock.lock(); - } - - // Just enqueue a new motion event. - MotionEntry* newEntry = new MotionEntry(args->eventTime, - args->deviceId, args->source, policyFlags, - args->action, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, - args->displayId, - args->pointerCount, args->pointerProperties, args->pointerCoords); - - needWake = enqueueInboundEventLocked(newEntry); - mLock.unlock(); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) { - // TODO: support sending secondary display events to input filter - return mInputFilterEnabled && isMainDisplay(args->displayId); -} - -void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchValues=0x%08x, switchMask=0x%08x", - args->eventTime, args->policyFlags, - args->switchValues, args->switchMask); -#endif - - uint32_t policyFlags = args->policyFlags; - policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->notifySwitch(args->eventTime, - args->switchValues, args->switchMask, policyFlags); -} - -void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d", - args->eventTime, args->deviceId); -#endif - - bool needWake; - { // acquire lock - AutoMutex _l(mLock); - - DeviceResetEntry* newEntry = new DeviceResetEntry(args->eventTime, args->deviceId); - needWake = enqueueInboundEventLocked(newEntry); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -int32_t InputDispatcher::injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " - "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", - event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); -#endif - - nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); - - policyFlags |= POLICY_FLAG_INJECTED; - if (hasInjectionPermission(injectorPid, injectorUid)) { - policyFlags |= POLICY_FLAG_TRUSTED; - } - - EventEntry* firstInjectedEntry; - EventEntry* lastInjectedEntry; - switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: { - const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event); - int32_t action = keyEvent->getAction(); - if (! validateKeyEvent(action)) { - return INPUT_EVENT_INJECTION_FAILED; - } - - int32_t flags = keyEvent->getFlags(); - if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { - policyFlags |= POLICY_FLAG_VIRTUAL; - } - - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags); - } - - if (policyFlags & POLICY_FLAG_WOKE_HERE) { - flags |= AKEY_EVENT_FLAG_WOKE_HERE; - } - - mLock.lock(); - firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(), - keyEvent->getDeviceId(), keyEvent->getSource(), - policyFlags, action, flags, - keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(), - keyEvent->getRepeatCount(), keyEvent->getDownTime()); - lastInjectedEntry = firstInjectedEntry; - break; - } - - case AINPUT_EVENT_TYPE_MOTION: { - const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); - int32_t displayId = ADISPLAY_ID_DEFAULT; - int32_t action = motionEvent->getAction(); - size_t pointerCount = motionEvent->getPointerCount(); - const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); - if (! validateMotionEvent(action, pointerCount, pointerProperties)) { - return INPUT_EVENT_INJECTION_FAILED; - } - - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - nsecs_t eventTime = motionEvent->getEventTime(); - mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags); - } - - mLock.lock(); - const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); - const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - firstInjectedEntry = new MotionEntry(*sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), displayId, - uint32_t(pointerCount), pointerProperties, samplePointerCoords); - lastInjectedEntry = firstInjectedEntry; - for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { - sampleEventTimes += 1; - samplePointerCoords += pointerCount; - MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), displayId, - uint32_t(pointerCount), pointerProperties, samplePointerCoords); - lastInjectedEntry->next = nextInjectedEntry; - lastInjectedEntry = nextInjectedEntry; - } - break; - } - - default: - ALOGW("Cannot inject event of type %d", event->getType()); - return INPUT_EVENT_INJECTION_FAILED; - } - - InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); - if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { - injectionState->injectionIsAsync = true; - } - - injectionState->refCount += 1; - lastInjectedEntry->injectionState = injectionState; - - bool needWake = false; - for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) { - EventEntry* nextEntry = entry->next; - needWake |= enqueueInboundEventLocked(entry); - entry = nextEntry; - } - - mLock.unlock(); - - if (needWake) { - mLooper->wake(); - } - - int32_t injectionResult; - { // acquire lock - AutoMutex _l(mLock); - - if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - } else { - for (;;) { - injectionResult = injectionState->injectionResult; - if (injectionResult != INPUT_EVENT_INJECTION_PENDING) { - break; - } - - nsecs_t remainingTimeout = endTime - now(); - if (remainingTimeout <= 0) { -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Timed out waiting for injection result " - "to become available."); -#endif - injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; - break; - } - - mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout); - } - - if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED - && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { - while (injectionState->pendingForegroundDispatches != 0) { -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.", - injectionState->pendingForegroundDispatches); -#endif - nsecs_t remainingTimeout = endTime - now(); - if (remainingTimeout <= 0) { -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Timed out waiting for pending foreground " - "dispatches to finish."); -#endif - injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; - break; - } - - mInjectionSyncFinishedCondition.waitRelative(mLock, remainingTimeout); - } - } - } - - injectionState->release(); - } // release lock - -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Finished with result %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectorPid, injectorUid); -#endif - - return injectionResult; -} - -bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { - return injectorUid == 0 - || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); -} - -void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { -#if DEBUG_INJECTION - ALOGD("Setting input event injection result to %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectionState->injectorPid, injectionState->injectorUid); -#endif - - if (injectionState->injectionIsAsync - && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { - // Log the outcome since the injector did not wait for the injection result. - switch (injectionResult) { - case INPUT_EVENT_INJECTION_SUCCEEDED: - ALOGV("Asynchronous input event injection succeeded."); - break; - case INPUT_EVENT_INJECTION_FAILED: - ALOGW("Asynchronous input event injection failed."); - break; - case INPUT_EVENT_INJECTION_PERMISSION_DENIED: - ALOGW("Asynchronous input event injection permission denied."); - break; - case INPUT_EVENT_INJECTION_TIMED_OUT: - ALOGW("Asynchronous input event injection timed out."); - break; - } - } - - injectionState->injectionResult = injectionResult; - mInjectionResultAvailableCondition.broadcast(); - } -} - -void InputDispatcher::incrementPendingForegroundDispatchesLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { - injectionState->pendingForegroundDispatches += 1; - } -} - -void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { - injectionState->pendingForegroundDispatches -= 1; - - if (injectionState->pendingForegroundDispatches == 0) { - mInjectionSyncFinishedCondition.broadcast(); - } - } -} - -sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked( - const sp<InputChannel>& inputChannel) const { - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); - if (windowHandle->getInputChannel() == inputChannel) { - return windowHandle; - } - } - return NULL; -} - -bool InputDispatcher::hasWindowHandleLocked( - const sp<InputWindowHandle>& windowHandle) const { - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - if (mWindowHandles.itemAt(i) == windowHandle) { - return true; - } - } - return false; -} - -void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) { -#if DEBUG_FOCUS - ALOGD("setInputWindows"); -#endif - { // acquire lock - AutoMutex _l(mLock); - - Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles; - mWindowHandles = inputWindowHandles; - - sp<InputWindowHandle> newFocusedWindowHandle; - bool foundHoveredWindow = false; - for (size_t i = 0; i < mWindowHandles.size(); i++) { - const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); - if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) { - mWindowHandles.removeAt(i--); - continue; - } - if (windowHandle->getInfo()->hasFocus) { - newFocusedWindowHandle = windowHandle; - } - if (windowHandle == mLastHoverWindowHandle) { - foundHoveredWindow = true; - } - } - - if (!foundHoveredWindow) { - mLastHoverWindowHandle = NULL; - } - - if (mFocusedWindowHandle != newFocusedWindowHandle) { - if (mFocusedWindowHandle != NULL) { -#if DEBUG_FOCUS - ALOGD("Focus left window: %s", - mFocusedWindowHandle->getName().string()); -#endif - sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel(); - if (focusedInputChannel != NULL) { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, - "focus left window"); - synthesizeCancelationEventsForInputChannelLocked( - focusedInputChannel, options); - } - } - if (newFocusedWindowHandle != NULL) { -#if DEBUG_FOCUS - ALOGD("Focus entered window: %s", - newFocusedWindowHandle->getName().string()); -#endif - } - mFocusedWindowHandle = newFocusedWindowHandle; - } - - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i); - if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { -#if DEBUG_FOCUS - ALOGD("Touched window was removed: %s", - touchedWindow.windowHandle->getName().string()); -#endif - sp<InputChannel> touchedInputChannel = - touchedWindow.windowHandle->getInputChannel(); - if (touchedInputChannel != NULL) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "touched window was removed"); - synthesizeCancelationEventsForInputChannelLocked( - touchedInputChannel, options); - } - mTouchState.windows.removeAt(i--); - } - } - - // Release information for windows that are no longer present. - // This ensures that unused input channels are released promptly. - // Otherwise, they might stick around until the window handle is destroyed - // which might not happen until the next GC. - for (size_t i = 0; i < oldWindowHandles.size(); i++) { - const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i); - if (!hasWindowHandleLocked(oldWindowHandle)) { -#if DEBUG_FOCUS - ALOGD("Window went away: %s", oldWindowHandle->getName().string()); -#endif - oldWindowHandle->releaseInfo(); - } - } - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); -} - -void InputDispatcher::setFocusedApplication( - const sp<InputApplicationHandle>& inputApplicationHandle) { -#if DEBUG_FOCUS - ALOGD("setFocusedApplication"); -#endif - { // acquire lock - AutoMutex _l(mLock); - - if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) { - if (mFocusedApplicationHandle != inputApplicationHandle) { - if (mFocusedApplicationHandle != NULL) { - resetANRTimeoutsLocked(); - mFocusedApplicationHandle->releaseInfo(); - } - mFocusedApplicationHandle = inputApplicationHandle; - } - } else if (mFocusedApplicationHandle != NULL) { - resetANRTimeoutsLocked(); - mFocusedApplicationHandle->releaseInfo(); - mFocusedApplicationHandle.clear(); - } - -#if DEBUG_FOCUS - //logDispatchStateLocked(); -#endif - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); -} - -void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { -#if DEBUG_FOCUS - ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen); -#endif - - bool changed; - { // acquire lock - AutoMutex _l(mLock); - - if (mDispatchEnabled != enabled || mDispatchFrozen != frozen) { - if (mDispatchFrozen && !frozen) { - resetANRTimeoutsLocked(); - } - - if (mDispatchEnabled && !enabled) { - resetAndDropEverythingLocked("dispatcher is being disabled"); - } - - mDispatchEnabled = enabled; - mDispatchFrozen = frozen; - changed = true; - } else { - changed = false; - } - -#if DEBUG_FOCUS - //logDispatchStateLocked(); -#endif - } // release lock - - if (changed) { - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); - } -} - -void InputDispatcher::setInputFilterEnabled(bool enabled) { -#if DEBUG_FOCUS - ALOGD("setInputFilterEnabled: enabled=%d", enabled); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - if (mInputFilterEnabled == enabled) { - return; - } - - mInputFilterEnabled = enabled; - resetAndDropEverythingLocked("input filter is being enabled or disabled"); - } // release lock - - // Wake up poll loop since there might be work to do to drop everything. - mLooper->wake(); -} - -bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, - const sp<InputChannel>& toChannel) { -#if DEBUG_FOCUS - ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s", - fromChannel->getName().string(), toChannel->getName().string()); -#endif - { // acquire lock - AutoMutex _l(mLock); - - sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel); - sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel); - if (fromWindowHandle == NULL || toWindowHandle == NULL) { -#if DEBUG_FOCUS - ALOGD("Cannot transfer focus because from or to window not found."); -#endif - return false; - } - if (fromWindowHandle == toWindowHandle) { -#if DEBUG_FOCUS - ALOGD("Trivial transfer to same window."); -#endif - return true; - } - if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) { -#if DEBUG_FOCUS - ALOGD("Cannot transfer focus because windows are on different displays."); -#endif - return false; - } - - bool found = false; - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - if (touchedWindow.windowHandle == fromWindowHandle) { - int32_t oldTargetFlags = touchedWindow.targetFlags; - BitSet32 pointerIds = touchedWindow.pointerIds; - - mTouchState.windows.removeAt(i); - - int32_t newTargetFlags = oldTargetFlags - & (InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); - mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); - - found = true; - break; - } - } - - if (! found) { -#if DEBUG_FOCUS - ALOGD("Focus transfer failed because from window did not have focus."); -#endif - return false; - } - - ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); - ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); - if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { - sp<Connection> fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex); - sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex); - - fromConnection->inputState.copyPointerStateTo(toConnection->inputState); - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "transferring touch focus from this window to another window"); - synthesizeCancelationEventsForConnectionLocked(fromConnection, options); - } - -#if DEBUG_FOCUS - logDispatchStateLocked(); -#endif - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); - return true; -} - -void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { -#if DEBUG_FOCUS - ALOGD("Resetting and dropping all events (%s).", reason); -#endif - - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - - resetKeyRepeatLocked(); - releasePendingEventLocked(); - drainInboundQueueLocked(); - resetANRTimeoutsLocked(); - - mTouchState.reset(); - mLastHoverWindowHandle.clear(); -} - -void InputDispatcher::logDispatchStateLocked() { - String8 dump; - dumpDispatchStateLocked(dump); - - char* text = dump.lockBuffer(dump.size()); - char* start = text; - while (*start != '\0') { - char* end = strchr(start, '\n'); - if (*end == '\n') { - *(end++) = '\0'; - } - ALOGD("%s", start); - start = end; - } -} - -void InputDispatcher::dumpDispatchStateLocked(String8& dump) { - dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); - dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); - - if (mFocusedApplicationHandle != NULL) { - dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", - mFocusedApplicationHandle->getName().string(), - mFocusedApplicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); - } else { - dump.append(INDENT "FocusedApplication: <null>\n"); - } - dump.appendFormat(INDENT "FocusedWindow: name='%s'\n", - mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : "<null>"); - - dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down)); - dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split)); - dump.appendFormat(INDENT "TouchDeviceId: %d\n", mTouchState.deviceId); - dump.appendFormat(INDENT "TouchSource: 0x%08x\n", mTouchState.source); - dump.appendFormat(INDENT "TouchDisplayId: %d\n", mTouchState.displayId); - if (!mTouchState.windows.isEmpty()) { - dump.append(INDENT "TouchedWindows:\n"); - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.windowHandle->getName().string(), - touchedWindow.pointerIds.value, - touchedWindow.targetFlags); - } - } else { - dump.append(INDENT "TouchedWindows: <none>\n"); - } - - if (!mWindowHandles.isEmpty()) { - dump.append(INDENT "Windows:\n"); - for (size_t i = 0; i < mWindowHandles.size(); i++) { - const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - - dump.appendFormat(INDENT2 "%d: name='%s', displayId=%d, " - "paused=%s, hasFocus=%s, hasWallpaper=%s, " - "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " - "frame=[%d,%d][%d,%d], scale=%f, " - "touchableRegion=", - i, windowInfo->name.string(), windowInfo->displayId, - toString(windowInfo->paused), - toString(windowInfo->hasFocus), - toString(windowInfo->hasWallpaper), - toString(windowInfo->visible), - toString(windowInfo->canReceiveKeys), - windowInfo->layoutParamsFlags, windowInfo->layoutParamsType, - windowInfo->layer, - windowInfo->frameLeft, windowInfo->frameTop, - windowInfo->frameRight, windowInfo->frameBottom, - windowInfo->scaleFactor); - dumpRegion(dump, windowInfo->touchableRegion); - dump.appendFormat(", inputFeatures=0x%08x", windowInfo->inputFeatures); - dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", - windowInfo->ownerPid, windowInfo->ownerUid, - windowInfo->dispatchingTimeout / 1000000.0); - } - } else { - dump.append(INDENT "Windows: <none>\n"); - } - - if (!mMonitoringChannels.isEmpty()) { - dump.append(INDENT "MonitoringChannels:\n"); - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - const sp<InputChannel>& channel = mMonitoringChannels[i]; - dump.appendFormat(INDENT2 "%d: '%s'\n", i, channel->getName().string()); - } - } else { - dump.append(INDENT "MonitoringChannels: <none>\n"); - } - - nsecs_t currentTime = now(); - - // Dump recently dispatched or dropped events from oldest to newest. - if (!mRecentQueue.isEmpty()) { - dump.appendFormat(INDENT "RecentQueue: length=%u\n", mRecentQueue.count()); - for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) { - dump.append(INDENT2); - entry->appendDescription(dump); - dump.appendFormat(", age=%0.1fms\n", - (currentTime - entry->eventTime) * 0.000001f); - } - } else { - dump.append(INDENT "RecentQueue: <empty>\n"); - } - - // Dump event currently being dispatched. - if (mPendingEvent) { - dump.append(INDENT "PendingEvent:\n"); - dump.append(INDENT2); - mPendingEvent->appendDescription(dump); - dump.appendFormat(", age=%0.1fms\n", - (currentTime - mPendingEvent->eventTime) * 0.000001f); - } else { - dump.append(INDENT "PendingEvent: <none>\n"); - } - - // Dump inbound events from oldest to newest. - if (!mInboundQueue.isEmpty()) { - dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count()); - for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) { - dump.append(INDENT2); - entry->appendDescription(dump); - dump.appendFormat(", age=%0.1fms\n", - (currentTime - entry->eventTime) * 0.000001f); - } - } else { - dump.append(INDENT "InboundQueue: <empty>\n"); - } - - if (!mConnectionsByFd.isEmpty()) { - dump.append(INDENT "Connections:\n"); - for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - const sp<Connection>& connection = mConnectionsByFd.valueAt(i); - dump.appendFormat(INDENT2 "%d: channelName='%s', windowName='%s', " - "status=%s, monitor=%s, inputPublisherBlocked=%s\n", - i, connection->getInputChannelName(), connection->getWindowName(), - connection->getStatusLabel(), toString(connection->monitor), - toString(connection->inputPublisherBlocked)); - - if (!connection->outboundQueue.isEmpty()) { - dump.appendFormat(INDENT3 "OutboundQueue: length=%u\n", - connection->outboundQueue.count()); - for (DispatchEntry* entry = connection->outboundQueue.head; entry; - entry = entry->next) { - dump.append(INDENT4); - entry->eventEntry->appendDescription(dump); - dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f); - } - } else { - dump.append(INDENT3 "OutboundQueue: <empty>\n"); - } - - if (!connection->waitQueue.isEmpty()) { - dump.appendFormat(INDENT3 "WaitQueue: length=%u\n", - connection->waitQueue.count()); - for (DispatchEntry* entry = connection->waitQueue.head; entry; - entry = entry->next) { - dump.append(INDENT4); - entry->eventEntry->appendDescription(dump); - dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, " - "age=%0.1fms, wait=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f, - (currentTime - entry->deliveryTime) * 0.000001f); - } - } else { - dump.append(INDENT3 "WaitQueue: <empty>\n"); - } - } - } else { - dump.append(INDENT "Connections: <none>\n"); - } - - if (isAppSwitchPendingLocked()) { - dump.appendFormat(INDENT "AppSwitch: pending, due in %0.1fms\n", - (mAppSwitchDueTime - now()) / 1000000.0); - } else { - dump.append(INDENT "AppSwitch: not pending\n"); - } - - dump.append(INDENT "Configuration:\n"); - dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", - mConfig.keyRepeatDelay * 0.000001f); - dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", - mConfig.keyRepeatTimeout * 0.000001f); -} - -status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { -#if DEBUG_REGISTRATION - ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(), - toString(monitor)); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - if (getConnectionIndexLocked(inputChannel) >= 0) { - ALOGW("Attempted to register already registered input channel '%s'", - inputChannel->getName().string()); - return BAD_VALUE; - } - - sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor); - - int fd = inputChannel->getFd(); - mConnectionsByFd.add(fd, connection); - - if (monitor) { - mMonitoringChannels.push(inputChannel); - } - - mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); - } // release lock - - // Wake the looper because some connections have changed. - mLooper->wake(); - return OK; -} - -status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) { -#if DEBUG_REGISTRATION - ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string()); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - status_t status = unregisterInputChannelLocked(inputChannel, false /*notify*/); - if (status) { - return status; - } - } // release lock - - // Wake the poll loop because removing the connection may have changed the current - // synchronization state. - mLooper->wake(); - return OK; -} - -status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, - bool notify) { - ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); - if (connectionIndex < 0) { - ALOGW("Attempted to unregister already unregistered input channel '%s'", - inputChannel->getName().string()); - return BAD_VALUE; - } - - sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); - mConnectionsByFd.removeItemsAt(connectionIndex); - - if (connection->monitor) { - removeMonitorChannelLocked(inputChannel); - } - - mLooper->removeFd(inputChannel->getFd()); - - nsecs_t currentTime = now(); - abortBrokenDispatchCycleLocked(currentTime, connection, notify); - - connection->status = Connection::STATUS_ZOMBIE; - return OK; -} - -void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) { - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - if (mMonitoringChannels[i] == inputChannel) { - mMonitoringChannels.removeAt(i); - break; - } - } -} - -ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) { - ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd()); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); - if (connection->inputChannel.get() == inputChannel.get()) { - return connectionIndex; - } - } - - return -1; -} - -void InputDispatcher::onDispatchCycleFinishedLocked( - nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); - commandEntry->connection = connection; - commandEntry->eventTime = currentTime; - commandEntry->seq = seq; - commandEntry->handled = handled; -} - -void InputDispatcher::onDispatchCycleBrokenLocked( - nsecs_t currentTime, const sp<Connection>& connection) { - ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", - connection->getInputChannelName()); - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); - commandEntry->connection = connection; -} - -void InputDispatcher::onANRLocked( - nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) { - float dispatchLatency = (currentTime - eventTime) * 0.000001f; - float waitDuration = (currentTime - waitStartTime) * 0.000001f; - ALOGI("Application is not responding: %s. " - "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), - dispatchLatency, waitDuration, reason); - - // Capture a record of the InputDispatcher state at the time of the ANR. - time_t t = time(NULL); - struct tm tm; - localtime_r(&t, &tm); - char timestr[64]; - strftime(timestr, sizeof(timestr), "%F %T", &tm); - mLastANRState.clear(); - mLastANRState.append(INDENT "ANR:\n"); - mLastANRState.appendFormat(INDENT2 "Time: %s\n", timestr); - mLastANRState.appendFormat(INDENT2 "Window: %s\n", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string()); - mLastANRState.appendFormat(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); - mLastANRState.appendFormat(INDENT2 "WaitDuration: %0.1fms\n", waitDuration); - mLastANRState.appendFormat(INDENT2 "Reason: %s\n", reason); - dumpDispatchStateLocked(mLastANRState); - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyANRLockedInterruptible); - commandEntry->inputApplicationHandle = applicationHandle; - commandEntry->inputWindowHandle = windowHandle; - commandEntry->reason = reason; -} - -void InputDispatcher::doNotifyConfigurationChangedInterruptible( - CommandEntry* commandEntry) { - mLock.unlock(); - - mPolicy->notifyConfigurationChanged(commandEntry->eventTime); - - mLock.lock(); -} - -void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( - CommandEntry* commandEntry) { - sp<Connection> connection = commandEntry->connection; - - if (connection->status != Connection::STATUS_ZOMBIE) { - mLock.unlock(); - - mPolicy->notifyInputChannelBroken(connection->inputWindowHandle); - - mLock.lock(); - } -} - -void InputDispatcher::doNotifyANRLockedInterruptible( - CommandEntry* commandEntry) { - mLock.unlock(); - - nsecs_t newTimeout = mPolicy->notifyANR( - commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle, - commandEntry->reason); - - mLock.lock(); - - resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, - commandEntry->inputWindowHandle != NULL - ? commandEntry->inputWindowHandle->getInputChannel() : NULL); -} - -void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( - CommandEntry* commandEntry) { - KeyEntry* entry = commandEntry->keyEntry; - - KeyEvent event; - initializeKeyEvent(&event, entry); - - mLock.unlock(); - - nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, - &event, entry->policyFlags); - - mLock.lock(); - - if (delay < 0) { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; - } else if (!delay) { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; - } else { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER; - entry->interceptKeyWakeupTime = now() + delay; - } - entry->release(); -} - -void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( - CommandEntry* commandEntry) { - sp<Connection> connection = commandEntry->connection; - nsecs_t finishTime = commandEntry->eventTime; - uint32_t seq = commandEntry->seq; - bool handled = commandEntry->handled; - - // Handle post-event policy actions. - DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq); - if (dispatchEntry) { - nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime; - if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { - String8 msg; - msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ", - connection->getWindowName(), eventDuration * 0.000001f); - dispatchEntry->eventEntry->appendDescription(msg); - ALOGI("%s", msg.string()); - } - - bool restartEvent; - if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { - KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); - restartEvent = afterKeyEventLockedInterruptible(connection, - dispatchEntry, keyEntry, handled); - } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) { - MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry); - restartEvent = afterMotionEventLockedInterruptible(connection, - dispatchEntry, motionEntry, handled); - } else { - restartEvent = false; - } - - // Dequeue the event and start the next cycle. - // Note that because the lock might have been released, it is possible that the - // contents of the wait queue to have been drained, so we need to double-check - // a few things. - if (dispatchEntry == connection->findWaitQueueEntry(seq)) { - connection->waitQueue.dequeue(dispatchEntry); - traceWaitQueueLengthLocked(connection); - if (restartEvent && connection->status == Connection::STATUS_NORMAL) { - connection->outboundQueue.enqueueAtHead(dispatchEntry); - traceOutboundQueueLengthLocked(connection); - } else { - releaseDispatchEntryLocked(dispatchEntry); - } - } - - // Start the next dispatch cycle for this connection. - startDispatchCycleLocked(now(), connection); - } -} - -bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) { - if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) { - // Get the fallback key state. - // Clear it out after dispatching the UP. - int32_t originalKeyCode = keyEntry->keyCode; - int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode); - if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - connection->inputState.removeFallbackKey(originalKeyCode); - } - - if (handled || !dispatchEntry->hasForegroundTarget()) { - // If the application handles the original key for which we previously - // generated a fallback or if the window is not a foreground window, - // then cancel the associated fallback key, if any. - if (fallbackKeyCode != -1) { - // Dispatch the unhandled key to the policy with the cancel flag. -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Asking policy to cancel fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); -#endif - KeyEvent event; - initializeKeyEvent(&event, keyEntry); - event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED); - - mLock.unlock(); - - mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, - &event, keyEntry->policyFlags, &event); - - mLock.lock(); - - // Cancel the fallback key. - if (fallbackKeyCode != AKEYCODE_UNKNOWN) { - CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, - "application handled the original non-fallback key " - "or is no longer a foreground target, " - "canceling previously dispatched fallback key"); - options.keyCode = fallbackKeyCode; - synthesizeCancelationEventsForConnectionLocked(connection, options); - } - connection->inputState.removeFallbackKey(originalKeyCode); - } - } else { - // If the application did not handle a non-fallback key, first check - // that we are in a good state to perform unhandled key event processing - // Then ask the policy what to do with it. - bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN - && keyEntry->repeatCount == 0; - if (fallbackKeyCode == -1 && !initialDown) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Skipping unhandled key event processing " - "since this is not an initial down. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - originalKeyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); -#endif - return false; - } - - // Dispatch the unhandled key to the policy. -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Asking policy to perform fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); -#endif - KeyEvent event; - initializeKeyEvent(&event, keyEntry); - - mLock.unlock(); - - bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, - &event, keyEntry->policyFlags, &event); - - mLock.lock(); - - if (connection->status != Connection::STATUS_NORMAL) { - connection->inputState.removeFallbackKey(originalKeyCode); - return false; - } - - // Latch the fallback keycode for this key on an initial down. - // The fallback keycode cannot change at any other point in the lifecycle. - if (initialDown) { - if (fallback) { - fallbackKeyCode = event.getKeyCode(); - } else { - fallbackKeyCode = AKEYCODE_UNKNOWN; - } - connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); - } - - ALOG_ASSERT(fallbackKeyCode != -1); - - // Cancel the fallback key if the policy decides not to send it anymore. - // We will continue to dispatch the key to the policy but we will no - // longer dispatch a fallback key to the application. - if (fallbackKeyCode != AKEYCODE_UNKNOWN - && (!fallback || fallbackKeyCode != event.getKeyCode())) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - if (fallback) { - ALOGD("Unhandled key event: Policy requested to send key %d" - "as a fallback for %d, but on the DOWN it had requested " - "to send %d instead. Fallback canceled.", - event.getKeyCode(), originalKeyCode, fallbackKeyCode); - } else { - ALOGD("Unhandled key event: Policy did not request fallback for %d, " - "but on the DOWN it had requested to send %d. " - "Fallback canceled.", - originalKeyCode, fallbackKeyCode); - } -#endif - - CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, - "canceling fallback, policy no longer desires it"); - options.keyCode = fallbackKeyCode; - synthesizeCancelationEventsForConnectionLocked(connection, options); - - fallback = false; - fallbackKeyCode = AKEYCODE_UNKNOWN; - if (keyEntry->action != AKEY_EVENT_ACTION_UP) { - connection->inputState.setFallbackKey(originalKeyCode, - fallbackKeyCode); - } - } - -#if DEBUG_OUTBOUND_EVENT_DETAILS - { - String8 msg; - const KeyedVector<int32_t, int32_t>& fallbackKeys = - connection->inputState.getFallbackKeys(); - for (size_t i = 0; i < fallbackKeys.size(); i++) { - msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i), - fallbackKeys.valueAt(i)); - } - ALOGD("Unhandled key event: %d currently tracked fallback keys%s.", - fallbackKeys.size(), msg.string()); - } -#endif - - if (fallback) { - // Restart the dispatch cycle using the fallback key. - keyEntry->eventTime = event.getEventTime(); - keyEntry->deviceId = event.getDeviceId(); - keyEntry->source = event.getSource(); - keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK; - keyEntry->keyCode = fallbackKeyCode; - keyEntry->scanCode = event.getScanCode(); - keyEntry->metaState = event.getMetaState(); - keyEntry->repeatCount = event.getRepeatCount(); - keyEntry->downTime = event.getDownTime(); - keyEntry->syntheticRepeat = false; - -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Dispatching fallback key. " - "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", - originalKeyCode, fallbackKeyCode, keyEntry->metaState); -#endif - return true; // restart the event - } else { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: No fallback key."); -#endif - } - } - } - return false; -} - -bool InputDispatcher::afterMotionEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) { - return false; -} - -void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) { - mLock.unlock(); - - mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType); - - mLock.lock(); -} - -void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) { - event->initialize(entry->deviceId, entry->source, entry->action, entry->flags, - entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, - entry->downTime, entry->eventTime); -} - -void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) { - // TODO Write some statistics about how long we spend waiting. -} - -void InputDispatcher::traceInboundQueueLengthLocked() { - if (ATRACE_ENABLED()) { - ATRACE_INT("iq", mInboundQueue.count()); - } -} - -void InputDispatcher::traceOutboundQueueLengthLocked(const sp<Connection>& connection) { - if (ATRACE_ENABLED()) { - char counterName[40]; - snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName()); - ATRACE_INT(counterName, connection->outboundQueue.count()); - } -} - -void InputDispatcher::traceWaitQueueLengthLocked(const sp<Connection>& connection) { - if (ATRACE_ENABLED()) { - char counterName[40]; - snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName()); - ATRACE_INT(counterName, connection->waitQueue.count()); - } -} - -void InputDispatcher::dump(String8& dump) { - AutoMutex _l(mLock); - - dump.append("Input Dispatcher State:\n"); - dumpDispatchStateLocked(dump); - - if (!mLastANRState.isEmpty()) { - dump.append("\nInput Dispatcher State at time of last ANR:\n"); - dump.append(mLastANRState); - } -} - -void InputDispatcher::monitor() { - // Acquire and release the lock to ensure that the dispatcher has not deadlocked. - mLock.lock(); - mLooper->wake(); - mDispatcherIsAliveCondition.wait(mLock); - mLock.unlock(); -} - - -// --- InputDispatcher::Queue --- - -template <typename T> -uint32_t InputDispatcher::Queue<T>::count() const { - uint32_t result = 0; - for (const T* entry = head; entry; entry = entry->next) { - result += 1; - } - return result; -} - - -// --- InputDispatcher::InjectionState --- - -InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : - refCount(1), - injectorPid(injectorPid), injectorUid(injectorUid), - injectionResult(INPUT_EVENT_INJECTION_PENDING), injectionIsAsync(false), - pendingForegroundDispatches(0) { -} - -InputDispatcher::InjectionState::~InjectionState() { -} - -void InputDispatcher::InjectionState::release() { - refCount -= 1; - if (refCount == 0) { - delete this; - } else { - ALOG_ASSERT(refCount > 0); - } -} - - -// --- InputDispatcher::EventEntry --- - -InputDispatcher::EventEntry::EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags) : - refCount(1), type(type), eventTime(eventTime), policyFlags(policyFlags), - injectionState(NULL), dispatchInProgress(false) { -} - -InputDispatcher::EventEntry::~EventEntry() { - releaseInjectionState(); -} - -void InputDispatcher::EventEntry::release() { - refCount -= 1; - if (refCount == 0) { - delete this; - } else { - ALOG_ASSERT(refCount > 0); - } -} - -void InputDispatcher::EventEntry::releaseInjectionState() { - if (injectionState) { - injectionState->release(); - injectionState = NULL; - } -} - - -// --- InputDispatcher::ConfigurationChangedEntry --- - -InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry(nsecs_t eventTime) : - EventEntry(TYPE_CONFIGURATION_CHANGED, eventTime, 0) { -} - -InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() { -} - -void InputDispatcher::ConfigurationChangedEntry::appendDescription(String8& msg) const { - msg.append("ConfigurationChangedEvent(), policyFlags=0x%08x", - policyFlags); -} - - -// --- InputDispatcher::DeviceResetEntry --- - -InputDispatcher::DeviceResetEntry::DeviceResetEntry(nsecs_t eventTime, int32_t deviceId) : - EventEntry(TYPE_DEVICE_RESET, eventTime, 0), - deviceId(deviceId) { -} - -InputDispatcher::DeviceResetEntry::~DeviceResetEntry() { -} - -void InputDispatcher::DeviceResetEntry::appendDescription(String8& msg) const { - msg.appendFormat("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", - deviceId, policyFlags); -} - - -// --- InputDispatcher::KeyEntry --- - -InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - int32_t repeatCount, nsecs_t downTime) : - EventEntry(TYPE_KEY, eventTime, policyFlags), - deviceId(deviceId), source(source), action(action), flags(flags), - keyCode(keyCode), scanCode(scanCode), metaState(metaState), - repeatCount(repeatCount), downTime(downTime), - syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN), - interceptKeyWakeupTime(0) { -} - -InputDispatcher::KeyEntry::~KeyEntry() { -} - -void InputDispatcher::KeyEntry::appendDescription(String8& msg) const { - msg.appendFormat("KeyEvent(deviceId=%d, source=0x%08x, action=%d, " - "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, " - "repeatCount=%d), policyFlags=0x%08x", - deviceId, source, action, flags, keyCode, scanCode, metaState, - repeatCount, policyFlags); -} - -void InputDispatcher::KeyEntry::recycle() { - releaseInjectionState(); - - dispatchInProgress = false; - syntheticRepeat = false; - interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; - interceptKeyWakeupTime = 0; -} - - -// --- InputDispatcher::MotionEntry --- - -InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t buttonState, - int32_t edgeFlags, float xPrecision, float yPrecision, - nsecs_t downTime, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) : - EventEntry(TYPE_MOTION, eventTime, policyFlags), - eventTime(eventTime), - deviceId(deviceId), source(source), action(action), flags(flags), - metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), - xPrecision(xPrecision), yPrecision(yPrecision), - downTime(downTime), displayId(displayId), pointerCount(pointerCount) { - for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties[i].copyFrom(pointerProperties[i]); - this->pointerCoords[i].copyFrom(pointerCoords[i]); - } -} - -InputDispatcher::MotionEntry::~MotionEntry() { -} - -void InputDispatcher::MotionEntry::appendDescription(String8& msg) const { - msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, " - "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, edgeFlags=0x%08x, " - "xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[", - deviceId, source, action, flags, metaState, buttonState, edgeFlags, - xPrecision, yPrecision, displayId); - for (uint32_t i = 0; i < pointerCount; i++) { - if (i) { - msg.append(", "); - } - msg.appendFormat("%d: (%.1f, %.1f)", pointerProperties[i].id, - pointerCoords[i].getX(), pointerCoords[i].getY()); - } - msg.appendFormat("]), policyFlags=0x%08x", policyFlags); -} - - -// --- InputDispatcher::DispatchEntry --- - -volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic; - -InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) : - seq(nextSeq()), - eventEntry(eventEntry), targetFlags(targetFlags), - xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor), - deliveryTime(0), resolvedAction(0), resolvedFlags(0) { - eventEntry->refCount += 1; -} - -InputDispatcher::DispatchEntry::~DispatchEntry() { - eventEntry->release(); -} - -uint32_t InputDispatcher::DispatchEntry::nextSeq() { - // Sequence number 0 is reserved and will never be returned. - uint32_t seq; - do { - seq = android_atomic_inc(&sNextSeqAtomic); - } while (!seq); - return seq; -} - - -// --- InputDispatcher::InputState --- - -InputDispatcher::InputState::InputState() { -} - -InputDispatcher::InputState::~InputState() { -} - -bool InputDispatcher::InputState::isNeutral() const { - return mKeyMementos.isEmpty() && mMotionMementos.isEmpty(); -} - -bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source, - int32_t displayId) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (memento.deviceId == deviceId - && memento.source == source - && memento.displayId == displayId - && memento.hovering) { - return true; - } - } - return false; -} - -bool InputDispatcher::InputState::trackKey(const KeyEntry* entry, - int32_t action, int32_t flags) { - switch (action) { - case AKEY_EVENT_ACTION_UP: { - if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) { - for (size_t i = 0; i < mFallbackKeys.size(); ) { - if (mFallbackKeys.valueAt(i) == entry->keyCode) { - mFallbackKeys.removeItemsAt(i); - } else { - i += 1; - } - } - } - ssize_t index = findKeyMemento(entry); - if (index >= 0) { - mKeyMementos.removeAt(index); - return true; - } - /* FIXME: We can't just drop the key up event because that prevents creating - * popup windows that are automatically shown when a key is held and then - * dismissed when the key is released. The problem is that the popup will - * not have received the original key down, so the key up will be considered - * to be inconsistent with its observed state. We could perhaps handle this - * by synthesizing a key down but that will cause other problems. - * - * So for now, allow inconsistent key up events to be dispatched. - * -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, " - "keyCode=%d, scanCode=%d", - entry->deviceId, entry->source, entry->keyCode, entry->scanCode); -#endif - return false; - */ - return true; - } - - case AKEY_EVENT_ACTION_DOWN: { - ssize_t index = findKeyMemento(entry); - if (index >= 0) { - mKeyMementos.removeAt(index); - } - addKeyMemento(entry, flags); - return true; - } - - default: - return true; - } -} - -bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry, - int32_t action, int32_t flags) { - int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; - switch (actionMasked) { - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, " - "actionMasked=%d", - entry->deviceId, entry->source, actionMasked); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_DOWN: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - } - addMotionMemento(entry, flags, false /*hovering*/); - return true; - } - - case AMOTION_EVENT_ACTION_POINTER_UP: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_MOVE: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - MotionMemento& memento = mMotionMementos.editItemAt(index); - memento.setPointers(entry); - return true; - } - if (actionMasked == AMOTION_EVENT_ACTION_MOVE - && (entry->source & (AINPUT_SOURCE_CLASS_JOYSTICK - | AINPUT_SOURCE_CLASS_NAVIGATION))) { - // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP. - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion pointer up/down or move event: " - "deviceId=%d, source=%08x, actionMasked=%d", - entry->deviceId, entry->source, actionMasked); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_HOVER_EXIT: { - ssize_t index = findMotionMemento(entry, true /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x", - entry->deviceId, entry->source); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: { - ssize_t index = findMotionMemento(entry, true /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - } - addMotionMemento(entry, flags, true /*hovering*/); - return true; - } - - default: - return true; - } -} - -ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const { - for (size_t i = 0; i < mKeyMementos.size(); i++) { - const KeyMemento& memento = mKeyMementos.itemAt(i); - if (memento.deviceId == entry->deviceId - && memento.source == entry->source - && memento.keyCode == entry->keyCode - && memento.scanCode == entry->scanCode) { - return i; - } - } - return -1; -} - -ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry, - bool hovering) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (memento.deviceId == entry->deviceId - && memento.source == entry->source - && memento.displayId == entry->displayId - && memento.hovering == hovering) { - return i; - } - } - return -1; -} - -void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) { - mKeyMementos.push(); - KeyMemento& memento = mKeyMementos.editTop(); - memento.deviceId = entry->deviceId; - memento.source = entry->source; - memento.keyCode = entry->keyCode; - memento.scanCode = entry->scanCode; - memento.metaState = entry->metaState; - memento.flags = flags; - memento.downTime = entry->downTime; - memento.policyFlags = entry->policyFlags; -} - -void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, - int32_t flags, bool hovering) { - mMotionMementos.push(); - MotionMemento& memento = mMotionMementos.editTop(); - memento.deviceId = entry->deviceId; - memento.source = entry->source; - memento.flags = flags; - memento.xPrecision = entry->xPrecision; - memento.yPrecision = entry->yPrecision; - memento.downTime = entry->downTime; - memento.displayId = entry->displayId; - memento.setPointers(entry); - memento.hovering = hovering; - memento.policyFlags = entry->policyFlags; -} - -void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) { - pointerCount = entry->pointerCount; - for (uint32_t i = 0; i < entry->pointerCount; i++) { - pointerProperties[i].copyFrom(entry->pointerProperties[i]); - pointerCoords[i].copyFrom(entry->pointerCoords[i]); - } -} - -void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, - Vector<EventEntry*>& outEvents, const CancelationOptions& options) { - for (size_t i = 0; i < mKeyMementos.size(); i++) { - const KeyMemento& memento = mKeyMementos.itemAt(i); - if (shouldCancelKey(memento, options)) { - outEvents.push(new KeyEntry(currentTime, - memento.deviceId, memento.source, memento.policyFlags, - AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, - memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime)); - } - } - - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (shouldCancelMotion(memento, options)) { - outEvents.push(new MotionEntry(currentTime, - memento.deviceId, memento.source, memento.policyFlags, - memento.hovering - ? AMOTION_EVENT_ACTION_HOVER_EXIT - : AMOTION_EVENT_ACTION_CANCEL, - memento.flags, 0, 0, 0, - memento.xPrecision, memento.yPrecision, memento.downTime, - memento.displayId, - memento.pointerCount, memento.pointerProperties, memento.pointerCoords)); - } - } -} - -void InputDispatcher::InputState::clear() { - mKeyMementos.clear(); - mMotionMementos.clear(); - mFallbackKeys.clear(); -} - -void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { - for (size_t j = 0; j < other.mMotionMementos.size(); ) { - const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j); - if (memento.deviceId == otherMemento.deviceId - && memento.source == otherMemento.source - && memento.displayId == otherMemento.displayId) { - other.mMotionMementos.removeAt(j); - } else { - j += 1; - } - } - other.mMotionMementos.push(memento); - } - } -} - -int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) { - ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); - return index >= 0 ? mFallbackKeys.valueAt(index) : -1; -} - -void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode, - int32_t fallbackKeyCode) { - ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); - if (index >= 0) { - mFallbackKeys.replaceValueAt(index, fallbackKeyCode); - } else { - mFallbackKeys.add(originalKeyCode, fallbackKeyCode); - } -} - -void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) { - mFallbackKeys.removeItem(originalKeyCode); -} - -bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, - const CancelationOptions& options) { - if (options.keyCode != -1 && memento.keyCode != options.keyCode) { - return false; - } - - if (options.deviceId != -1 && memento.deviceId != options.deviceId) { - return false; - } - - switch (options.mode) { - case CancelationOptions::CANCEL_ALL_EVENTS: - case CancelationOptions::CANCEL_NON_POINTER_EVENTS: - return true; - case CancelationOptions::CANCEL_FALLBACK_EVENTS: - return memento.flags & AKEY_EVENT_FLAG_FALLBACK; - default: - return false; - } -} - -bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, - const CancelationOptions& options) { - if (options.deviceId != -1 && memento.deviceId != options.deviceId) { - return false; - } - - switch (options.mode) { - case CancelationOptions::CANCEL_ALL_EVENTS: - return true; - case CancelationOptions::CANCEL_POINTER_EVENTS: - return memento.source & AINPUT_SOURCE_CLASS_POINTER; - case CancelationOptions::CANCEL_NON_POINTER_EVENTS: - return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); - default: - return false; - } -} - - -// --- InputDispatcher::Connection --- - -InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor) : - status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle), - monitor(monitor), - inputPublisher(inputChannel), inputPublisherBlocked(false) { -} - -InputDispatcher::Connection::~Connection() { -} - -const char* InputDispatcher::Connection::getWindowName() const { - if (inputWindowHandle != NULL) { - return inputWindowHandle->getName().string(); - } - if (monitor) { - return "monitor"; - } - return "?"; -} - -const char* InputDispatcher::Connection::getStatusLabel() const { - switch (status) { - case STATUS_NORMAL: - return "NORMAL"; - - case STATUS_BROKEN: - return "BROKEN"; - - case STATUS_ZOMBIE: - return "ZOMBIE"; - - default: - return "UNKNOWN"; - } -} - -InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) { - for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) { - if (entry->seq == seq) { - return entry; - } - } - return NULL; -} - - -// --- InputDispatcher::CommandEntry --- - -InputDispatcher::CommandEntry::CommandEntry(Command command) : - command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0), - seq(0), handled(false) { -} - -InputDispatcher::CommandEntry::~CommandEntry() { -} - - -// --- InputDispatcher::TouchState --- - -InputDispatcher::TouchState::TouchState() : - down(false), split(false), deviceId(-1), source(0), displayId(-1) { -} - -InputDispatcher::TouchState::~TouchState() { -} - -void InputDispatcher::TouchState::reset() { - down = false; - split = false; - deviceId = -1; - source = 0; - displayId = -1; - windows.clear(); -} - -void InputDispatcher::TouchState::copyFrom(const TouchState& other) { - down = other.down; - split = other.split; - deviceId = other.deviceId; - source = other.source; - displayId = other.displayId; - windows = other.windows; -} - -void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds) { - if (targetFlags & InputTarget::FLAG_SPLIT) { - split = true; - } - - for (size_t i = 0; i < windows.size(); i++) { - TouchedWindow& touchedWindow = windows.editItemAt(i); - if (touchedWindow.windowHandle == windowHandle) { - touchedWindow.targetFlags |= targetFlags; - if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { - touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS; - } - touchedWindow.pointerIds.value |= pointerIds.value; - return; - } - } - - windows.push(); - - TouchedWindow& touchedWindow = windows.editTop(); - touchedWindow.windowHandle = windowHandle; - touchedWindow.targetFlags = targetFlags; - touchedWindow.pointerIds = pointerIds; -} - -void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) { - for (size_t i = 0; i < windows.size(); i++) { - if (windows.itemAt(i).windowHandle == windowHandle) { - windows.removeAt(i); - return; - } - } -} - -void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { - for (size_t i = 0 ; i < windows.size(); ) { - TouchedWindow& window = windows.editItemAt(i); - if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS - | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) { - window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK; - window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS; - i += 1; - } else { - windows.removeAt(i); - } - } -} - -sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const { - for (size_t i = 0; i < windows.size(); i++) { - const TouchedWindow& window = windows.itemAt(i); - if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - return window.windowHandle; - } - } - return NULL; -} - -bool InputDispatcher::TouchState::isSlippery() const { - // Must have exactly one foreground window. - bool haveSlipperyForegroundWindow = false; - for (size_t i = 0; i < windows.size(); i++) { - const TouchedWindow& window = windows.itemAt(i); - if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - if (haveSlipperyForegroundWindow - || !(window.windowHandle->getInfo()->layoutParamsFlags - & InputWindowInfo::FLAG_SLIPPERY)) { - return false; - } - haveSlipperyForegroundWindow = true; - } - } - return haveSlipperyForegroundWindow; -} - - -// --- InputDispatcherThread --- - -InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) : - Thread(/*canCallJava*/ true), mDispatcher(dispatcher) { -} - -InputDispatcherThread::~InputDispatcherThread() { -} - -bool InputDispatcherThread::threadLoop() { - mDispatcher->dispatchOnce(); - return true; -} - -} // namespace android diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h deleted file mode 100644 index 190e7b2..0000000 --- a/services/input/InputDispatcher.h +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_DISPATCHER_H -#define _UI_INPUT_DISPATCHER_H - -#include <input/Input.h> -#include <input/InputTransport.h> -#include <utils/KeyedVector.h> -#include <utils/Vector.h> -#include <utils/threads.h> -#include <utils/Timers.h> -#include <utils/RefBase.h> -#include <utils/String8.h> -#include <utils/Looper.h> -#include <utils/BitSet.h> -#include <cutils/atomic.h> - -#include <stddef.h> -#include <unistd.h> -#include <limits.h> - -#include "InputWindow.h" -#include "InputApplication.h" -#include "InputListener.h" - - -namespace android { - -/* - * Constants used to report the outcome of input event injection. - */ -enum { - /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */ - INPUT_EVENT_INJECTION_PENDING = -1, - - /* Injection succeeded. */ - INPUT_EVENT_INJECTION_SUCCEEDED = 0, - - /* Injection failed because the injector did not have permission to inject - * into the application with input focus. */ - INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1, - - /* Injection failed because there were no available input targets. */ - INPUT_EVENT_INJECTION_FAILED = 2, - - /* Injection failed due to a timeout. */ - INPUT_EVENT_INJECTION_TIMED_OUT = 3 -}; - -/* - * Constants used to determine the input event injection synchronization mode. - */ -enum { - /* Injection is asynchronous and is assumed always to be successful. */ - INPUT_EVENT_INJECTION_SYNC_NONE = 0, - - /* Waits for previous events to be dispatched so that the input dispatcher can determine - * whether input event injection willbe permitted based on the current input focus. - * Does not wait for the input event to finish processing. */ - INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1, - - /* Waits for the input event to be completely processed. */ - INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2, -}; - - -/* - * An input target specifies how an input event is to be dispatched to a particular window - * including the window's input channel, control flags, a timeout, and an X / Y offset to - * be added to input event coordinates to compensate for the absolute position of the - * window area. - */ -struct InputTarget { - enum { - /* This flag indicates that the event is being delivered to a foreground application. */ - FLAG_FOREGROUND = 1 << 0, - - /* This flag indicates that the target of a MotionEvent is partly or wholly - * obscured by another visible window above it. The motion event should be - * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ - FLAG_WINDOW_IS_OBSCURED = 1 << 1, - - /* This flag indicates that a motion event is being split across multiple windows. */ - FLAG_SPLIT = 1 << 2, - - /* This flag indicates that the pointer coordinates dispatched to the application - * will be zeroed out to avoid revealing information to an application. This is - * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing - * the same UID from watching all touches. */ - FLAG_ZERO_COORDS = 1 << 3, - - /* This flag indicates that the event should be sent as is. - * Should always be set unless the event is to be transmuted. */ - FLAG_DISPATCH_AS_IS = 1 << 8, - - /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside - * of the area of this target and so should instead be delivered as an - * AMOTION_EVENT_ACTION_OUTSIDE to this target. */ - FLAG_DISPATCH_AS_OUTSIDE = 1 << 9, - - /* This flag indicates that a hover sequence is starting in the given window. - * The event is transmuted into ACTION_HOVER_ENTER. */ - FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10, - - /* This flag indicates that a hover event happened outside of a window which handled - * previous hover events, signifying the end of the current hover sequence for that - * window. - * The event is transmuted into ACTION_HOVER_ENTER. */ - FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11, - - /* This flag indicates that the event should be canceled. - * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips - * outside of a window. */ - FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12, - - /* This flag indicates that the event should be dispatched as an initial down. - * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips - * into a new window. */ - FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13, - - /* Mask for all dispatch modes. */ - FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS - | FLAG_DISPATCH_AS_OUTSIDE - | FLAG_DISPATCH_AS_HOVER_ENTER - | FLAG_DISPATCH_AS_HOVER_EXIT - | FLAG_DISPATCH_AS_SLIPPERY_EXIT - | FLAG_DISPATCH_AS_SLIPPERY_ENTER, - }; - - // The input channel to be targeted. - sp<InputChannel> inputChannel; - - // Flags for the input target. - int32_t flags; - - // The x and y offset to add to a MotionEvent as it is delivered. - // (ignored for KeyEvents) - float xOffset, yOffset; - - // Scaling factor to apply to MotionEvent as it is delivered. - // (ignored for KeyEvents) - float scaleFactor; - - // The subset of pointer ids to include in motion events dispatched to this input target - // if FLAG_SPLIT is set. - BitSet32 pointerIds; -}; - - -/* - * Input dispatcher configuration. - * - * Specifies various options that modify the behavior of the input dispatcher. - * The values provided here are merely defaults. The actual values will come from ViewConfiguration - * and are passed into the dispatcher during initialization. - */ -struct InputDispatcherConfiguration { - // The key repeat initial timeout. - nsecs_t keyRepeatTimeout; - - // The key repeat inter-key delay. - nsecs_t keyRepeatDelay; - - InputDispatcherConfiguration() : - keyRepeatTimeout(500 * 1000000LL), - keyRepeatDelay(50 * 1000000LL) { } -}; - - -/* - * Input dispatcher policy interface. - * - * The input reader policy is used by the input reader to interact with the Window Manager - * and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - */ -class InputDispatcherPolicyInterface : public virtual RefBase { -protected: - InputDispatcherPolicyInterface() { } - virtual ~InputDispatcherPolicyInterface() { } - -public: - /* Notifies the system that a configuration change has occurred. */ - virtual void notifyConfigurationChanged(nsecs_t when) = 0; - - /* Notifies the system that an application is not responding. - * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ - virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputWindowHandle>& inputWindowHandle, - const String8& reason) = 0; - - /* Notifies the system that an input channel is unrecoverably broken. */ - virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0; - - /* Gets the input dispatcher configuration. */ - virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; - - /* Returns true if automatic key repeating is enabled. */ - virtual bool isKeyRepeatEnabled() = 0; - - /* Filters an input event. - * Return true to dispatch the event unmodified, false to consume the event. - * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED - * to injectInputEvent. - */ - virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0; - - /* Intercepts a key event immediately before queueing it. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event - * should be dispatched to applications. - */ - virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0; - - /* Intercepts a touch, trackball or other motion event before queueing it. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event - * should be dispatched to applications. - */ - virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; - - /* Allows the policy a chance to intercept a key before dispatching. */ - virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, - const KeyEvent* keyEvent, uint32_t policyFlags) = 0; - - /* Allows the policy a chance to perform default processing for an unhandled key. - * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */ - virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, - const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0; - - /* Notifies the policy about switch events. - */ - virtual void notifySwitch(nsecs_t when, - uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) = 0; - - /* Poke user activity for an event dispatched to a window. */ - virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0; - - /* Checks whether a given application pid/uid has permission to inject input events - * into other applications. - * - * This method is special in that its implementation promises to be non-reentrant and - * is safe to call while holding other locks. (Most other methods make no such guarantees!) - */ - virtual bool checkInjectEventsPermissionNonReentrant( - int32_t injectorPid, int32_t injectorUid) = 0; -}; - - -/* Notifies the system about input events generated by the input reader. - * The dispatcher is expected to be mostly asynchronous. */ -class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface { -protected: - InputDispatcherInterface() { } - virtual ~InputDispatcherInterface() { } - -public: - /* Dumps the state of the input dispatcher. - * - * This method may be called on any thread (usually by the input manager). */ - virtual void dump(String8& dump) = 0; - - /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */ - virtual void monitor() = 0; - - /* Runs a single iteration of the dispatch loop. - * Nominally processes one queued event, a timeout, or a response from an input consumer. - * - * This method should only be called on the input dispatcher thread. - */ - virtual void dispatchOnce() = 0; - - /* Injects an input event and optionally waits for sync. - * The synchronization mode determines whether the method blocks while waiting for - * input injection to proceed. - * Returns one of the INPUT_EVENT_INJECTION_XXX constants. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual int32_t injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) = 0; - - /* Sets the list of input windows. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0; - - /* Sets the focused application. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setFocusedApplication( - const sp<InputApplicationHandle>& inputApplicationHandle) = 0; - - /* Sets the input dispatching mode. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setInputDispatchMode(bool enabled, bool frozen) = 0; - - /* Sets whether input event filtering is enabled. - * When enabled, incoming input events are sent to the policy's filterInputEvent - * method instead of being dispatched. The filter is expected to use - * injectInputEvent to inject the events it would like to have dispatched. - * It should include POLICY_FLAG_FILTERED in the policy flags during injection. - */ - virtual void setInputFilterEnabled(bool enabled) = 0; - - /* Transfers touch focus from the window associated with one channel to the - * window associated with the other channel. - * - * Returns true on success. False if the window did not actually have touch focus. - */ - virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel, - const sp<InputChannel>& toChannel) = 0; - - /* Registers or unregister input channels that may be used as targets for input events. - * If monitor is true, the channel will receive a copy of all input events. - * - * These methods may be called on any thread (usually by the input manager). - */ - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor) = 0; - virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; -}; - -/* Dispatches events to input targets. Some functions of the input dispatcher, such as - * identifying input targets, are controlled by a separate policy object. - * - * IMPORTANT INVARIANT: - * Because the policy can potentially block or cause re-entrance into the input dispatcher, - * the input dispatcher never calls into the policy while holding its internal locks. - * The implementation is also carefully designed to recover from scenarios such as an - * input channel becoming unregistered while identifying input targets or processing timeouts. - * - * Methods marked 'Locked' must be called with the lock acquired. - * - * Methods marked 'LockedInterruptible' must be called with the lock acquired but - * may during the course of their execution release the lock, call into the policy, and - * then reacquire the lock. The caller is responsible for recovering gracefully. - * - * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. - */ -class InputDispatcher : public InputDispatcherInterface { -protected: - virtual ~InputDispatcher(); - -public: - explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); - - virtual void dump(String8& dump); - virtual void monitor(); - - virtual void dispatchOnce(); - - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); - virtual void notifyKey(const NotifyKeyArgs* args); - virtual void notifyMotion(const NotifyMotionArgs* args); - virtual void notifySwitch(const NotifySwitchArgs* args); - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); - - virtual int32_t injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags); - - virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles); - virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle); - virtual void setInputDispatchMode(bool enabled, bool frozen); - virtual void setInputFilterEnabled(bool enabled); - - virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel, - const sp<InputChannel>& toChannel); - - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor); - virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); - -private: - template <typename T> - struct Link { - T* next; - T* prev; - - protected: - inline Link() : next(NULL), prev(NULL) { } - }; - - struct InjectionState { - mutable int32_t refCount; - - int32_t injectorPid; - int32_t injectorUid; - int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING - bool injectionIsAsync; // set to true if injection is not waiting for the result - int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress - - InjectionState(int32_t injectorPid, int32_t injectorUid); - void release(); - - private: - ~InjectionState(); - }; - - struct EventEntry : Link<EventEntry> { - enum { - TYPE_CONFIGURATION_CHANGED, - TYPE_DEVICE_RESET, - TYPE_KEY, - TYPE_MOTION - }; - - mutable int32_t refCount; - int32_t type; - nsecs_t eventTime; - uint32_t policyFlags; - InjectionState* injectionState; - - bool dispatchInProgress; // initially false, set to true while dispatching - - inline bool isInjected() const { return injectionState != NULL; } - - void release(); - - virtual void appendDescription(String8& msg) const = 0; - - protected: - EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags); - virtual ~EventEntry(); - void releaseInjectionState(); - }; - - struct ConfigurationChangedEntry : EventEntry { - ConfigurationChangedEntry(nsecs_t eventTime); - virtual void appendDescription(String8& msg) const; - - protected: - virtual ~ConfigurationChangedEntry(); - }; - - struct DeviceResetEntry : EventEntry { - int32_t deviceId; - - DeviceResetEntry(nsecs_t eventTime, int32_t deviceId); - virtual void appendDescription(String8& msg) const; - - protected: - virtual ~DeviceResetEntry(); - }; - - struct KeyEntry : EventEntry { - int32_t deviceId; - uint32_t source; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - int32_t repeatCount; - nsecs_t downTime; - - bool syntheticRepeat; // set to true for synthetic key repeats - - enum InterceptKeyResult { - INTERCEPT_KEY_RESULT_UNKNOWN, - INTERCEPT_KEY_RESULT_SKIP, - INTERCEPT_KEY_RESULT_CONTINUE, - INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER, - }; - InterceptKeyResult interceptKeyResult; // set based on the interception result - nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER - - KeyEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - int32_t repeatCount, nsecs_t downTime); - virtual void appendDescription(String8& msg) const; - void recycle(); - - protected: - virtual ~KeyEntry(); - }; - - struct MotionEntry : EventEntry { - nsecs_t eventTime; - int32_t deviceId; - uint32_t source; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t buttonState; - int32_t edgeFlags; - float xPrecision; - float yPrecision; - nsecs_t downTime; - int32_t displayId; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - - MotionEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, - int32_t metaState, int32_t buttonState, int32_t edgeFlags, - float xPrecision, float yPrecision, - nsecs_t downTime, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); - virtual void appendDescription(String8& msg) const; - - protected: - virtual ~MotionEntry(); - }; - - // Tracks the progress of dispatching a particular event to a particular connection. - struct DispatchEntry : Link<DispatchEntry> { - const uint32_t seq; // unique sequence number, never 0 - - EventEntry* eventEntry; // the event to dispatch - int32_t targetFlags; - float xOffset; - float yOffset; - float scaleFactor; - nsecs_t deliveryTime; // time when the event was actually delivered - - // Set to the resolved action and flags when the event is enqueued. - int32_t resolvedAction; - int32_t resolvedFlags; - - DispatchEntry(EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float scaleFactor); - ~DispatchEntry(); - - inline bool hasForegroundTarget() const { - return targetFlags & InputTarget::FLAG_FOREGROUND; - } - - inline bool isSplit() const { - return targetFlags & InputTarget::FLAG_SPLIT; - } - - private: - static volatile int32_t sNextSeqAtomic; - - static uint32_t nextSeq(); - }; - - // A command entry captures state and behavior for an action to be performed in the - // dispatch loop after the initial processing has taken place. It is essentially - // a kind of continuation used to postpone sensitive policy interactions to a point - // in the dispatch loop where it is safe to release the lock (generally after finishing - // the critical parts of the dispatch cycle). - // - // The special thing about commands is that they can voluntarily release and reacquire - // the dispatcher lock at will. Initially when the command starts running, the - // dispatcher lock is held. However, if the command needs to call into the policy to - // do some work, it can release the lock, do the work, then reacquire the lock again - // before returning. - // - // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch - // never calls into the policy while holding its lock. - // - // Commands are implicitly 'LockedInterruptible'. - struct CommandEntry; - typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry); - - class Connection; - struct CommandEntry : Link<CommandEntry> { - CommandEntry(Command command); - ~CommandEntry(); - - Command command; - - // parameters for the command (usage varies by command) - sp<Connection> connection; - nsecs_t eventTime; - KeyEntry* keyEntry; - sp<InputApplicationHandle> inputApplicationHandle; - sp<InputWindowHandle> inputWindowHandle; - String8 reason; - int32_t userActivityEventType; - uint32_t seq; - bool handled; - }; - - // Generic queue implementation. - template <typename T> - struct Queue { - T* head; - T* tail; - - inline Queue() : head(NULL), tail(NULL) { - } - - inline bool isEmpty() const { - return !head; - } - - inline void enqueueAtTail(T* entry) { - entry->prev = tail; - if (tail) { - tail->next = entry; - } else { - head = entry; - } - entry->next = NULL; - tail = entry; - } - - inline void enqueueAtHead(T* entry) { - entry->next = head; - if (head) { - head->prev = entry; - } else { - tail = entry; - } - entry->prev = NULL; - head = entry; - } - - inline void dequeue(T* entry) { - if (entry->prev) { - entry->prev->next = entry->next; - } else { - head = entry->next; - } - if (entry->next) { - entry->next->prev = entry->prev; - } else { - tail = entry->prev; - } - } - - inline T* dequeueAtHead() { - T* entry = head; - head = entry->next; - if (head) { - head->prev = NULL; - } else { - tail = NULL; - } - return entry; - } - - uint32_t count() const; - }; - - /* Specifies which events are to be canceled and why. */ - struct CancelationOptions { - enum Mode { - CANCEL_ALL_EVENTS = 0, - CANCEL_POINTER_EVENTS = 1, - CANCEL_NON_POINTER_EVENTS = 2, - CANCEL_FALLBACK_EVENTS = 3, - }; - - // The criterion to use to determine which events should be canceled. - Mode mode; - - // Descriptive reason for the cancelation. - const char* reason; - - // The specific keycode of the key event to cancel, or -1 to cancel any key event. - int32_t keyCode; - - // The specific device id of events to cancel, or -1 to cancel events from any device. - int32_t deviceId; - - CancelationOptions(Mode mode, const char* reason) : - mode(mode), reason(reason), keyCode(-1), deviceId(-1) { } - }; - - /* Tracks dispatched key and motion event state so that cancelation events can be - * synthesized when events are dropped. */ - class InputState { - public: - InputState(); - ~InputState(); - - // Returns true if there is no state to be canceled. - bool isNeutral() const; - - // Returns true if the specified source is known to have received a hover enter - // motion event. - bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const; - - // Records tracking information for a key event that has just been published. - // Returns true if the event should be delivered, false if it is inconsistent - // and should be skipped. - bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags); - - // Records tracking information for a motion event that has just been published. - // Returns true if the event should be delivered, false if it is inconsistent - // and should be skipped. - bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags); - - // Synthesizes cancelation events for the current state and resets the tracked state. - void synthesizeCancelationEvents(nsecs_t currentTime, - Vector<EventEntry*>& outEvents, const CancelationOptions& options); - - // Clears the current state. - void clear(); - - // Copies pointer-related parts of the input state to another instance. - void copyPointerStateTo(InputState& other) const; - - // Gets the fallback key associated with a keycode. - // Returns -1 if none. - // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy. - int32_t getFallbackKey(int32_t originalKeyCode); - - // Sets the fallback key for a particular keycode. - void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode); - - // Removes the fallback key for a particular keycode. - void removeFallbackKey(int32_t originalKeyCode); - - inline const KeyedVector<int32_t, int32_t>& getFallbackKeys() const { - return mFallbackKeys; - } - - private: - struct KeyMemento { - int32_t deviceId; - uint32_t source; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - int32_t flags; - nsecs_t downTime; - uint32_t policyFlags; - }; - - struct MotionMemento { - int32_t deviceId; - uint32_t source; - int32_t flags; - float xPrecision; - float yPrecision; - nsecs_t downTime; - int32_t displayId; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - bool hovering; - uint32_t policyFlags; - - void setPointers(const MotionEntry* entry); - }; - - Vector<KeyMemento> mKeyMementos; - Vector<MotionMemento> mMotionMementos; - KeyedVector<int32_t, int32_t> mFallbackKeys; - - ssize_t findKeyMemento(const KeyEntry* entry) const; - ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const; - - void addKeyMemento(const KeyEntry* entry, int32_t flags); - void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering); - - static bool shouldCancelKey(const KeyMemento& memento, - const CancelationOptions& options); - static bool shouldCancelMotion(const MotionMemento& memento, - const CancelationOptions& options); - }; - - /* Manages the dispatch state associated with a single input channel. */ - class Connection : public RefBase { - protected: - virtual ~Connection(); - - public: - enum Status { - // Everything is peachy. - STATUS_NORMAL, - // An unrecoverable communication error has occurred. - STATUS_BROKEN, - // The input channel has been unregistered. - STATUS_ZOMBIE - }; - - Status status; - sp<InputChannel> inputChannel; // never null - sp<InputWindowHandle> inputWindowHandle; // may be null - bool monitor; - InputPublisher inputPublisher; - InputState inputState; - - // True if the socket is full and no further events can be published until - // the application consumes some of the input. - bool inputPublisherBlocked; - - // Queue of events that need to be published to the connection. - Queue<DispatchEntry> outboundQueue; - - // Queue of events that have been published to the connection but that have not - // yet received a "finished" response from the application. - Queue<DispatchEntry> waitQueue; - - explicit Connection(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor); - - inline const char* getInputChannelName() const { return inputChannel->getName().string(); } - - const char* getWindowName() const; - const char* getStatusLabel() const; - - DispatchEntry* findWaitQueueEntry(uint32_t seq); - }; - - enum DropReason { - DROP_REASON_NOT_DROPPED = 0, - DROP_REASON_POLICY = 1, - DROP_REASON_APP_SWITCH = 2, - DROP_REASON_DISABLED = 3, - DROP_REASON_BLOCKED = 4, - DROP_REASON_STALE = 5, - }; - - sp<InputDispatcherPolicyInterface> mPolicy; - InputDispatcherConfiguration mConfig; - - Mutex mLock; - - Condition mDispatcherIsAliveCondition; - - sp<Looper> mLooper; - - EventEntry* mPendingEvent; - Queue<EventEntry> mInboundQueue; - Queue<EventEntry> mRecentQueue; - Queue<CommandEntry> mCommandQueue; - - void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime); - - // Enqueues an inbound event. Returns true if mLooper->wake() should be called. - bool enqueueInboundEventLocked(EventEntry* entry); - - // Cleans up input state when dropping an inbound event. - void dropInboundEventLocked(EventEntry* entry, DropReason dropReason); - - // Adds an event to a queue of recent events for debugging purposes. - void addRecentEventLocked(EventEntry* entry); - - // App switch latency optimization. - bool mAppSwitchSawKeyDown; - nsecs_t mAppSwitchDueTime; - - static bool isAppSwitchKeyCode(int32_t keyCode); - bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry); - bool isAppSwitchPendingLocked(); - void resetPendingAppSwitchLocked(bool handled); - - // Stale event latency optimization. - static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry); - - // Blocked event latency optimization. Drops old events when the user intends - // to transfer focus to a new application. - EventEntry* mNextUnblockedEvent; - - sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y); - - // All registered connections mapped by channel file descriptor. - KeyedVector<int, sp<Connection> > mConnectionsByFd; - - ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel); - - // Input channels that will receive a copy of all input events. - Vector<sp<InputChannel> > mMonitoringChannels; - - // Event injection and synchronization. - Condition mInjectionResultAvailableCondition; - bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); - void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult); - - Condition mInjectionSyncFinishedCondition; - void incrementPendingForegroundDispatchesLocked(EventEntry* entry); - void decrementPendingForegroundDispatchesLocked(EventEntry* entry); - - // Key repeat tracking. - struct KeyRepeatState { - KeyEntry* lastKeyEntry; // or null if no repeat - nsecs_t nextRepeatTime; - } mKeyRepeatState; - - void resetKeyRepeatLocked(); - KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime); - - // Deferred command processing. - bool haveCommandsLocked() const; - bool runCommandsLockedInterruptible(); - CommandEntry* postCommandLocked(Command command); - - // Input filter processing. - bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args); - bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args); - - // Inbound event processing. - void drainInboundQueueLocked(); - void releasePendingEventLocked(); - void releaseInboundEventLocked(EventEntry* entry); - - // Dispatch state. - bool mDispatchEnabled; - bool mDispatchFrozen; - bool mInputFilterEnabled; - - Vector<sp<InputWindowHandle> > mWindowHandles; - - sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const; - bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const; - - // Focus tracking for keys, trackball, etc. - sp<InputWindowHandle> mFocusedWindowHandle; - - // Focus tracking for touch. - struct TouchedWindow { - sp<InputWindowHandle> windowHandle; - int32_t targetFlags; - BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set - }; - struct TouchState { - bool down; - bool split; - int32_t deviceId; // id of the device that is currently down, others are rejected - uint32_t source; // source of the device that is current down, others are rejected - int32_t displayId; // id to the display that currently has a touch, others are rejected - Vector<TouchedWindow> windows; - - TouchState(); - ~TouchState(); - void reset(); - void copyFrom(const TouchState& other); - void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds); - void removeWindow(const sp<InputWindowHandle>& windowHandle); - void filterNonAsIsTouchWindows(); - sp<InputWindowHandle> getFirstForegroundWindowHandle() const; - bool isSlippery() const; - }; - - TouchState mTouchState; - TouchState mTempTouchState; - - // Focused application. - sp<InputApplicationHandle> mFocusedApplicationHandle; - - // Dispatcher state at time of last ANR. - String8 mLastANRState; - - // Dispatch inbound events. - bool dispatchConfigurationChangedLocked( - nsecs_t currentTime, ConfigurationChangedEntry* entry); - bool dispatchDeviceResetLocked( - nsecs_t currentTime, DeviceResetEntry* entry); - bool dispatchKeyLocked( - nsecs_t currentTime, KeyEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime); - bool dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime); - void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry, - const Vector<InputTarget>& inputTargets); - - void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry); - void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry); - - // Keeping track of ANR timeouts. - enum InputTargetWaitCause { - INPUT_TARGET_WAIT_CAUSE_NONE, - INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, - INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY, - }; - - InputTargetWaitCause mInputTargetWaitCause; - nsecs_t mInputTargetWaitStartTime; - nsecs_t mInputTargetWaitTimeoutTime; - bool mInputTargetWaitTimeoutExpired; - sp<InputApplicationHandle> mInputTargetWaitApplicationHandle; - - // Contains the last window which received a hover event. - sp<InputWindowHandle> mLastHoverWindowHandle; - - // Finding targets for input events. - int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, - const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t* nextWakeupTime, const char* reason); - void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp<InputChannel>& inputChannel); - nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime); - void resetANRTimeoutsLocked(); - - int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, - Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime); - int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, - Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions); - - void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets); - void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets); - - void pokeUserActivityLocked(const EventEntry* eventEntry); - bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, - const InjectionState* injectionState); - bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, - int32_t x, int32_t y) const; - bool isWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry); - String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle); - - // Manage the dispatch cycle for a single connection. - // These methods are deliberately not Interruptible because doing all of the work - // with the mutex held makes it easier to ensure that connection invariants are maintained. - // If needed, the methods post commands to run later once the critical bits are done. - void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget); - void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget); - void enqueueDispatchEntryLocked(const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode); - void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); - void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - uint32_t seq, bool handled); - void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - bool notify); - void drainDispatchQueueLocked(Queue<DispatchEntry>* queue); - void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry); - static int handleReceiveCallback(int fd, int events, void* data); - - void synthesizeCancelationEventsForAllConnectionsLocked( - const CancelationOptions& options); - void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, - const CancelationOptions& options); - void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, - const CancelationOptions& options); - - // Splitting motion events across windows. - MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); - - // Reset and drop everything the dispatcher is doing. - void resetAndDropEverythingLocked(const char* reason); - - // Dump state. - void dumpDispatchStateLocked(String8& dump); - void logDispatchStateLocked(); - - // Registration. - void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel); - status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify); - - // Add or remove a connection to the mActiveConnections vector. - void activateConnectionLocked(Connection* connection); - void deactivateConnectionLocked(Connection* connection); - - // Interesting events that we might like to log or tell the framework about. - void onDispatchCycleFinishedLocked( - nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled); - void onDispatchCycleBrokenLocked( - nsecs_t currentTime, const sp<Connection>& connection); - void onANRLocked( - nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t eventTime, nsecs_t waitStartTime, const char* reason); - - // Outbound policy interactions. - void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry); - void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry); - void doNotifyANRLockedInterruptible(CommandEntry* commandEntry); - void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry); - void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry); - bool afterKeyEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled); - bool afterMotionEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled); - void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry); - void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); - - // Statistics gathering. - void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); - void traceInboundQueueLengthLocked(); - void traceOutboundQueueLengthLocked(const sp<Connection>& connection); - void traceWaitQueueLengthLocked(const sp<Connection>& connection); -}; - -/* Enqueues and dispatches input events, endlessly. */ -class InputDispatcherThread : public Thread { -public: - explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher); - ~InputDispatcherThread(); - -private: - virtual bool threadLoop(); - - sp<InputDispatcherInterface> mDispatcher; -}; - -} // namespace android - -#endif // _UI_INPUT_DISPATCHER_H diff --git a/services/input/InputListener.cpp b/services/input/InputListener.cpp deleted file mode 100644 index 85bb0ed..0000000 --- a/services/input/InputListener.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "InputListener" - -//#define LOG_NDEBUG 0 - -#include "InputListener.h" - -#include <cutils/log.h> - -namespace android { - -// --- NotifyConfigurationChangedArgs --- - -NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(nsecs_t eventTime) : - eventTime(eventTime) { -} - -NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs( - const NotifyConfigurationChangedArgs& other) : - eventTime(other.eventTime) { -} - -void NotifyConfigurationChangedArgs::notify(const sp<InputListenerInterface>& listener) const { - listener->notifyConfigurationChanged(this); -} - - -// --- NotifyKeyArgs --- - -NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, - uint32_t policyFlags, - int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, - int32_t metaState, nsecs_t downTime) : - eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), - action(action), flags(flags), keyCode(keyCode), scanCode(scanCode), - metaState(metaState), downTime(downTime) { -} - -NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) : - eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), - policyFlags(other.policyFlags), - action(other.action), flags(other.flags), - keyCode(other.keyCode), scanCode(other.scanCode), - metaState(other.metaState), downTime(other.downTime) { -} - -void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const { - listener->notifyKey(this); -} - - -// --- NotifyMotionArgs --- - -NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, - uint32_t policyFlags, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime) : - eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), - action(action), flags(flags), metaState(metaState), buttonState(buttonState), - edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount), - xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) { - for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties[i].copyFrom(pointerProperties[i]); - this->pointerCoords[i].copyFrom(pointerCoords[i]); - } -} - -NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : - eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), - policyFlags(other.policyFlags), - action(other.action), flags(other.flags), - metaState(other.metaState), buttonState(other.buttonState), - edgeFlags(other.edgeFlags), displayId(other.displayId), - pointerCount(other.pointerCount), - xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) { - for (uint32_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(other.pointerProperties[i]); - pointerCoords[i].copyFrom(other.pointerCoords[i]); - } -} - -void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const { - listener->notifyMotion(this); -} - - -// --- NotifySwitchArgs --- - -NotifySwitchArgs::NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags, - uint32_t switchValues, uint32_t switchMask) : - eventTime(eventTime), policyFlags(policyFlags), - switchValues(switchValues), switchMask(switchMask) { -} - -NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) : - eventTime(other.eventTime), policyFlags(other.policyFlags), - switchValues(other.switchValues), switchMask(other.switchMask) { -} - -void NotifySwitchArgs::notify(const sp<InputListenerInterface>& listener) const { - listener->notifySwitch(this); -} - - -// --- NotifyDeviceResetArgs --- - -NotifyDeviceResetArgs::NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId) : - eventTime(eventTime), deviceId(deviceId) { -} - -NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) : - eventTime(other.eventTime), deviceId(other.deviceId) { -} - -void NotifyDeviceResetArgs::notify(const sp<InputListenerInterface>& listener) const { - listener->notifyDeviceReset(this); -} - - -// --- QueuedInputListener --- - -QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) : - mInnerListener(innerListener) { -} - -QueuedInputListener::~QueuedInputListener() { - size_t count = mArgsQueue.size(); - for (size_t i = 0; i < count; i++) { - delete mArgsQueue[i]; - } -} - -void QueuedInputListener::notifyConfigurationChanged( - const NotifyConfigurationChangedArgs* args) { - mArgsQueue.push(new NotifyConfigurationChangedArgs(*args)); -} - -void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) { - mArgsQueue.push(new NotifyKeyArgs(*args)); -} - -void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { - mArgsQueue.push(new NotifyMotionArgs(*args)); -} - -void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) { - mArgsQueue.push(new NotifySwitchArgs(*args)); -} - -void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { - mArgsQueue.push(new NotifyDeviceResetArgs(*args)); -} - -void QueuedInputListener::flush() { - size_t count = mArgsQueue.size(); - for (size_t i = 0; i < count; i++) { - NotifyArgs* args = mArgsQueue[i]; - args->notify(mInnerListener); - delete args; - } - mArgsQueue.clear(); -} - - -} // namespace android diff --git a/services/input/InputListener.h b/services/input/InputListener.h deleted file mode 100644 index 78ae10f..0000000 --- a/services/input/InputListener.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_LISTENER_H -#define _UI_INPUT_LISTENER_H - -#include <input/Input.h> -#include <utils/RefBase.h> -#include <utils/Vector.h> - -namespace android { - -class InputListenerInterface; - - -/* Superclass of all input event argument objects */ -struct NotifyArgs { - virtual ~NotifyArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const = 0; -}; - - -/* Describes a configuration change event. */ -struct NotifyConfigurationChangedArgs : public NotifyArgs { - nsecs_t eventTime; - - inline NotifyConfigurationChangedArgs() { } - - NotifyConfigurationChangedArgs(nsecs_t eventTime); - - NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other); - - virtual ~NotifyConfigurationChangedArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const; -}; - - -/* Describes a key event. */ -struct NotifyKeyArgs : public NotifyArgs { - nsecs_t eventTime; - int32_t deviceId; - uint32_t source; - uint32_t policyFlags; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - nsecs_t downTime; - - inline NotifyKeyArgs() { } - - NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, - int32_t metaState, nsecs_t downTime); - - NotifyKeyArgs(const NotifyKeyArgs& other); - - virtual ~NotifyKeyArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const; -}; - - -/* Describes a motion event. */ -struct NotifyMotionArgs : public NotifyArgs { - nsecs_t eventTime; - int32_t deviceId; - uint32_t source; - uint32_t policyFlags; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t buttonState; - int32_t edgeFlags; - int32_t displayId; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - float xPrecision; - float yPrecision; - nsecs_t downTime; - - inline NotifyMotionArgs() { } - - NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime); - - NotifyMotionArgs(const NotifyMotionArgs& other); - - virtual ~NotifyMotionArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const; -}; - - -/* Describes a switch event. */ -struct NotifySwitchArgs : public NotifyArgs { - nsecs_t eventTime; - uint32_t policyFlags; - uint32_t switchValues; - uint32_t switchMask; - - inline NotifySwitchArgs() { } - - NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags, - uint32_t switchValues, uint32_t switchMask); - - NotifySwitchArgs(const NotifySwitchArgs& other); - - virtual ~NotifySwitchArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const; -}; - - -/* Describes a device reset event, such as when a device is added, - * reconfigured, or removed. */ -struct NotifyDeviceResetArgs : public NotifyArgs { - nsecs_t eventTime; - int32_t deviceId; - - inline NotifyDeviceResetArgs() { } - - NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId); - - NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other); - - virtual ~NotifyDeviceResetArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const; -}; - - -/* - * The interface used by the InputReader to notify the InputListener about input events. - */ -class InputListenerInterface : public virtual RefBase { -protected: - InputListenerInterface() { } - virtual ~InputListenerInterface() { } - -public: - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0; - virtual void notifyKey(const NotifyKeyArgs* args) = 0; - virtual void notifyMotion(const NotifyMotionArgs* args) = 0; - virtual void notifySwitch(const NotifySwitchArgs* args) = 0; - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0; -}; - - -/* - * An implementation of the listener interface that queues up and defers dispatch - * of decoded events until flushed. - */ -class QueuedInputListener : public InputListenerInterface { -protected: - virtual ~QueuedInputListener(); - -public: - QueuedInputListener(const sp<InputListenerInterface>& innerListener); - - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); - virtual void notifyKey(const NotifyKeyArgs* args); - virtual void notifyMotion(const NotifyMotionArgs* args); - virtual void notifySwitch(const NotifySwitchArgs* args); - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); - - void flush(); - -private: - sp<InputListenerInterface> mInnerListener; - Vector<NotifyArgs*> mArgsQueue; -}; - -} // namespace android - -#endif // _UI_INPUT_LISTENER_H diff --git a/services/input/InputManager.cpp b/services/input/InputManager.cpp deleted file mode 100644 index 6a6547b..0000000 --- a/services/input/InputManager.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "InputManager" - -//#define LOG_NDEBUG 0 - -#include "InputManager.h" - -#include <cutils/log.h> - -namespace android { - -InputManager::InputManager( - const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& readerPolicy, - const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { - mDispatcher = new InputDispatcher(dispatcherPolicy); - mReader = new InputReader(eventHub, readerPolicy, mDispatcher); - initialize(); -} - -InputManager::InputManager( - const sp<InputReaderInterface>& reader, - const sp<InputDispatcherInterface>& dispatcher) : - mReader(reader), - mDispatcher(dispatcher) { - initialize(); -} - -InputManager::~InputManager() { - stop(); -} - -void InputManager::initialize() { - mReaderThread = new InputReaderThread(mReader); - mDispatcherThread = new InputDispatcherThread(mDispatcher); -} - -status_t InputManager::start() { - status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); - if (result) { - ALOGE("Could not start InputDispatcher thread due to error %d.", result); - return result; - } - - result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); - if (result) { - ALOGE("Could not start InputReader thread due to error %d.", result); - - mDispatcherThread->requestExit(); - return result; - } - - return OK; -} - -status_t InputManager::stop() { - status_t result = mReaderThread->requestExitAndWait(); - if (result) { - ALOGW("Could not stop InputReader thread due to error %d.", result); - } - - result = mDispatcherThread->requestExitAndWait(); - if (result) { - ALOGW("Could not stop InputDispatcher thread due to error %d.", result); - } - - return OK; -} - -sp<InputReaderInterface> InputManager::getReader() { - return mReader; -} - -sp<InputDispatcherInterface> InputManager::getDispatcher() { - return mDispatcher; -} - -} // namespace android diff --git a/services/input/InputManager.h b/services/input/InputManager.h deleted file mode 100644 index a213b2d..0000000 --- a/services/input/InputManager.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_MANAGER_H -#define _UI_INPUT_MANAGER_H - -/** - * Native input manager. - */ - -#include "EventHub.h" -#include "InputReader.h" -#include "InputDispatcher.h" - -#include <input/Input.h> -#include <input/InputTransport.h> -#include <utils/Errors.h> -#include <utils/Vector.h> -#include <utils/Timers.h> -#include <utils/RefBase.h> -#include <utils/String8.h> - -namespace android { - -/* - * The input manager is the core of the system event processing. - * - * The input manager uses two threads. - * - * 1. The InputReaderThread (called "InputReader") reads and preprocesses raw input events, - * applies policy, and posts messages to a queue managed by the DispatcherThread. - * 2. The InputDispatcherThread (called "InputDispatcher") thread waits for new events on the - * queue and asynchronously dispatches them to applications. - * - * By design, the InputReaderThread class and InputDispatcherThread class do not share any - * internal state. Moreover, all communication is done one way from the InputReaderThread - * into the InputDispatcherThread and never the reverse. Both classes may interact with the - * InputDispatchPolicy, however. - * - * The InputManager class never makes any calls into Java itself. Instead, the - * InputDispatchPolicy is responsible for performing all external interactions with the - * system, including calling DVM services. - */ -class InputManagerInterface : public virtual RefBase { -protected: - InputManagerInterface() { } - virtual ~InputManagerInterface() { } - -public: - /* Starts the input manager threads. */ - virtual status_t start() = 0; - - /* Stops the input manager threads and waits for them to exit. */ - virtual status_t stop() = 0; - - /* Gets the input reader. */ - virtual sp<InputReaderInterface> getReader() = 0; - - /* Gets the input dispatcher. */ - virtual sp<InputDispatcherInterface> getDispatcher() = 0; -}; - -class InputManager : public InputManagerInterface { -protected: - virtual ~InputManager(); - -public: - InputManager( - const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& readerPolicy, - const sp<InputDispatcherPolicyInterface>& dispatcherPolicy); - - // (used for testing purposes) - InputManager( - const sp<InputReaderInterface>& reader, - const sp<InputDispatcherInterface>& dispatcher); - - virtual status_t start(); - virtual status_t stop(); - - virtual sp<InputReaderInterface> getReader(); - virtual sp<InputDispatcherInterface> getDispatcher(); - -private: - sp<InputReaderInterface> mReader; - sp<InputReaderThread> mReaderThread; - - sp<InputDispatcherInterface> mDispatcher; - sp<InputDispatcherThread> mDispatcherThread; - - void initialize(); -}; - -} // namespace android - -#endif // _UI_INPUT_MANAGER_H diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp deleted file mode 100644 index 03852a5..0000000 --- a/services/input/InputReader.cpp +++ /dev/null @@ -1,6530 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "InputReader" - -//#define LOG_NDEBUG 0 - -// Log debug messages for each raw event received from the EventHub. -#define DEBUG_RAW_EVENTS 0 - -// Log debug messages about touch screen filtering hacks. -#define DEBUG_HACKS 0 - -// Log debug messages about virtual key processing. -#define DEBUG_VIRTUAL_KEYS 0 - -// Log debug messages about pointers. -#define DEBUG_POINTERS 0 - -// Log debug messages about pointer assignment calculations. -#define DEBUG_POINTER_ASSIGNMENT 0 - -// Log debug messages about gesture detection. -#define DEBUG_GESTURES 0 - -// Log debug messages about the vibrator. -#define DEBUG_VIBRATOR 0 - -#include "InputReader.h" - -#include <cutils/log.h> -#include <input/Keyboard.h> -#include <input/VirtualKeyMap.h> - -#include <stddef.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <limits.h> -#include <math.h> - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " -#define INDENT4 " " -#define INDENT5 " " - -namespace android { - -// --- Constants --- - -// Maximum number of slots supported when using the slot-based Multitouch Protocol B. -static const size_t MAX_SLOTS = 32; - -// --- Static Functions --- - -template<typename T> -inline static T abs(const T& value) { - return value < 0 ? - value : value; -} - -template<typename T> -inline static T min(const T& a, const T& b) { - return a < b ? a : b; -} - -template<typename T> -inline static void swap(T& a, T& b) { - T temp = a; - a = b; - b = temp; -} - -inline static float avg(float x, float y) { - return (x + y) / 2; -} - -inline static float distance(float x1, float y1, float x2, float y2) { - return hypotf(x1 - x2, y1 - y2); -} - -inline static int32_t signExtendNybble(int32_t value) { - return value >= 8 ? value - 16 : value; -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation, - const int32_t map[][4], size_t mapSize) { - if (orientation != DISPLAY_ORIENTATION_0) { - for (size_t i = 0; i < mapSize; i++) { - if (value == map[i][0]) { - return map[i][orientation]; - } - } - } - return value; -} - -static const int32_t keyCodeRotationMap[][4] = { - // key codes enumerated counter-clockwise with the original (unrotated) key first - // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation - { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT }, - { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN }, - { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT }, - { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP }, -}; -static const size_t keyCodeRotationMapSize = - sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); - -static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { - return rotateValueUsingRotationMap(keyCode, orientation, - keyCodeRotationMap, keyCodeRotationMapSize); -} - -static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { - float temp; - switch (orientation) { - case DISPLAY_ORIENTATION_90: - temp = *deltaX; - *deltaX = *deltaY; - *deltaY = -temp; - break; - - case DISPLAY_ORIENTATION_180: - *deltaX = -*deltaX; - *deltaY = -*deltaY; - break; - - case DISPLAY_ORIENTATION_270: - temp = *deltaX; - *deltaX = -*deltaY; - *deltaY = temp; - break; - } -} - -static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { - return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0; -} - -// Returns true if the pointer should be reported as being down given the specified -// button states. This determines whether the event is reported as a touch event. -static bool isPointerDown(int32_t buttonState) { - return buttonState & - (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY - | AMOTION_EVENT_BUTTON_TERTIARY); -} - -static float calculateCommonVector(float a, float b) { - if (a > 0 && b > 0) { - return a < b ? a : b; - } else if (a < 0 && b < 0) { - return a > b ? a : b; - } else { - return 0; - } -} - -static void synthesizeButtonKey(InputReaderContext* context, int32_t action, - nsecs_t when, int32_t deviceId, uint32_t source, - uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState, - int32_t buttonState, int32_t keyCode) { - if ( - (action == AKEY_EVENT_ACTION_DOWN - && !(lastButtonState & buttonState) - && (currentButtonState & buttonState)) - || (action == AKEY_EVENT_ACTION_UP - && (lastButtonState & buttonState) - && !(currentButtonState & buttonState))) { - NotifyKeyArgs args(when, deviceId, source, policyFlags, - action, 0, keyCode, 0, context->getGlobalMetaState(), when); - context->getListener()->notifyKey(&args); - } -} - -static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, - nsecs_t when, int32_t deviceId, uint32_t source, - uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) { - synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, - lastButtonState, currentButtonState, - AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK); - synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, - lastButtonState, currentButtonState, - AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD); -} - - -// --- InputReaderConfiguration --- - -bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const { - const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay; - if (viewport.displayId >= 0) { - *outViewport = viewport; - return true; - } - return false; -} - -void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) { - DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay; - v = viewport; -} - - -// --- InputReader --- - -InputReader::InputReader(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener) : - mContext(this), mEventHub(eventHub), mPolicy(policy), - mGlobalMetaState(0), mGeneration(1), - mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), - mConfigurationChangesToRefresh(0) { - mQueuedListener = new QueuedInputListener(listener); - - { // acquire lock - AutoMutex _l(mLock); - - refreshConfigurationLocked(0); - updateGlobalMetaStateLocked(); - } // release lock -} - -InputReader::~InputReader() { - for (size_t i = 0; i < mDevices.size(); i++) { - delete mDevices.valueAt(i); - } -} - -void InputReader::loopOnce() { - int32_t oldGeneration; - int32_t timeoutMillis; - bool inputDevicesChanged = false; - Vector<InputDeviceInfo> inputDevices; - { // acquire lock - AutoMutex _l(mLock); - - oldGeneration = mGeneration; - timeoutMillis = -1; - - uint32_t changes = mConfigurationChangesToRefresh; - if (changes) { - mConfigurationChangesToRefresh = 0; - timeoutMillis = 0; - refreshConfigurationLocked(changes); - } else if (mNextTimeout != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); - } - } // release lock - - size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); - - { // acquire lock - AutoMutex _l(mLock); - mReaderIsAliveCondition.broadcast(); - - if (count) { - processEventsLocked(mEventBuffer, count); - } - - if (mNextTimeout != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (now >= mNextTimeout) { -#if DEBUG_RAW_EVENTS - ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); -#endif - mNextTimeout = LLONG_MAX; - timeoutExpiredLocked(now); - } - } - - if (oldGeneration != mGeneration) { - inputDevicesChanged = true; - getInputDevicesLocked(inputDevices); - } - } // release lock - - // Send out a message that the describes the changed input devices. - if (inputDevicesChanged) { - mPolicy->notifyInputDevicesChanged(inputDevices); - } - - // Flush queued events out to the listener. - // This must happen outside of the lock because the listener could potentially call - // back into the InputReader's methods, such as getScanCodeState, or become blocked - // on another thread similarly waiting to acquire the InputReader lock thereby - // resulting in a deadlock. This situation is actually quite plausible because the - // listener is actually the input dispatcher, which calls into the window manager, - // which occasionally calls into the input reader. - mQueuedListener->flush(); -} - -void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { - for (const RawEvent* rawEvent = rawEvents; count;) { - int32_t type = rawEvent->type; - size_t batchSize = 1; - if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { - int32_t deviceId = rawEvent->deviceId; - while (batchSize < count) { - if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT - || rawEvent[batchSize].deviceId != deviceId) { - break; - } - batchSize += 1; - } -#if DEBUG_RAW_EVENTS - ALOGD("BatchSize: %d Count: %d", batchSize, count); -#endif - processEventsForDeviceLocked(deviceId, rawEvent, batchSize); - } else { - switch (rawEvent->type) { - case EventHubInterface::DEVICE_ADDED: - addDeviceLocked(rawEvent->when, rawEvent->deviceId); - break; - case EventHubInterface::DEVICE_REMOVED: - removeDeviceLocked(rawEvent->when, rawEvent->deviceId); - break; - case EventHubInterface::FINISHED_DEVICE_SCAN: - handleConfigurationChangedLocked(rawEvent->when); - break; - default: - ALOG_ASSERT(false); // can't happen - break; - } - } - count -= batchSize; - rawEvent += batchSize; - } -} - -void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); - return; - } - - InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); - uint32_t classes = mEventHub->getDeviceClasses(deviceId); - int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId); - - InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes); - device->configure(when, &mConfig, 0); - device->reset(when); - - if (device->isIgnored()) { - ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, - identifier.name.string()); - } else { - ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, - identifier.name.string(), device->getSources()); - } - - mDevices.add(deviceId, device); - bumpGenerationLocked(); -} - -void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { - InputDevice* device = NULL; - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); - return; - } - - device = mDevices.valueAt(deviceIndex); - mDevices.removeItemsAt(deviceIndex, 1); - bumpGenerationLocked(); - - if (device->isIgnored()) { - ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", - device->getId(), device->getName().string()); - } else { - ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", - device->getId(), device->getName().string(), device->getSources()); - } - - device->reset(when); - delete device; -} - -InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, uint32_t classes) { - InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), - controllerNumber, identifier, classes); - - // External devices. - if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { - device->setExternal(true); - } - - // Switch-like devices. - if (classes & INPUT_DEVICE_CLASS_SWITCH) { - device->addMapper(new SwitchInputMapper(device)); - } - - // Vibrator-like devices. - if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { - device->addMapper(new VibratorInputMapper(device)); - } - - // Keyboard-like devices. - uint32_t keyboardSource = 0; - int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; - if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { - keyboardSource |= AINPUT_SOURCE_KEYBOARD; - } - if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { - keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; - } - if (classes & INPUT_DEVICE_CLASS_DPAD) { - keyboardSource |= AINPUT_SOURCE_DPAD; - } - if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { - keyboardSource |= AINPUT_SOURCE_GAMEPAD; - } - - if (keyboardSource != 0) { - device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); - } - - // Cursor-like devices. - if (classes & INPUT_DEVICE_CLASS_CURSOR) { - device->addMapper(new CursorInputMapper(device)); - } - - // Touchscreens and touchpad devices. - if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { - device->addMapper(new MultiTouchInputMapper(device)); - } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { - device->addMapper(new SingleTouchInputMapper(device)); - } - - // Joystick-like devices. - if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { - device->addMapper(new JoystickInputMapper(device)); - } - - return device; -} - -void InputReader::processEventsForDeviceLocked(int32_t deviceId, - const RawEvent* rawEvents, size_t count) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Discarding event for unknown deviceId %d.", deviceId); - return; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - if (device->isIgnored()) { - //ALOGD("Discarding event for ignored deviceId %d.", deviceId); - return; - } - - device->process(rawEvents, count); -} - -void InputReader::timeoutExpiredLocked(nsecs_t when) { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored()) { - device->timeoutExpired(when); - } - } -} - -void InputReader::handleConfigurationChangedLocked(nsecs_t when) { - // Reset global meta state because it depends on the list of all configured devices. - updateGlobalMetaStateLocked(); - - // Enqueue configuration changed. - NotifyConfigurationChangedArgs args(when); - mQueuedListener->notifyConfigurationChanged(&args); -} - -void InputReader::refreshConfigurationLocked(uint32_t changes) { - mPolicy->getReaderConfiguration(&mConfig); - mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); - - if (changes) { - ALOGI("Reconfiguring input devices. changes=0x%08x", changes); - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - - if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { - mEventHub->requestReopenDevices(); - } else { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->configure(now, &mConfig, changes); - } - } - } -} - -void InputReader::updateGlobalMetaStateLocked() { - mGlobalMetaState = 0; - - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - mGlobalMetaState |= device->getMetaState(); - } -} - -int32_t InputReader::getGlobalMetaStateLocked() { - return mGlobalMetaState; -} - -void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { - mDisableVirtualKeysTimeout = time; -} - -bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) { - if (now < mDisableVirtualKeysTimeout) { - ALOGI("Dropping virtual key from device %s because virtual keys are " - "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d", - device->getName().string(), - (mDisableVirtualKeysTimeout - now) * 0.000001, - keyCode, scanCode); - return true; - } else { - return false; - } -} - -void InputReader::fadePointerLocked() { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->fadePointer(); - } -} - -void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { - if (when < mNextTimeout) { - mNextTimeout = when; - mEventHub->wake(); - } -} - -int32_t InputReader::bumpGenerationLocked() { - return ++mGeneration; -} - -void InputReader::getInputDevices(Vector<InputDeviceInfo>& outInputDevices) { - AutoMutex _l(mLock); - getInputDevicesLocked(outInputDevices); -} - -void InputReader::getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices) { - outInputDevices.clear(); - - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored()) { - outInputDevices.push(); - device->getDeviceInfo(&outInputDevices.editTop()); - } - } -} - -int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState); -} - -int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState); -} - -int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState); -} - -int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = (device->*getStateFunc)(sourceMask, code); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one device reports it. - int32_t currentResult = (device->*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; - } - } - } - } - return result; -} - -bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - AutoMutex _l(mLock); - - memset(outFlags, 0, numCodes); - return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); -} - -bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = device->markSupportedKeyCodes(sourceMask, - numCodes, keyCodes, outFlags); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result |= device->markSupportedKeyCodes(sourceMask, - numCodes, keyCodes, outFlags); - } - } - } - return result; -} - -void InputReader::requestRefreshConfiguration(uint32_t changes) { - AutoMutex _l(mLock); - - if (changes) { - bool needWake = !mConfigurationChangesToRefresh; - mConfigurationChangesToRefresh |= changes; - - if (needWake) { - mEventHub->wake(); - } - } -} - -void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - device->vibrate(pattern, patternSize, repeat, token); - } -} - -void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - device->cancelVibrate(token); - } -} - -void InputReader::dump(String8& dump) { - AutoMutex _l(mLock); - - mEventHub->dump(dump); - dump.append("\n"); - - dump.append("Input Reader State:\n"); - - for (size_t i = 0; i < mDevices.size(); i++) { - mDevices.valueAt(i)->dump(dump); - } - - dump.append(INDENT "Configuration:\n"); - dump.append(INDENT2 "ExcludedDeviceNames: ["); - for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { - if (i != 0) { - dump.append(", "); - } - dump.append(mConfig.excludedDeviceNames.itemAt(i).string()); - } - dump.append("]\n"); - dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", - mConfig.virtualKeyQuietTime * 0.000001f); - - dump.appendFormat(INDENT2 "PointerVelocityControlParameters: " - "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", - mConfig.pointerVelocityControlParameters.scale, - mConfig.pointerVelocityControlParameters.lowThreshold, - mConfig.pointerVelocityControlParameters.highThreshold, - mConfig.pointerVelocityControlParameters.acceleration); - - dump.appendFormat(INDENT2 "WheelVelocityControlParameters: " - "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", - mConfig.wheelVelocityControlParameters.scale, - mConfig.wheelVelocityControlParameters.lowThreshold, - mConfig.wheelVelocityControlParameters.highThreshold, - mConfig.wheelVelocityControlParameters.acceleration); - - dump.appendFormat(INDENT2 "PointerGesture:\n"); - dump.appendFormat(INDENT3 "Enabled: %s\n", - toString(mConfig.pointerGesturesEnabled)); - dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n", - mConfig.pointerGestureQuietInterval * 0.000001f); - dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", - mConfig.pointerGestureDragMinSwitchSpeed); - dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n", - mConfig.pointerGestureTapInterval * 0.000001f); - dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n", - mConfig.pointerGestureTapDragInterval * 0.000001f); - dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n", - mConfig.pointerGestureTapSlop); - dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n", - mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); - dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n", - mConfig.pointerGestureMultitouchMinDistance); - dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", - mConfig.pointerGestureSwipeTransitionAngleCosine); - dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", - mConfig.pointerGestureSwipeMaxWidthRatio); - dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n", - mConfig.pointerGestureMovementSpeedRatio); - dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n", - mConfig.pointerGestureZoomSpeedRatio); -} - -void InputReader::monitor() { - // Acquire and release the lock to ensure that the reader has not deadlocked. - mLock.lock(); - mEventHub->wake(); - mReaderIsAliveCondition.wait(mLock); - mLock.unlock(); - - // Check the EventHub - mEventHub->monitor(); -} - - -// --- InputReader::ContextImpl --- - -InputReader::ContextImpl::ContextImpl(InputReader* reader) : - mReader(reader) { -} - -void InputReader::ContextImpl::updateGlobalMetaState() { - // lock is already held by the input loop - mReader->updateGlobalMetaStateLocked(); -} - -int32_t InputReader::ContextImpl::getGlobalMetaState() { - // lock is already held by the input loop - return mReader->getGlobalMetaStateLocked(); -} - -void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { - // lock is already held by the input loop - mReader->disableVirtualKeysUntilLocked(time); -} - -bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) { - // lock is already held by the input loop - return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode); -} - -void InputReader::ContextImpl::fadePointer() { - // lock is already held by the input loop - mReader->fadePointerLocked(); -} - -void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { - // lock is already held by the input loop - mReader->requestTimeoutAtTimeLocked(when); -} - -int32_t InputReader::ContextImpl::bumpGeneration() { - // lock is already held by the input loop - return mReader->bumpGenerationLocked(); -} - -InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { - return mReader->mPolicy.get(); -} - -InputListenerInterface* InputReader::ContextImpl::getListener() { - return mReader->mQueuedListener.get(); -} - -EventHubInterface* InputReader::ContextImpl::getEventHub() { - return mReader->mEventHub.get(); -} - - -// --- InputReaderThread --- - -InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) : - Thread(/*canCallJava*/ true), mReader(reader) { -} - -InputReaderThread::~InputReaderThread() { -} - -bool InputReaderThread::threadLoop() { - mReader->loopOnce(); - return true; -} - - -// --- InputDevice --- - -InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, - int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) : - mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber), - mIdentifier(identifier), mClasses(classes), - mSources(0), mIsExternal(false), mDropUntilNextSync(false) { -} - -InputDevice::~InputDevice() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - delete mMappers[i]; - } - mMappers.clear(); -} - -void InputDevice::dump(String8& dump) { - InputDeviceInfo deviceInfo; - getDeviceInfo(& deviceInfo); - - dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(), - deviceInfo.getDisplayName().string()); - dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration); - dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); - dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); - dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); - - const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); - if (!ranges.isEmpty()) { - dump.append(INDENT2 "Motion Ranges:\n"); - for (size_t i = 0; i < ranges.size(); i++) { - const InputDeviceInfo::MotionRange& range = ranges.itemAt(i); - const char* label = getAxisLabel(range.axis); - char name[32]; - if (label) { - strncpy(name, label, sizeof(name)); - name[sizeof(name) - 1] = '\0'; - } else { - snprintf(name, sizeof(name), "%d", range.axis); - } - dump.appendFormat(INDENT3 "%s: source=0x%08x, " - "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n", - name, range.source, range.min, range.max, range.flat, range.fuzz, - range.resolution); - } - } - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->dump(dump); - } -} - -void InputDevice::addMapper(InputMapper* mapper) { - mMappers.add(mapper); -} - -void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { - mSources = 0; - - if (!isIgnored()) { - if (!changes) { // first time only - mContext->getEventHub()->getConfiguration(mId, &mConfiguration); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { - if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { - sp<KeyCharacterMap> keyboardLayout = - mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor); - if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { - bumpGeneration(); - } - } - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) { - if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { - String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); - if (mAlias != alias) { - mAlias = alias; - bumpGeneration(); - } - } - } - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->configure(when, config, changes); - mSources |= mapper->getSources(); - } - } -} - -void InputDevice::reset(nsecs_t when) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->reset(when); - } - - mContext->updateGlobalMetaState(); - - notifyReset(when); -} - -void InputDevice::process(const RawEvent* rawEvents, size_t count) { - // Process all of the events in order for each mapper. - // We cannot simply ask each mapper to process them in bulk because mappers may - // have side-effects that must be interleaved. For example, joystick movement events and - // gamepad button presses are handled by different mappers but they should be dispatched - // in the order received. - size_t numMappers = mMappers.size(); - for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { -#if DEBUG_RAW_EVENTS - ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld", - rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, - rawEvent->when); -#endif - - if (mDropUntilNextSync) { - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - mDropUntilNextSync = false; -#if DEBUG_RAW_EVENTS - ALOGD("Recovered from input event buffer overrun."); -#endif - } else { -#if DEBUG_RAW_EVENTS - ALOGD("Dropped input event while waiting for next input sync."); -#endif - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { - ALOGI("Detected input event buffer overrun for device %s.", getName().string()); - mDropUntilNextSync = true; - reset(rawEvent->when); - } else { - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->process(rawEvent); - } - } - } -} - -void InputDevice::timeoutExpired(nsecs_t when) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->timeoutExpired(when); - } -} - -void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { - outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, - mIsExternal); - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->populateDeviceInfo(outDeviceInfo); - } -} - -int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState); -} - -int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getState(sourceMask, scanCode, & InputMapper::getScanCodeState); -} - -int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getState(sourceMask, switchCode, & InputMapper::getSwitchState); -} - -int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. - int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; - } - } - } - return result; -} - -bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); - } - } - return result; -} - -void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->vibrate(pattern, patternSize, repeat, token); - } -} - -void InputDevice::cancelVibrate(int32_t token) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->cancelVibrate(token); - } -} - -int32_t InputDevice::getMetaState() { - int32_t result = 0; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - result |= mapper->getMetaState(); - } - return result; -} - -void InputDevice::fadePointer() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->fadePointer(); - } -} - -void InputDevice::bumpGeneration() { - mGeneration = mContext->bumpGeneration(); -} - -void InputDevice::notifyReset(nsecs_t when) { - NotifyDeviceResetArgs args(when, mId); - mContext->getListener()->notifyDeviceReset(&args); -} - - -// --- CursorButtonAccumulator --- - -CursorButtonAccumulator::CursorButtonAccumulator() { - clearButtons(); -} - -void CursorButtonAccumulator::reset(InputDevice* device) { - mBtnLeft = device->isKeyPressed(BTN_LEFT); - mBtnRight = device->isKeyPressed(BTN_RIGHT); - mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); - mBtnBack = device->isKeyPressed(BTN_BACK); - mBtnSide = device->isKeyPressed(BTN_SIDE); - mBtnForward = device->isKeyPressed(BTN_FORWARD); - mBtnExtra = device->isKeyPressed(BTN_EXTRA); - mBtnTask = device->isKeyPressed(BTN_TASK); -} - -void CursorButtonAccumulator::clearButtons() { - mBtnLeft = 0; - mBtnRight = 0; - mBtnMiddle = 0; - mBtnBack = 0; - mBtnSide = 0; - mBtnForward = 0; - mBtnExtra = 0; - mBtnTask = 0; -} - -void CursorButtonAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_KEY) { - switch (rawEvent->code) { - case BTN_LEFT: - mBtnLeft = rawEvent->value; - break; - case BTN_RIGHT: - mBtnRight = rawEvent->value; - break; - case BTN_MIDDLE: - mBtnMiddle = rawEvent->value; - break; - case BTN_BACK: - mBtnBack = rawEvent->value; - break; - case BTN_SIDE: - mBtnSide = rawEvent->value; - break; - case BTN_FORWARD: - mBtnForward = rawEvent->value; - break; - case BTN_EXTRA: - mBtnExtra = rawEvent->value; - break; - case BTN_TASK: - mBtnTask = rawEvent->value; - break; - } - } -} - -uint32_t CursorButtonAccumulator::getButtonState() const { - uint32_t result = 0; - if (mBtnLeft) { - result |= AMOTION_EVENT_BUTTON_PRIMARY; - } - if (mBtnRight) { - result |= AMOTION_EVENT_BUTTON_SECONDARY; - } - if (mBtnMiddle) { - result |= AMOTION_EVENT_BUTTON_TERTIARY; - } - if (mBtnBack || mBtnSide) { - result |= AMOTION_EVENT_BUTTON_BACK; - } - if (mBtnForward || mBtnExtra) { - result |= AMOTION_EVENT_BUTTON_FORWARD; - } - return result; -} - - -// --- CursorMotionAccumulator --- - -CursorMotionAccumulator::CursorMotionAccumulator() { - clearRelativeAxes(); -} - -void CursorMotionAccumulator::reset(InputDevice* device) { - clearRelativeAxes(); -} - -void CursorMotionAccumulator::clearRelativeAxes() { - mRelX = 0; - mRelY = 0; -} - -void CursorMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_REL) { - switch (rawEvent->code) { - case REL_X: - mRelX = rawEvent->value; - break; - case REL_Y: - mRelY = rawEvent->value; - break; - } - } -} - -void CursorMotionAccumulator::finishSync() { - clearRelativeAxes(); -} - - -// --- CursorScrollAccumulator --- - -CursorScrollAccumulator::CursorScrollAccumulator() : - mHaveRelWheel(false), mHaveRelHWheel(false) { - clearRelativeAxes(); -} - -void CursorScrollAccumulator::configure(InputDevice* device) { - mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); - mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); -} - -void CursorScrollAccumulator::reset(InputDevice* device) { - clearRelativeAxes(); -} - -void CursorScrollAccumulator::clearRelativeAxes() { - mRelWheel = 0; - mRelHWheel = 0; -} - -void CursorScrollAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_REL) { - switch (rawEvent->code) { - case REL_WHEEL: - mRelWheel = rawEvent->value; - break; - case REL_HWHEEL: - mRelHWheel = rawEvent->value; - break; - } - } -} - -void CursorScrollAccumulator::finishSync() { - clearRelativeAxes(); -} - - -// --- TouchButtonAccumulator --- - -TouchButtonAccumulator::TouchButtonAccumulator() : - mHaveBtnTouch(false), mHaveStylus(false) { - clearButtons(); -} - -void TouchButtonAccumulator::configure(InputDevice* device) { - mHaveBtnTouch = device->hasKey(BTN_TOUCH); - mHaveStylus = device->hasKey(BTN_TOOL_PEN) - || device->hasKey(BTN_TOOL_RUBBER) - || device->hasKey(BTN_TOOL_BRUSH) - || device->hasKey(BTN_TOOL_PENCIL) - || device->hasKey(BTN_TOOL_AIRBRUSH); -} - -void TouchButtonAccumulator::reset(InputDevice* device) { - mBtnTouch = device->isKeyPressed(BTN_TOUCH); - mBtnStylus = device->isKeyPressed(BTN_STYLUS); - mBtnStylus2 = device->isKeyPressed(BTN_STYLUS); - mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); - mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); - mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); - mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); - mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); - mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); - mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); - mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); - mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); - mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); - mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); -} - -void TouchButtonAccumulator::clearButtons() { - mBtnTouch = 0; - mBtnStylus = 0; - mBtnStylus2 = 0; - mBtnToolFinger = 0; - mBtnToolPen = 0; - mBtnToolRubber = 0; - mBtnToolBrush = 0; - mBtnToolPencil = 0; - mBtnToolAirbrush = 0; - mBtnToolMouse = 0; - mBtnToolLens = 0; - mBtnToolDoubleTap = 0; - mBtnToolTripleTap = 0; - mBtnToolQuadTap = 0; -} - -void TouchButtonAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_KEY) { - switch (rawEvent->code) { - case BTN_TOUCH: - mBtnTouch = rawEvent->value; - break; - case BTN_STYLUS: - mBtnStylus = rawEvent->value; - break; - case BTN_STYLUS2: - mBtnStylus2 = rawEvent->value; - break; - case BTN_TOOL_FINGER: - mBtnToolFinger = rawEvent->value; - break; - case BTN_TOOL_PEN: - mBtnToolPen = rawEvent->value; - break; - case BTN_TOOL_RUBBER: - mBtnToolRubber = rawEvent->value; - break; - case BTN_TOOL_BRUSH: - mBtnToolBrush = rawEvent->value; - break; - case BTN_TOOL_PENCIL: - mBtnToolPencil = rawEvent->value; - break; - case BTN_TOOL_AIRBRUSH: - mBtnToolAirbrush = rawEvent->value; - break; - case BTN_TOOL_MOUSE: - mBtnToolMouse = rawEvent->value; - break; - case BTN_TOOL_LENS: - mBtnToolLens = rawEvent->value; - break; - case BTN_TOOL_DOUBLETAP: - mBtnToolDoubleTap = rawEvent->value; - break; - case BTN_TOOL_TRIPLETAP: - mBtnToolTripleTap = rawEvent->value; - break; - case BTN_TOOL_QUADTAP: - mBtnToolQuadTap = rawEvent->value; - break; - } - } -} - -uint32_t TouchButtonAccumulator::getButtonState() const { - uint32_t result = 0; - if (mBtnStylus) { - result |= AMOTION_EVENT_BUTTON_SECONDARY; - } - if (mBtnStylus2) { - result |= AMOTION_EVENT_BUTTON_TERTIARY; - } - return result; -} - -int32_t TouchButtonAccumulator::getToolType() const { - if (mBtnToolMouse || mBtnToolLens) { - return AMOTION_EVENT_TOOL_TYPE_MOUSE; - } - if (mBtnToolRubber) { - return AMOTION_EVENT_TOOL_TYPE_ERASER; - } - if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { - return AMOTION_EVENT_TOOL_TYPE_FINGER; - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - -bool TouchButtonAccumulator::isToolActive() const { - return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber - || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush - || mBtnToolMouse || mBtnToolLens - || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; -} - -bool TouchButtonAccumulator::isHovering() const { - return mHaveBtnTouch && !mBtnTouch; -} - -bool TouchButtonAccumulator::hasStylus() const { - return mHaveStylus; -} - - -// --- RawPointerAxes --- - -RawPointerAxes::RawPointerAxes() { - clear(); -} - -void RawPointerAxes::clear() { - x.clear(); - y.clear(); - pressure.clear(); - touchMajor.clear(); - touchMinor.clear(); - toolMajor.clear(); - toolMinor.clear(); - orientation.clear(); - distance.clear(); - tiltX.clear(); - tiltY.clear(); - trackingId.clear(); - slot.clear(); -} - - -// --- RawPointerData --- - -RawPointerData::RawPointerData() { - clear(); -} - -void RawPointerData::clear() { - pointerCount = 0; - clearIdBits(); -} - -void RawPointerData::copyFrom(const RawPointerData& other) { - pointerCount = other.pointerCount; - hoveringIdBits = other.hoveringIdBits; - touchingIdBits = other.touchingIdBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointers[i] = other.pointers[i]; - - int id = pointers[i].id; - idToIndex[id] = other.idToIndex[id]; - } -} - -void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { - float x = 0, y = 0; - uint32_t count = touchingIdBits.count(); - if (count) { - for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const Pointer& pointer = pointerForId(id); - x += pointer.x; - y += pointer.y; - } - x /= count; - y /= count; - } - *outX = x; - *outY = y; -} - - -// --- CookedPointerData --- - -CookedPointerData::CookedPointerData() { - clear(); -} - -void CookedPointerData::clear() { - pointerCount = 0; - hoveringIdBits.clear(); - touchingIdBits.clear(); -} - -void CookedPointerData::copyFrom(const CookedPointerData& other) { - pointerCount = other.pointerCount; - hoveringIdBits = other.hoveringIdBits; - touchingIdBits = other.touchingIdBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(other.pointerProperties[i]); - pointerCoords[i].copyFrom(other.pointerCoords[i]); - - int id = pointerProperties[i].id; - idToIndex[id] = other.idToIndex[id]; - } -} - - -// --- SingleTouchMotionAccumulator --- - -SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { - clearAbsoluteAxes(); -} - -void SingleTouchMotionAccumulator::reset(InputDevice* device) { - mAbsX = device->getAbsoluteAxisValue(ABS_X); - mAbsY = device->getAbsoluteAxisValue(ABS_Y); - mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); - mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); - mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); - mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); - mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); -} - -void SingleTouchMotionAccumulator::clearAbsoluteAxes() { - mAbsX = 0; - mAbsY = 0; - mAbsPressure = 0; - mAbsToolWidth = 0; - mAbsDistance = 0; - mAbsTiltX = 0; - mAbsTiltY = 0; -} - -void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { - switch (rawEvent->code) { - case ABS_X: - mAbsX = rawEvent->value; - break; - case ABS_Y: - mAbsY = rawEvent->value; - break; - case ABS_PRESSURE: - mAbsPressure = rawEvent->value; - break; - case ABS_TOOL_WIDTH: - mAbsToolWidth = rawEvent->value; - break; - case ABS_DISTANCE: - mAbsDistance = rawEvent->value; - break; - case ABS_TILT_X: - mAbsTiltX = rawEvent->value; - break; - case ABS_TILT_Y: - mAbsTiltY = rawEvent->value; - break; - } - } -} - - -// --- MultiTouchMotionAccumulator --- - -MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : - mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false), - mHaveStylus(false) { -} - -MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { - delete[] mSlots; -} - -void MultiTouchMotionAccumulator::configure(InputDevice* device, - size_t slotCount, bool usingSlotsProtocol) { - mSlotCount = slotCount; - mUsingSlotsProtocol = usingSlotsProtocol; - mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); - - delete[] mSlots; - mSlots = new Slot[slotCount]; -} - -void MultiTouchMotionAccumulator::reset(InputDevice* device) { - // Unfortunately there is no way to read the initial contents of the slots. - // So when we reset the accumulator, we must assume they are all zeroes. - if (mUsingSlotsProtocol) { - // Query the driver for the current slot index and use it as the initial slot - // before we start reading events from the device. It is possible that the - // current slot index will not be the same as it was when the first event was - // written into the evdev buffer, which means the input mapper could start - // out of sync with the initial state of the events in the evdev buffer. - // In the extremely unlikely case that this happens, the data from - // two slots will be confused until the next ABS_MT_SLOT event is received. - // This can cause the touch point to "jump", but at least there will be - // no stuck touches. - int32_t initialSlot; - status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), - ABS_MT_SLOT, &initialSlot); - if (status) { - ALOGD("Could not retrieve current multitouch slot index. status=%d", status); - initialSlot = -1; - } - clearSlots(initialSlot); - } else { - clearSlots(-1); - } -} - -void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { - if (mSlots) { - for (size_t i = 0; i < mSlotCount; i++) { - mSlots[i].clear(); - } - } - mCurrentSlot = initialSlot; -} - -void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { - bool newSlot = false; - if (mUsingSlotsProtocol) { - if (rawEvent->code == ABS_MT_SLOT) { - mCurrentSlot = rawEvent->value; - newSlot = true; - } - } else if (mCurrentSlot < 0) { - mCurrentSlot = 0; - } - - if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { -#if DEBUG_POINTERS - if (newSlot) { - ALOGW("MultiTouch device emitted invalid slot index %d but it " - "should be between 0 and %d; ignoring this slot.", - mCurrentSlot, mSlotCount - 1); - } -#endif - } else { - Slot* slot = &mSlots[mCurrentSlot]; - - switch (rawEvent->code) { - case ABS_MT_POSITION_X: - slot->mInUse = true; - slot->mAbsMTPositionX = rawEvent->value; - break; - case ABS_MT_POSITION_Y: - slot->mInUse = true; - slot->mAbsMTPositionY = rawEvent->value; - break; - case ABS_MT_TOUCH_MAJOR: - slot->mInUse = true; - slot->mAbsMTTouchMajor = rawEvent->value; - break; - case ABS_MT_TOUCH_MINOR: - slot->mInUse = true; - slot->mAbsMTTouchMinor = rawEvent->value; - slot->mHaveAbsMTTouchMinor = true; - break; - case ABS_MT_WIDTH_MAJOR: - slot->mInUse = true; - slot->mAbsMTWidthMajor = rawEvent->value; - break; - case ABS_MT_WIDTH_MINOR: - slot->mInUse = true; - slot->mAbsMTWidthMinor = rawEvent->value; - slot->mHaveAbsMTWidthMinor = true; - break; - case ABS_MT_ORIENTATION: - slot->mInUse = true; - slot->mAbsMTOrientation = rawEvent->value; - break; - case ABS_MT_TRACKING_ID: - if (mUsingSlotsProtocol && rawEvent->value < 0) { - // The slot is no longer in use but it retains its previous contents, - // which may be reused for subsequent touches. - slot->mInUse = false; - } else { - slot->mInUse = true; - slot->mAbsMTTrackingId = rawEvent->value; - } - break; - case ABS_MT_PRESSURE: - slot->mInUse = true; - slot->mAbsMTPressure = rawEvent->value; - break; - case ABS_MT_DISTANCE: - slot->mInUse = true; - slot->mAbsMTDistance = rawEvent->value; - break; - case ABS_MT_TOOL_TYPE: - slot->mInUse = true; - slot->mAbsMTToolType = rawEvent->value; - slot->mHaveAbsMTToolType = true; - break; - } - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { - // MultiTouch Sync: The driver has returned all data for *one* of the pointers. - mCurrentSlot += 1; - } -} - -void MultiTouchMotionAccumulator::finishSync() { - if (!mUsingSlotsProtocol) { - clearSlots(-1); - } -} - -bool MultiTouchMotionAccumulator::hasStylus() const { - return mHaveStylus; -} - - -// --- MultiTouchMotionAccumulator::Slot --- - -MultiTouchMotionAccumulator::Slot::Slot() { - clear(); -} - -void MultiTouchMotionAccumulator::Slot::clear() { - mInUse = false; - mHaveAbsMTTouchMinor = false; - mHaveAbsMTWidthMinor = false; - mHaveAbsMTToolType = false; - mAbsMTPositionX = 0; - mAbsMTPositionY = 0; - mAbsMTTouchMajor = 0; - mAbsMTTouchMinor = 0; - mAbsMTWidthMajor = 0; - mAbsMTWidthMinor = 0; - mAbsMTOrientation = 0; - mAbsMTTrackingId = -1; - mAbsMTPressure = 0; - mAbsMTDistance = 0; - mAbsMTToolType = 0; -} - -int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { - if (mHaveAbsMTToolType) { - switch (mAbsMTToolType) { - case MT_TOOL_FINGER: - return AMOTION_EVENT_TOOL_TYPE_FINGER; - case MT_TOOL_PEN: - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - - -// --- InputMapper --- - -InputMapper::InputMapper(InputDevice* device) : - mDevice(device), mContext(device->getContext()) { -} - -InputMapper::~InputMapper() { -} - -void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { - info->addSource(getSources()); -} - -void InputMapper::dump(String8& dump) { -} - -void InputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { -} - -void InputMapper::reset(nsecs_t when) { -} - -void InputMapper::timeoutExpired(nsecs_t when) { -} - -int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return AKEY_STATE_UNKNOWN; -} - -bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return false; -} - -void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { -} - -void InputMapper::cancelVibrate(int32_t token) { -} - -int32_t InputMapper::getMetaState() { - return 0; -} - -void InputMapper::fadePointer() { -} - -status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { - return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); -} - -void InputMapper::bumpGeneration() { - mDevice->bumpGeneration(); -} - -void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, - const RawAbsoluteAxisInfo& axis, const char* name) { - if (axis.valid) { - dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", - name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution); - } else { - dump.appendFormat(INDENT4 "%s: unknown range\n", name); - } -} - - -// --- SwitchInputMapper --- - -SwitchInputMapper::SwitchInputMapper(InputDevice* device) : - InputMapper(device), mUpdatedSwitchValues(0), mUpdatedSwitchMask(0) { -} - -SwitchInputMapper::~SwitchInputMapper() { -} - -uint32_t SwitchInputMapper::getSources() { - return AINPUT_SOURCE_SWITCH; -} - -void SwitchInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_SW: - processSwitch(rawEvent->code, rawEvent->value); - break; - - case EV_SYN: - if (rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } - } -} - -void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) { - if (switchCode >= 0 && switchCode < 32) { - if (switchValue) { - mUpdatedSwitchValues |= 1 << switchCode; - } - mUpdatedSwitchMask |= 1 << switchCode; - } -} - -void SwitchInputMapper::sync(nsecs_t when) { - if (mUpdatedSwitchMask) { - NotifySwitchArgs args(when, 0, mUpdatedSwitchValues, mUpdatedSwitchMask); - getListener()->notifySwitch(&args); - - mUpdatedSwitchValues = 0; - mUpdatedSwitchMask = 0; - } -} - -int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getEventHub()->getSwitchState(getDeviceId(), switchCode); -} - - -// --- VibratorInputMapper --- - -VibratorInputMapper::VibratorInputMapper(InputDevice* device) : - InputMapper(device), mVibrating(false) { -} - -VibratorInputMapper::~VibratorInputMapper() { -} - -uint32_t VibratorInputMapper::getSources() { - return 0; -} - -void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setVibrator(true); -} - -void VibratorInputMapper::process(const RawEvent* rawEvent) { - // TODO: Handle FF_STATUS, although it does not seem to be widely supported. -} - -void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { -#if DEBUG_VIBRATOR - String8 patternStr; - for (size_t i = 0; i < patternSize; i++) { - if (i != 0) { - patternStr.append(", "); - } - patternStr.appendFormat("%lld", pattern[i]); - } - ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d", - getDeviceId(), patternStr.string(), repeat, token); -#endif - - mVibrating = true; - memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t)); - mPatternSize = patternSize; - mRepeat = repeat; - mToken = token; - mIndex = -1; - - nextStep(); -} - -void VibratorInputMapper::cancelVibrate(int32_t token) { -#if DEBUG_VIBRATOR - ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token); -#endif - - if (mVibrating && mToken == token) { - stopVibrating(); - } -} - -void VibratorInputMapper::timeoutExpired(nsecs_t when) { - if (mVibrating) { - if (when >= mNextStepTime) { - nextStep(); - } else { - getContext()->requestTimeoutAtTime(mNextStepTime); - } - } -} - -void VibratorInputMapper::nextStep() { - mIndex += 1; - if (size_t(mIndex) >= mPatternSize) { - if (mRepeat < 0) { - // We are done. - stopVibrating(); - return; - } - mIndex = mRepeat; - } - - bool vibratorOn = mIndex & 1; - nsecs_t duration = mPattern[mIndex]; - if (vibratorOn) { -#if DEBUG_VIBRATOR - ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld", - getDeviceId(), duration); -#endif - getEventHub()->vibrate(getDeviceId(), duration); - } else { -#if DEBUG_VIBRATOR - ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId()); -#endif - getEventHub()->cancelVibrate(getDeviceId()); - } - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - mNextStepTime = now + duration; - getContext()->requestTimeoutAtTime(mNextStepTime); -#if DEBUG_VIBRATOR - ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f); -#endif -} - -void VibratorInputMapper::stopVibrating() { - mVibrating = false; -#if DEBUG_VIBRATOR - ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId()); -#endif - getEventHub()->cancelVibrate(getDeviceId()); -} - -void VibratorInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Vibrator Input Mapper:\n"); - dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating)); -} - - -// --- KeyboardInputMapper --- - -KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, - uint32_t source, int32_t keyboardType) : - InputMapper(device), mSource(source), - mKeyboardType(keyboardType) { -} - -KeyboardInputMapper::~KeyboardInputMapper() { -} - -uint32_t KeyboardInputMapper::getSources() { - return mSource; -} - -void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setKeyboardType(mKeyboardType); - info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); -} - -void KeyboardInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Keyboard Input Mapper:\n"); - dumpParameters(dump); - dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType); - dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); - dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mKeyDowns.size()); - dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState); - dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime); -} - - -void KeyboardInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - // Configure basic parameters. - configureParameters(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - DisplayViewport v; - if (config->getDisplayInfo(false /*external*/, &v)) { - mOrientation = v.orientation; - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } -} - -void KeyboardInputMapper::configureParameters() { - mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - if (mParameters.orientationAware) { - mParameters.hasAssociatedDisplay = true; - } -} - -void KeyboardInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n", - toString(mParameters.hasAssociatedDisplay)); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void KeyboardInputMapper::reset(nsecs_t when) { - mMetaState = AMETA_NONE; - mDownTime = 0; - mKeyDowns.clear(); - mCurrentHidUsage = 0; - - resetLedState(); - - InputMapper::reset(when); -} - -void KeyboardInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_KEY: { - int32_t scanCode = rawEvent->code; - int32_t usageCode = mCurrentHidUsage; - mCurrentHidUsage = 0; - - if (isKeyboardOrGamepadKey(scanCode)) { - int32_t keyCode; - uint32_t flags; - if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) { - keyCode = AKEYCODE_UNKNOWN; - flags = 0; - } - processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags); - } - break; - } - case EV_MSC: { - if (rawEvent->code == MSC_SCAN) { - mCurrentHidUsage = rawEvent->value; - } - break; - } - case EV_SYN: { - if (rawEvent->code == SYN_REPORT) { - mCurrentHidUsage = 0; - } - } - } -} - -bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { - return scanCode < BTN_MOUSE - || scanCode >= KEY_OK - || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) - || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); -} - -void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, - int32_t scanCode, uint32_t policyFlags) { - - if (down) { - // Rotate key codes according to orientation if needed. - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - keyCode = rotateKeyCode(keyCode, mOrientation); - } - - // Add key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key repeat, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; - } else { - // key down - if ((policyFlags & POLICY_FLAG_VIRTUAL) - && mContext->shouldDropVirtualKey(when, - getDevice(), keyCode, scanCode)) { - return; - } - - mKeyDowns.push(); - KeyDown& keyDown = mKeyDowns.editTop(); - keyDown.keyCode = keyCode; - keyDown.scanCode = scanCode; - } - - mDownTime = when; - } else { - // Remove key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key up, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; - mKeyDowns.removeAt(size_t(keyDownIndex)); - } else { - // key was not actually down - ALOGI("Dropping key up from device %s because the key was not down. " - "keyCode=%d, scanCode=%d", - getDeviceName().string(), keyCode, scanCode); - return; - } - } - - int32_t oldMetaState = mMetaState; - int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState); - bool metaStateChanged = oldMetaState != newMetaState; - if (metaStateChanged) { - mMetaState = newMetaState; - updateLedState(false); - } - - nsecs_t downTime = mDownTime; - - // Key down on external an keyboard should wake the device. - // We don't do this for internal keyboards to prevent them from waking up in your pocket. - // For internal keyboards, the key layout file should specify the policy flags for - // each wake key individually. - // TODO: Use the input device configuration to control this behavior more finely. - if (down && getDevice()->isExternal() - && !(policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED))) { - policyFlags |= POLICY_FLAG_WAKE_DROPPED; - } - - if (metaStateChanged) { - getContext()->updateGlobalMetaState(); - } - - if (down && !isMetaKey(keyCode)) { - getContext()->fadePointer(); - } - - NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags, - down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); - getListener()->notifyKey(&args); -} - -ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { - size_t n = mKeyDowns.size(); - for (size_t i = 0; i < n; i++) { - if (mKeyDowns[i].scanCode == scanCode) { - return i; - } - } - return -1; -} - -int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); -} - -int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); -} - -bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); -} - -int32_t KeyboardInputMapper::getMetaState() { - return mMetaState; -} - -void KeyboardInputMapper::resetLedState() { - initializeLedState(mCapsLockLedState, LED_CAPSL); - initializeLedState(mNumLockLedState, LED_NUML); - initializeLedState(mScrollLockLedState, LED_SCROLLL); - - updateLedState(true); -} - -void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) { - ledState.avail = getEventHub()->hasLed(getDeviceId(), led); - ledState.on = false; -} - -void KeyboardInputMapper::updateLedState(bool reset) { - updateLedStateForModifier(mCapsLockLedState, LED_CAPSL, - AMETA_CAPS_LOCK_ON, reset); - updateLedStateForModifier(mNumLockLedState, LED_NUML, - AMETA_NUM_LOCK_ON, reset); - updateLedStateForModifier(mScrollLockLedState, LED_SCROLLL, - AMETA_SCROLL_LOCK_ON, reset); -} - -void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, - int32_t led, int32_t modifier, bool reset) { - if (ledState.avail) { - bool desiredState = (mMetaState & modifier) != 0; - if (reset || ledState.on != desiredState) { - getEventHub()->setLedState(getDeviceId(), led, desiredState); - ledState.on = desiredState; - } - } -} - - -// --- CursorInputMapper --- - -CursorInputMapper::CursorInputMapper(InputDevice* device) : - InputMapper(device) { -} - -CursorInputMapper::~CursorInputMapper() { -} - -uint32_t CursorInputMapper::getSources() { - return mSource; -} - -void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mParameters.mode == Parameters::MODE_POINTER) { - float minX, minY, maxX, maxY; - if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f); - } - } else { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f); - } - info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); - - if (mCursorScrollAccumulator.haveRelativeVWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); - } - if (mCursorScrollAccumulator.haveRelativeHWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); - } -} - -void CursorInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Cursor Input Mapper:\n"); - dumpParameters(dump); - dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale); - dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale); - dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); - dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); - dump.appendFormat(INDENT3 "HaveVWheel: %s\n", - toString(mCursorScrollAccumulator.haveRelativeVWheel())); - dump.appendFormat(INDENT3 "HaveHWheel: %s\n", - toString(mCursorScrollAccumulator.haveRelativeHWheel())); - dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); - dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); - dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); - dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState); - dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); - dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime); -} - -void CursorInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - mCursorScrollAccumulator.configure(getDevice()); - - // Configure basic parameters. - configureParameters(); - - // Configure device mode. - switch (mParameters.mode) { - case Parameters::MODE_POINTER: - mSource = AINPUT_SOURCE_MOUSE; - mXPrecision = 1.0f; - mYPrecision = 1.0f; - mXScale = 1.0f; - mYScale = 1.0f; - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - break; - case Parameters::MODE_NAVIGATION: - mSource = AINPUT_SOURCE_TRACKBALL; - mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - break; - } - - mVWheelScale = 1.0f; - mHWheelScale = 1.0f; - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters); - mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - DisplayViewport v; - if (config->getDisplayInfo(false /*external*/, &v)) { - mOrientation = v.orientation; - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - bumpGeneration(); - } -} - -void CursorInputMapper::configureParameters() { - mParameters.mode = Parameters::MODE_POINTER; - String8 cursorModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { - if (cursorModeString == "navigation") { - mParameters.mode = Parameters::MODE_NAVIGATION; - } else if (cursorModeString != "pointer" && cursorModeString != "default") { - ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); - } - } - - mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { - mParameters.hasAssociatedDisplay = true; - } -} - -void CursorInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n", - toString(mParameters.hasAssociatedDisplay)); - - switch (mParameters.mode) { - case Parameters::MODE_POINTER: - dump.append(INDENT4 "Mode: pointer\n"); - break; - case Parameters::MODE_NAVIGATION: - dump.append(INDENT4 "Mode: navigation\n"); - break; - default: - ALOG_ASSERT(false); - } - - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void CursorInputMapper::reset(nsecs_t when) { - mButtonState = 0; - mDownTime = 0; - - mPointerVelocityControl.reset(); - mWheelXVelocityControl.reset(); - mWheelYVelocityControl.reset(); - - mCursorButtonAccumulator.reset(getDevice()); - mCursorMotionAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - - InputMapper::reset(when); -} - -void CursorInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mCursorMotionAccumulator.process(rawEvent); - mCursorScrollAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void CursorInputMapper::sync(nsecs_t when) { - int32_t lastButtonState = mButtonState; - int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); - mButtonState = currentButtonState; - - bool wasDown = isPointerDown(lastButtonState); - bool down = isPointerDown(currentButtonState); - bool downChanged; - if (!wasDown && down) { - mDownTime = when; - downChanged = true; - } else if (wasDown && !down) { - downChanged = true; - } else { - downChanged = false; - } - nsecs_t downTime = mDownTime; - bool buttonsChanged = currentButtonState != lastButtonState; - bool buttonsPressed = currentButtonState & ~lastButtonState; - - float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; - float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; - bool moved = deltaX != 0 || deltaY != 0; - - // Rotate delta according to orientation if needed. - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay - && (deltaX != 0.0f || deltaY != 0.0f)) { - rotateDelta(mOrientation, &deltaX, &deltaY); - } - - // Move the pointer. - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; - - PointerCoords pointerCoords; - pointerCoords.clear(); - - float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); - float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); - bool scrolled = vscroll != 0 || hscroll != 0; - - mWheelYVelocityControl.move(when, NULL, &vscroll); - mWheelXVelocityControl.move(when, &hscroll, NULL); - - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - int32_t displayId; - if (mPointerController != NULL) { - if (moved || scrolled || buttonsChanged) { - mPointerController->setPresentation( - PointerControllerInterface::PRESENTATION_POINTER); - - if (moved) { - mPointerController->move(deltaX, deltaY); - } - - if (buttonsChanged) { - mPointerController->setButtonState(currentButtonState); - } - - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } - - float x, y; - mPointerController->getPosition(&x, &y); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - displayId = ADISPLAY_ID_DEFAULT; - } else { - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); - displayId = ADISPLAY_ID_NONE; - } - - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); - - // Moving an external trackball or mouse should wake the device. - // We don't do this for internal cursor devices to prevent them from waking up - // the device in your pocket. - // TODO: Use the input device configuration to control this behavior more finely. - uint32_t policyFlags = 0; - if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE_DROPPED; - } - - // Synthesize key down from buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - policyFlags, lastButtonState, currentButtonState); - - // Send motion event. - if (downChanged || moved || scrolled || buttonsChanged) { - int32_t metaState = mContext->getGlobalMetaState(); - int32_t motionEventAction; - if (downChanged) { - motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else if (down || mPointerController == NULL) { - motionEventAction = AMOTION_EVENT_ACTION_MOVE; - } else { - motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; - } - - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - motionEventAction, 0, metaState, currentButtonState, 0, - displayId, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime); - getListener()->notifyMotion(&args); - - // Send hover move after UP to tell the application that the mouse is hovering now. - if (motionEventAction == AMOTION_EVENT_ACTION_UP - && mPointerController != NULL) { - NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, - displayId, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime); - getListener()->notifyMotion(&hoverArgs); - } - - // Send scroll events. - if (scrolled) { - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - - NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - displayId, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime); - getListener()->notifyMotion(&scrollArgs); - } - } - - // Synthesize key up from buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - policyFlags, lastButtonState, currentButtonState); - - mCursorMotionAccumulator.finishSync(); - mCursorScrollAccumulator.finishSync(); -} - -int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); - } else { - return AKEY_STATE_UNKNOWN; - } -} - -void CursorInputMapper::fadePointer() { - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - - -// --- TouchInputMapper --- - -TouchInputMapper::TouchInputMapper(InputDevice* device) : - InputMapper(device), - mSource(0), mDeviceMode(DEVICE_MODE_DISABLED), - mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0), - mSurfaceOrientation(DISPLAY_ORIENTATION_0) { -} - -TouchInputMapper::~TouchInputMapper() { -} - -uint32_t TouchInputMapper::getSources() { - return mSource; -} - -void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mDeviceMode != DEVICE_MODE_DISABLED) { - info->addMotionRange(mOrientedRanges.x); - info->addMotionRange(mOrientedRanges.y); - info->addMotionRange(mOrientedRanges.pressure); - - if (mOrientedRanges.haveSize) { - info->addMotionRange(mOrientedRanges.size); - } - - if (mOrientedRanges.haveTouchSize) { - info->addMotionRange(mOrientedRanges.touchMajor); - info->addMotionRange(mOrientedRanges.touchMinor); - } - - if (mOrientedRanges.haveToolSize) { - info->addMotionRange(mOrientedRanges.toolMajor); - info->addMotionRange(mOrientedRanges.toolMinor); - } - - if (mOrientedRanges.haveOrientation) { - info->addMotionRange(mOrientedRanges.orientation); - } - - if (mOrientedRanges.haveDistance) { - info->addMotionRange(mOrientedRanges.distance); - } - - if (mOrientedRanges.haveTilt) { - info->addMotionRange(mOrientedRanges.tilt); - } - - if (mCursorScrollAccumulator.haveRelativeVWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - 0.0f); - } - if (mCursorScrollAccumulator.haveRelativeHWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - 0.0f); - } - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { - const InputDeviceInfo::MotionRange& x = mOrientedRanges.x; - const InputDeviceInfo::MotionRange& y = mOrientedRanges.y; - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, - x.fuzz, x.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, - y.fuzz, y.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, - x.fuzz, x.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, - y.fuzz, y.resolution); - } - info->setButtonUnderPad(mParameters.hasButtonUnderPad); - } -} - -void TouchInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Touch Input Mapper:\n"); - dumpParameters(dump); - dumpVirtualKeys(dump); - dumpRawPointerAxes(dump); - dumpCalibration(dump); - dumpSurface(dump); - - dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n"); - dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate); - dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate); - dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale); - dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale); - dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision); - dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mYPrecision); - dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); - dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale); - dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale); - dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); - dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); - dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); - dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); - dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); - dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); - dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); - - dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState); - - dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n", - mLastRawPointerData.pointerCount); - for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) { - const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i]; - dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " - "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " - "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " - "toolType=%d, isHovering=%s\n", i, - pointer.id, pointer.x, pointer.y, pointer.pressure, - pointer.touchMajor, pointer.touchMinor, - pointer.toolMajor, pointer.toolMinor, - pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance, - pointer.toolType, toString(pointer.isHovering)); - } - - dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n", - mLastCookedPointerData.pointerCount); - for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) { - const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i]; - const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i]; - dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " - "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " - "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " - "toolType=%d, isHovering=%s\n", i, - pointerProperties.id, - pointerCoords.getX(), - pointerCoords.getY(), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), - pointerProperties.toolType, - toString(mLastCookedPointerData.isHovering(i))); - } - - if (mDeviceMode == DEVICE_MODE_POINTER) { - dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); - dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", - mPointerXMovementScale); - dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n", - mPointerYMovementScale); - dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n", - mPointerXZoomScale); - dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n", - mPointerYZoomScale); - dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n", - mPointerGestureMaxSwipeWidth); - } -} - -void TouchInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - mConfig = *config; - - if (!changes) { // first time only - // Configure basic parameters. - configureParameters(); - - // Configure common accumulators. - mCursorScrollAccumulator.configure(getDevice()); - mTouchButtonAccumulator.configure(getDevice()); - - // Configure absolute axis information. - configureRawPointerAxes(); - - // Prepare input device calibration. - parseCalibration(); - resolveCalibration(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - // Update pointer speed. - mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); - mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); - } - - bool resetNeeded = false; - if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO - | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT - | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) { - // Configure device sources, surface dimensions, orientation and - // scaling factors. - configureSurface(when, &resetNeeded); - } - - if (changes && resetNeeded) { - // Send reset, unless this is the first time the device has been configured, - // in which case the reader will call reset itself after all mappers are ready. - getDevice()->notifyReset(when); - } -} - -void TouchInputMapper::configureParameters() { - // Use the pointer presentation mode for devices that do not support distinct - // multitouch. The spot-based presentation relies on being able to accurately - // locate two or more fingers on the touch pad. - mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT) - ? Parameters::GESTURE_MODE_POINTER : Parameters::GESTURE_MODE_SPOTS; - - String8 gestureModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), - gestureModeString)) { - if (gestureModeString == "pointer") { - mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER; - } else if (gestureModeString == "spots") { - mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS; - } else if (gestureModeString != "default") { - ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); - } - } - - if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { - // The device is a touch screen. - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { - // The device is a pointing device like a track pad. - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) - || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { - // The device is a cursor device with a touch pad attached. - // By default don't use the touch pad to move the pointer. - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else { - // The device is a touch pad of unknown purpose. - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } - - mParameters.hasButtonUnderPad= - getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD); - - String8 deviceTypeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), - deviceTypeString)) { - if (deviceTypeString == "touchScreen") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (deviceTypeString == "touchPad") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else if (deviceTypeString == "touchNavigation") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION; - } else if (deviceTypeString == "pointer") { - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (deviceTypeString != "default") { - ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); - } - } - - mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; - getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - mParameters.associatedDisplayIsExternal = false; - if (mParameters.orientationAware - || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { - mParameters.hasAssociatedDisplay = true; - mParameters.associatedDisplayIsExternal = - mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - && getDevice()->isExternal(); - } -} - -void TouchInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - - switch (mParameters.gestureMode) { - case Parameters::GESTURE_MODE_POINTER: - dump.append(INDENT4 "GestureMode: pointer\n"); - break; - case Parameters::GESTURE_MODE_SPOTS: - dump.append(INDENT4 "GestureMode: spots\n"); - break; - default: - assert(false); - } - - switch (mParameters.deviceType) { - case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - dump.append(INDENT4 "DeviceType: touchScreen\n"); - break; - case Parameters::DEVICE_TYPE_TOUCH_PAD: - dump.append(INDENT4 "DeviceType: touchPad\n"); - break; - case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION: - dump.append(INDENT4 "DeviceType: touchNavigation\n"); - break; - case Parameters::DEVICE_TYPE_POINTER: - dump.append(INDENT4 "DeviceType: pointer\n"); - break; - default: - ALOG_ASSERT(false); - } - - dump.appendFormat(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s\n", - toString(mParameters.hasAssociatedDisplay), - toString(mParameters.associatedDisplayIsExternal)); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void TouchInputMapper::configureRawPointerAxes() { - mRawPointerAxes.clear(); -} - -void TouchInputMapper::dumpRawPointerAxes(String8& dump) { - dump.append(INDENT3 "Raw Touch Axes:\n"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); -} - -void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { - int32_t oldDeviceMode = mDeviceMode; - - // Determine device mode. - if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER - && mConfig.pointerGesturesEnabled) { - mSource = AINPUT_SOURCE_MOUSE; - mDeviceMode = DEVICE_MODE_POINTER; - if (hasStylus()) { - mSource |= AINPUT_SOURCE_STYLUS; - } - } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - && mParameters.hasAssociatedDisplay) { - mSource = AINPUT_SOURCE_TOUCHSCREEN; - mDeviceMode = DEVICE_MODE_DIRECT; - if (hasStylus()) { - mSource |= AINPUT_SOURCE_STYLUS; - } - } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { - mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; - mDeviceMode = DEVICE_MODE_NAVIGATION; - } else { - mSource = AINPUT_SOURCE_TOUCHPAD; - mDeviceMode = DEVICE_MODE_UNSCALED; - } - - // Ensure we have valid X and Y axes. - if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { - ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis! " - "The device will be inoperable.", getDeviceName().string()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; - } - - // Raw width and height in the natural orientation. - int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; - int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; - - // Get associated display dimensions. - DisplayViewport newViewport; - if (mParameters.hasAssociatedDisplay) { - if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal, &newViewport)) { - ALOGI(INDENT "Touch device '%s' could not query the properties of its associated " - "display. The device will be inoperable until the display size " - "becomes available.", - getDeviceName().string()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; - } - } else { - newViewport.setNonDisplayViewport(rawWidth, rawHeight); - } - bool viewportChanged = mViewport != newViewport; - if (viewportChanged) { - mViewport = newViewport; - - if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { - // Convert rotated viewport to natural surface coordinates. - int32_t naturalLogicalWidth, naturalLogicalHeight; - int32_t naturalPhysicalWidth, naturalPhysicalHeight; - int32_t naturalPhysicalLeft, naturalPhysicalTop; - int32_t naturalDeviceWidth, naturalDeviceHeight; - switch (mViewport.orientation) { - case DISPLAY_ORIENTATION_90: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom; - naturalPhysicalTop = mViewport.physicalLeft; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_180: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight; - naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - case DISPLAY_ORIENTATION_270: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.physicalTop; - naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_0: - default: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.physicalLeft; - naturalPhysicalTop = mViewport.physicalTop; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - } - - mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth; - mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight; - mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth; - mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight; - - mSurfaceOrientation = mParameters.orientationAware ? - mViewport.orientation : DISPLAY_ORIENTATION_0; - } else { - mSurfaceWidth = rawWidth; - mSurfaceHeight = rawHeight; - mSurfaceLeft = 0; - mSurfaceTop = 0; - mSurfaceOrientation = DISPLAY_ORIENTATION_0; - } - } - - // If moving between pointer modes, need to reset some state. - bool deviceModeChanged = mDeviceMode != oldDeviceMode; - if (deviceModeChanged) { - mOrientedRanges.clear(); - } - - // Create pointer controller if needed. - if (mDeviceMode == DEVICE_MODE_POINTER || - (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { - if (mPointerController == NULL) { - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - } - } else { - mPointerController.clear(); - } - - if (viewportChanged || deviceModeChanged) { - ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " - "display id %d", - getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight, - mSurfaceOrientation, mDeviceMode, mViewport.displayId); - - // Configure X and Y factors. - mXScale = float(mSurfaceWidth) / rawWidth; - mYScale = float(mSurfaceHeight) / rawHeight; - mXTranslate = -mSurfaceLeft; - mYTranslate = -mSurfaceTop; - mXPrecision = 1.0f / mXScale; - mYPrecision = 1.0f / mYScale; - - mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; - mOrientedRanges.x.source = mSource; - mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; - mOrientedRanges.y.source = mSource; - - configureVirtualKeys(); - - // Scale factor for terms that are not oriented in a particular axis. - // If the pixels are square then xScale == yScale otherwise we fake it - // by choosing an average. - mGeometricScale = avg(mXScale, mYScale); - - // Size of diagonal axis. - float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight); - - // Size factors. - if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { - if (mRawPointerAxes.touchMajor.valid - && mRawPointerAxes.touchMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; - } else if (mRawPointerAxes.toolMajor.valid - && mRawPointerAxes.toolMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; - } else { - mSizeScale = 0.0f; - } - - mOrientedRanges.haveTouchSize = true; - mOrientedRanges.haveToolSize = true; - mOrientedRanges.haveSize = true; - - mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; - mOrientedRanges.touchMajor.source = mSource; - mOrientedRanges.touchMajor.min = 0; - mOrientedRanges.touchMajor.max = diagonalSize; - mOrientedRanges.touchMajor.flat = 0; - mOrientedRanges.touchMajor.fuzz = 0; - mOrientedRanges.touchMajor.resolution = 0; - - mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; - mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; - - mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; - mOrientedRanges.toolMajor.source = mSource; - mOrientedRanges.toolMajor.min = 0; - mOrientedRanges.toolMajor.max = diagonalSize; - mOrientedRanges.toolMajor.flat = 0; - mOrientedRanges.toolMajor.fuzz = 0; - mOrientedRanges.toolMajor.resolution = 0; - - mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; - mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; - - mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; - mOrientedRanges.size.source = mSource; - mOrientedRanges.size.min = 0; - mOrientedRanges.size.max = 1.0; - mOrientedRanges.size.flat = 0; - mOrientedRanges.size.fuzz = 0; - mOrientedRanges.size.resolution = 0; - } else { - mSizeScale = 0.0f; - } - - // Pressure factors. - mPressureScale = 0; - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL - || mCalibration.pressureCalibration - == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { - if (mCalibration.havePressureScale) { - mPressureScale = mCalibration.pressureScale; - } else if (mRawPointerAxes.pressure.valid - && mRawPointerAxes.pressure.maxValue != 0) { - mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; - } - } - - mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; - mOrientedRanges.pressure.source = mSource; - mOrientedRanges.pressure.min = 0; - mOrientedRanges.pressure.max = 1.0; - mOrientedRanges.pressure.flat = 0; - mOrientedRanges.pressure.fuzz = 0; - mOrientedRanges.pressure.resolution = 0; - - // Tilt - mTiltXCenter = 0; - mTiltXScale = 0; - mTiltYCenter = 0; - mTiltYScale = 0; - mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; - if (mHaveTilt) { - mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, - mRawPointerAxes.tiltX.maxValue); - mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, - mRawPointerAxes.tiltY.maxValue); - mTiltXScale = M_PI / 180; - mTiltYScale = M_PI / 180; - - mOrientedRanges.haveTilt = true; - - mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; - mOrientedRanges.tilt.source = mSource; - mOrientedRanges.tilt.min = 0; - mOrientedRanges.tilt.max = M_PI_2; - mOrientedRanges.tilt.flat = 0; - mOrientedRanges.tilt.fuzz = 0; - mOrientedRanges.tilt.resolution = 0; - } - - // Orientation - mOrientationScale = 0; - if (mHaveTilt) { - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI; - mOrientedRanges.orientation.max = M_PI; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } else if (mCalibration.orientationCalibration != - Calibration::ORIENTATION_CALIBRATION_NONE) { - if (mCalibration.orientationCalibration - == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { - if (mRawPointerAxes.orientation.valid) { - if (mRawPointerAxes.orientation.maxValue > 0) { - mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue; - } else if (mRawPointerAxes.orientation.minValue < 0) { - mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue; - } else { - mOrientationScale = 0; - } - } - } - - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI_2; - mOrientedRanges.orientation.max = M_PI_2; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } - - // Distance - mDistanceScale = 0; - if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) { - if (mCalibration.distanceCalibration - == Calibration::DISTANCE_CALIBRATION_SCALED) { - if (mCalibration.haveDistanceScale) { - mDistanceScale = mCalibration.distanceScale; - } else { - mDistanceScale = 1.0f; - } - } - - mOrientedRanges.haveDistance = true; - - mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; - mOrientedRanges.distance.source = mSource; - mOrientedRanges.distance.min = - mRawPointerAxes.distance.minValue * mDistanceScale; - mOrientedRanges.distance.max = - mRawPointerAxes.distance.maxValue * mDistanceScale; - mOrientedRanges.distance.flat = 0; - mOrientedRanges.distance.fuzz = - mRawPointerAxes.distance.fuzz * mDistanceScale; - mOrientedRanges.distance.resolution = 0; - } - - // Compute oriented precision, scales and ranges. - // Note that the maximum value reported is an inclusive maximum value so it is one - // unit less than the total width or height of surface. - switch (mSurfaceOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: - mOrientedXPrecision = mYPrecision; - mOrientedYPrecision = mXPrecision; - - mOrientedRanges.x.min = mYTranslate; - mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; - - mOrientedRanges.y.min = mXTranslate; - mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; - break; - - default: - mOrientedXPrecision = mXPrecision; - mOrientedYPrecision = mYPrecision; - - mOrientedRanges.x.min = mXTranslate; - mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; - - mOrientedRanges.y.min = mYTranslate; - mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; - break; - } - - if (mDeviceMode == DEVICE_MODE_POINTER) { - // Compute pointer gesture detection parameters. - float rawDiagonal = hypotf(rawWidth, rawHeight); - float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight); - - // Scale movements such that one whole swipe of the touch pad covers a - // given area relative to the diagonal size of the display when no acceleration - // is applied. - // Assume that the touch pad has a square aspect ratio such that movements in - // X and Y of the same number of raw units cover the same physical distance. - mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio - * displayDiagonal / rawDiagonal; - mPointerYMovementScale = mPointerXMovementScale; - - // Scale zooms to cover a smaller range of the display than movements do. - // This value determines the area around the pointer that is affected by freeform - // pointer gestures. - mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio - * displayDiagonal / rawDiagonal; - mPointerYZoomScale = mPointerXZoomScale; - - // Max width between pointers to detect a swipe gesture is more than some fraction - // of the diagonal axis of the touch pad. Touches that are wider than this are - // translated into freeform gestures. - mPointerGestureMaxSwipeWidth = - mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; - - // Abort current pointer usages because the state has changed. - abortPointerUsage(when, 0 /*policyFlags*/); - } - - // Inform the dispatcher about the changes. - *outResetNeeded = true; - bumpGeneration(); - } -} - -void TouchInputMapper::dumpSurface(String8& dump) { - dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, " - "logicalFrame=[%d, %d, %d, %d], " - "physicalFrame=[%d, %d, %d, %d], " - "deviceSize=[%d, %d]\n", - mViewport.displayId, mViewport.orientation, - mViewport.logicalLeft, mViewport.logicalTop, - mViewport.logicalRight, mViewport.logicalBottom, - mViewport.physicalLeft, mViewport.physicalTop, - mViewport.physicalRight, mViewport.physicalBottom, - mViewport.deviceWidth, mViewport.deviceHeight); - - dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); - dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); - dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); - dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); - dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); -} - -void TouchInputMapper::configureVirtualKeys() { - Vector<VirtualKeyDefinition> virtualKeyDefinitions; - getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); - - mVirtualKeys.clear(); - - if (virtualKeyDefinitions.size() == 0) { - return; - } - - mVirtualKeys.setCapacity(virtualKeyDefinitions.size()); - - int32_t touchScreenLeft = mRawPointerAxes.x.minValue; - int32_t touchScreenTop = mRawPointerAxes.y.minValue; - int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; - int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; - - for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { - const VirtualKeyDefinition& virtualKeyDefinition = - virtualKeyDefinitions[i]; - - mVirtualKeys.add(); - VirtualKey& virtualKey = mVirtualKeys.editTop(); - - virtualKey.scanCode = virtualKeyDefinition.scanCode; - int32_t keyCode; - uint32_t flags; - if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, &keyCode, &flags)) { - ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", - virtualKey.scanCode); - mVirtualKeys.pop(); // drop the key - continue; - } - - virtualKey.keyCode = keyCode; - virtualKey.flags = flags; - - // convert the key definition's display coordinates into touch coordinates for a hit box - int32_t halfWidth = virtualKeyDefinition.width / 2; - int32_t halfHeight = virtualKeyDefinition.height / 2; - - virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) - * touchScreenWidth / mSurfaceWidth + touchScreenLeft; - virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) - * touchScreenWidth / mSurfaceWidth + touchScreenLeft; - virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) - * touchScreenHeight / mSurfaceHeight + touchScreenTop; - virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) - * touchScreenHeight / mSurfaceHeight + touchScreenTop; - } -} - -void TouchInputMapper::dumpVirtualKeys(String8& dump) { - if (!mVirtualKeys.isEmpty()) { - dump.append(INDENT3 "Virtual Keys:\n"); - - for (size_t i = 0; i < mVirtualKeys.size(); i++) { - const VirtualKey& virtualKey = mVirtualKeys.itemAt(i); - dump.appendFormat(INDENT4 "%d: scanCode=%d, keyCode=%d, " - "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", - i, virtualKey.scanCode, virtualKey.keyCode, - virtualKey.hitLeft, virtualKey.hitRight, - virtualKey.hitTop, virtualKey.hitBottom); - } - } -} - -void TouchInputMapper::parseCalibration() { - const PropertyMap& in = getDevice()->getConfiguration(); - Calibration& out = mCalibration; - - // Size - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; - String8 sizeCalibrationString; - if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { - if (sizeCalibrationString == "none") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } else if (sizeCalibrationString == "geometric") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; - } else if (sizeCalibrationString == "diameter") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER; - } else if (sizeCalibrationString == "box") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX; - } else if (sizeCalibrationString == "area") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA; - } else if (sizeCalibrationString != "default") { - ALOGW("Invalid value for touch.size.calibration: '%s'", - sizeCalibrationString.string()); - } - } - - out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), - out.sizeScale); - out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), - out.sizeBias); - out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), - out.sizeIsSummed); - - // Pressure - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; - String8 pressureCalibrationString; - if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { - if (pressureCalibrationString == "none") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } else if (pressureCalibrationString == "physical") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } else if (pressureCalibrationString == "amplitude") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; - } else if (pressureCalibrationString != "default") { - ALOGW("Invalid value for touch.pressure.calibration: '%s'", - pressureCalibrationString.string()); - } - } - - out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), - out.pressureScale); - - // Orientation - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; - String8 orientationCalibrationString; - if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { - if (orientationCalibrationString == "none") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } else if (orientationCalibrationString == "interpolated") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } else if (orientationCalibrationString == "vector") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR; - } else if (orientationCalibrationString != "default") { - ALOGW("Invalid value for touch.orientation.calibration: '%s'", - orientationCalibrationString.string()); - } - } - - // Distance - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT; - String8 distanceCalibrationString; - if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { - if (distanceCalibrationString == "none") { - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; - } else if (distanceCalibrationString == "scaled") { - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; - } else if (distanceCalibrationString != "default") { - ALOGW("Invalid value for touch.distance.calibration: '%s'", - distanceCalibrationString.string()); - } - } - - out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), - out.distanceScale); - - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT; - String8 coverageCalibrationString; - if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { - if (coverageCalibrationString == "none") { - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; - } else if (coverageCalibrationString == "box") { - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX; - } else if (coverageCalibrationString != "default") { - ALOGW("Invalid value for touch.coverage.calibration: '%s'", - coverageCalibrationString.string()); - } - } -} - -void TouchInputMapper::resolveCalibration() { - // Size - if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) { - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; - } - } else { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } - - // Pressure - if (mRawPointerAxes.pressure.valid) { - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } - } else { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } - - // Orientation - if (mRawPointerAxes.orientation.valid) { - if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } - } else { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } - - // Distance - if (mRawPointerAxes.distance.valid) { - if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) { - mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; - } - } else { - mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; - } - - // Coverage - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) { - mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; - } -} - -void TouchInputMapper::dumpCalibration(String8& dump) { - dump.append(INDENT3 "Calibration:\n"); - - // Size - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.size.calibration: none\n"); - break; - case Calibration::SIZE_CALIBRATION_GEOMETRIC: - dump.append(INDENT4 "touch.size.calibration: geometric\n"); - break; - case Calibration::SIZE_CALIBRATION_DIAMETER: - dump.append(INDENT4 "touch.size.calibration: diameter\n"); - break; - case Calibration::SIZE_CALIBRATION_BOX: - dump.append(INDENT4 "touch.size.calibration: box\n"); - break; - case Calibration::SIZE_CALIBRATION_AREA: - dump.append(INDENT4 "touch.size.calibration: area\n"); - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.haveSizeScale) { - dump.appendFormat(INDENT4 "touch.size.scale: %0.3f\n", - mCalibration.sizeScale); - } - - if (mCalibration.haveSizeBias) { - dump.appendFormat(INDENT4 "touch.size.bias: %0.3f\n", - mCalibration.sizeBias); - } - - if (mCalibration.haveSizeIsSummed) { - dump.appendFormat(INDENT4 "touch.size.isSummed: %s\n", - toString(mCalibration.sizeIsSummed)); - } - - // Pressure - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.pressure.calibration: none\n"); - break; - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - dump.append(INDENT4 "touch.pressure.calibration: physical\n"); - break; - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - dump.append(INDENT4 "touch.pressure.calibration: amplitude\n"); - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.havePressureScale) { - dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n", - mCalibration.pressureScale); - } - - // Orientation - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_NONE: - dump.append(INDENT4 "touch.orientation.calibration: none\n"); - break; - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - dump.append(INDENT4 "touch.orientation.calibration: interpolated\n"); - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: - dump.append(INDENT4 "touch.orientation.calibration: vector\n"); - break; - default: - ALOG_ASSERT(false); - } - - // Distance - switch (mCalibration.distanceCalibration) { - case Calibration::DISTANCE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.distance.calibration: none\n"); - break; - case Calibration::DISTANCE_CALIBRATION_SCALED: - dump.append(INDENT4 "touch.distance.calibration: scaled\n"); - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.haveDistanceScale) { - dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n", - mCalibration.distanceScale); - } - - switch (mCalibration.coverageCalibration) { - case Calibration::COVERAGE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.coverage.calibration: none\n"); - break; - case Calibration::COVERAGE_CALIBRATION_BOX: - dump.append(INDENT4 "touch.coverage.calibration: box\n"); - break; - default: - ALOG_ASSERT(false); - } -} - -void TouchInputMapper::reset(nsecs_t when) { - mCursorButtonAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - mTouchButtonAccumulator.reset(getDevice()); - - mPointerVelocityControl.reset(); - mWheelXVelocityControl.reset(); - mWheelYVelocityControl.reset(); - - mCurrentRawPointerData.clear(); - mLastRawPointerData.clear(); - mCurrentCookedPointerData.clear(); - mLastCookedPointerData.clear(); - mCurrentButtonState = 0; - mLastButtonState = 0; - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; - mCurrentFingerIdBits.clear(); - mLastFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mLastStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mLastMouseIdBits.clear(); - mPointerUsage = POINTER_USAGE_NONE; - mSentHoverEnter = false; - mDownTime = 0; - - mCurrentVirtualKey.down = false; - - mPointerGesture.reset(); - mPointerSimple.reset(); - - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - mPointerController->clearSpots(); - } - - InputMapper::reset(when); -} - -void TouchInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mCursorScrollAccumulator.process(rawEvent); - mTouchButtonAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void TouchInputMapper::sync(nsecs_t when) { - // Sync button state. - mCurrentButtonState = mTouchButtonAccumulator.getButtonState() - | mCursorButtonAccumulator.getButtonState(); - - // Sync scroll state. - mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); - mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); - mCursorScrollAccumulator.finishSync(); - - // Sync touch state. - bool havePointerIds = true; - mCurrentRawPointerData.clear(); - syncTouch(when, &havePointerIds); - -#if DEBUG_RAW_EVENTS - if (!havePointerIds) { - ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount); - } else { - ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount, - mLastRawPointerData.touchingIdBits.value, - mCurrentRawPointerData.touchingIdBits.value, - mLastRawPointerData.hoveringIdBits.value, - mCurrentRawPointerData.hoveringIdBits.value); - } -#endif - - // Reset state that we will compute below. - mCurrentFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mCurrentCookedPointerData.clear(); - - if (mDeviceMode == DEVICE_MODE_DISABLED) { - // Drop all input if the device is disabled. - mCurrentRawPointerData.clear(); - mCurrentButtonState = 0; - } else { - // Preprocess pointer data. - if (!havePointerIds) { - assignPointerIds(); - } - - // Handle policy on initial down or hover events. - uint32_t policyFlags = 0; - bool initialDown = mLastRawPointerData.pointerCount == 0 - && mCurrentRawPointerData.pointerCount != 0; - bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; - if (initialDown || buttonsPressed) { - // If this is a touch screen, hide the pointer on an initial down. - if (mDeviceMode == DEVICE_MODE_DIRECT) { - getContext()->fadePointer(); - } - - // Initial downs on external touch devices should wake the device. - // We don't do this for internal touch screens to prevent them from waking - // up in your pocket. - // TODO: Use the input device configuration to control this behavior more finely. - if (getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE_DROPPED; - } - } - - // Synthesize key down from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); - - // Consume raw off-screen touches before cooking pointer data. - // If touches are consumed, subsequent code will not receive any pointer data. - if (consumeRawTouches(when, policyFlags)) { - mCurrentRawPointerData.clear(); - } - - // Cook pointer data. This call populates the mCurrentCookedPointerData structure - // with cooked pointer data that has the same ids and indices as the raw data. - // The following code can use either the raw or cooked data, as needed. - cookPointerData(); - - // Dispatch the touches either directly or by translation through a pointer on screen. - if (mDeviceMode == DEVICE_MODE_POINTER) { - for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mCurrentFingerIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { - mCurrentMouseIdBits.markBit(id); - } - } - for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } - } - - // Stylus takes precedence over all tools, then mouse, then finger. - PointerUsage pointerUsage = mPointerUsage; - if (!mCurrentStylusIdBits.isEmpty()) { - mCurrentMouseIdBits.clear(); - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_STYLUS; - } else if (!mCurrentMouseIdBits.isEmpty()) { - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_MOUSE; - } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) { - pointerUsage = POINTER_USAGE_GESTURES; - } - - dispatchPointerUsage(when, policyFlags, pointerUsage); - } else { - if (mDeviceMode == DEVICE_MODE_DIRECT - && mConfig.showTouches && mPointerController != NULL) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - - mPointerController->setButtonState(mCurrentButtonState); - mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.touchingIdBits); - } - - dispatchHoverExit(when, policyFlags); - dispatchTouches(when, policyFlags); - dispatchHoverEnterAndMove(when, policyFlags); - } - - // Synthesize key up from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); - } - - // Copy current touch to last touch in preparation for the next cycle. - mLastRawPointerData.copyFrom(mCurrentRawPointerData); - mLastCookedPointerData.copyFrom(mCurrentCookedPointerData); - mLastButtonState = mCurrentButtonState; - mLastFingerIdBits = mCurrentFingerIdBits; - mLastStylusIdBits = mCurrentStylusIdBits; - mLastMouseIdBits = mCurrentMouseIdBits; - - // Clear some transient state. - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; -} - -void TouchInputMapper::timeoutExpired(nsecs_t when) { - if (mDeviceMode == DEVICE_MODE_POINTER) { - if (mPointerUsage == POINTER_USAGE_GESTURES) { - dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); - } - } -} - -bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { - // Check for release of a virtual key. - if (mCurrentVirtualKey.down) { - if (mCurrentRawPointerData.touchingIdBits.isEmpty()) { - // Pointer went up while virtual key was down. - mCurrentVirtualKey.down = false; - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); - } - return true; - } - - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); - if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { - // Pointer is still within the space of the virtual key. - return true; - } - } - - // Pointer left virtual key area or another pointer also went down. - // Send key cancellation but do not consume the touch yet. - // This is useful when the user swipes through from the virtual key area - // into the main display surface. - mCurrentVirtualKey.down = false; - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY - | AKEY_EVENT_FLAG_CANCELED); - } - } - - if (mLastRawPointerData.touchingIdBits.isEmpty() - && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { - // Pointer just went down. Check for virtual key press or off-screen touches. - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (!isPointInsideSurface(pointer.x, pointer.y)) { - // If exactly one pointer went down, check for virtual key hit. - // Otherwise we will drop the entire stroke. - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { - const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); - if (virtualKey) { - mCurrentVirtualKey.down = true; - mCurrentVirtualKey.downTime = when; - mCurrentVirtualKey.keyCode = virtualKey->keyCode; - mCurrentVirtualKey.scanCode = virtualKey->scanCode; - mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey( - when, getDevice(), virtualKey->keyCode, virtualKey->scanCode); - - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, - mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_DOWN, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); - } - } - } - return true; - } - } - - // Disable all virtual key touches that happen within a short time interval of the - // most recent touch within the screen area. The idea is to filter out stray - // virtual key presses when interacting with the touch screen. - // - // Problems we're trying to solve: - // - // 1. While scrolling a list or dragging the window shade, the user swipes down into a - // virtual key area that is implemented by a separate touch panel and accidentally - // triggers a virtual key. - // - // 2. While typing in the on screen keyboard, the user taps slightly outside the screen - // area and accidentally triggers a virtual key. This often happens when virtual keys - // are layed out below the screen near to where the on screen keyboard's space bar - // is displayed. - if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { - mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); - } - return false; -} - -void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags) { - int32_t keyCode = mCurrentVirtualKey.keyCode; - int32_t scanCode = mCurrentVirtualKey.scanCode; - nsecs_t downTime = mCurrentVirtualKey.downTime; - int32_t metaState = mContext->getGlobalMetaState(); - policyFlags |= POLICY_FLAG_VIRTUAL; - - NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, - keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); - getListener()->notifyKey(&args); -} - -void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits; - BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits; - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; - - if (currentIdBits == lastIdBits) { - if (!currentIdBits.isEmpty()) { - // No pointer id changes so this is a move event. - // The listener takes care of batching moves so we don't have to deal with that here. - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - currentIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - } else { - // There may be pointers going up and pointers going down and pointers moving - // all at the same time. - BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); - BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); - BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); - BitSet32 dispatchedIdBits(lastIdBits.value); - - // Update last coordinates of pointers that have moved so that we observe the new - // pointer positions at the same time as other pointers that have just gone up. - bool moveNeeded = updateMovedPointers( - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - moveIdBits); - if (buttonState != mLastButtonState) { - moveNeeded = true; - } - - // Dispatch pointer up events. - while (!upIdBits.isEmpty()) { - uint32_t upId = upIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - dispatchedIdBits, upId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - dispatchedIdBits.clearBit(upId); - } - - // Dispatch move events if any of the remaining pointers moved from their old locations. - // Although applications receive new locations as part of individual pointer up - // events, they do not generally handle them except when presented in a move event. - if (moveNeeded) { - ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - dispatchedIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - - // Dispatch pointer down events using the new pointer locations. - while (!downIdBits.isEmpty()) { - uint32_t downId = downIdBits.clearFirstMarkedBit(); - dispatchedIdBits.markBit(downId); - - if (dispatchedIdBits.count() == 1) { - // First pointer is going down. Set down time. - mDownTime = when; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - dispatchedIdBits, downId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - } -} - -void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { - if (mSentHoverEnter && - (mCurrentCookedPointerData.hoveringIdBits.isEmpty() - || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) { - int32_t metaState = getContext()->getGlobalMetaState(); - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - mLastCookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mSentHoverEnter = false; - } -} - -void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { - if (mCurrentCookedPointerData.touchingIdBits.isEmpty() - && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - if (!mSentHoverEnter) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mSentHoverEnter = true; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } -} - -void TouchInputMapper::cookPointerData() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; - - mCurrentCookedPointerData.clear(); - mCurrentCookedPointerData.pointerCount = currentPointerCount; - mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits; - mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits; - - // Walk through the the active pointers and map device coordinates onto - // surface coordinates and adjust for display orientation. - for (uint32_t i = 0; i < currentPointerCount; i++) { - const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i]; - - // Size - float touchMajor, touchMinor, toolMajor, toolMinor, size; - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_GEOMETRIC: - case Calibration::SIZE_CALIBRATION_DIAMETER: - case Calibration::SIZE_CALIBRATION_BOX: - case Calibration::SIZE_CALIBRATION_AREA: - if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) { - touchMajor = in.touchMajor; - touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; - toolMajor = in.toolMajor; - toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; - size = mRawPointerAxes.touchMinor.valid - ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; - } else if (mRawPointerAxes.touchMajor.valid) { - toolMajor = touchMajor = in.touchMajor; - toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid - ? in.touchMinor : in.touchMajor; - size = mRawPointerAxes.touchMinor.valid - ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; - } else if (mRawPointerAxes.toolMajor.valid) { - touchMajor = toolMajor = in.toolMajor; - touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid - ? in.toolMinor : in.toolMajor; - size = mRawPointerAxes.toolMinor.valid - ? avg(in.toolMajor, in.toolMinor) : in.toolMajor; - } else { - ALOG_ASSERT(false, "No touch or tool axes. " - "Size calibration should have been resolved to NONE."); - touchMajor = 0; - touchMinor = 0; - toolMajor = 0; - toolMinor = 0; - size = 0; - } - - if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { - uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count(); - if (touchingCount > 1) { - touchMajor /= touchingCount; - touchMinor /= touchingCount; - toolMajor /= touchingCount; - toolMinor /= touchingCount; - size /= touchingCount; - } - } - - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) { - touchMajor *= mGeometricScale; - touchMinor *= mGeometricScale; - toolMajor *= mGeometricScale; - toolMinor *= mGeometricScale; - } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) { - touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0; - touchMinor = touchMajor; - toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0; - toolMinor = toolMajor; - } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) { - touchMinor = touchMajor; - toolMinor = toolMajor; - } - - mCalibration.applySizeScaleAndBias(&touchMajor); - mCalibration.applySizeScaleAndBias(&touchMinor); - mCalibration.applySizeScaleAndBias(&toolMajor); - mCalibration.applySizeScaleAndBias(&toolMinor); - size *= mSizeScale; - break; - default: - touchMajor = 0; - touchMinor = 0; - toolMajor = 0; - toolMinor = 0; - size = 0; - break; - } - - // Pressure - float pressure; - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - pressure = in.pressure * mPressureScale; - break; - default: - pressure = in.isHovering ? 0 : 1; - break; - } - - // Tilt and Orientation - float tilt; - float orientation; - if (mHaveTilt) { - float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; - float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; - orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); - tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); - } else { - tilt = 0; - - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - orientation = in.orientation * mOrientationScale; - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: { - int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); - int32_t c2 = signExtendNybble(in.orientation & 0x0f); - if (c1 != 0 || c2 != 0) { - orientation = atan2f(c1, c2) * 0.5f; - float confidence = hypotf(c1, c2); - float scale = 1.0f + confidence / 16.0f; - touchMajor *= scale; - touchMinor /= scale; - toolMajor *= scale; - toolMinor /= scale; - } else { - orientation = 0; - } - break; - } - default: - orientation = 0; - } - } - - // Distance - float distance; - switch (mCalibration.distanceCalibration) { - case Calibration::DISTANCE_CALIBRATION_SCALED: - distance = in.distance * mDistanceScale; - break; - default: - distance = 0; - } - - // Coverage - int32_t rawLeft, rawTop, rawRight, rawBottom; - switch (mCalibration.coverageCalibration) { - case Calibration::COVERAGE_CALIBRATION_BOX: - rawLeft = (in.toolMinor & 0xffff0000) >> 16; - rawRight = in.toolMinor & 0x0000ffff; - rawBottom = in.toolMajor & 0x0000ffff; - rawTop = (in.toolMajor & 0xffff0000) >> 16; - break; - default: - rawLeft = rawTop = rawRight = rawBottom = 0; - break; - } - - // X, Y, and the bounding box for coverage information - // Adjust coords for surface orientation. - float x, y, left, top, right, bottom; - switch (mSurfaceOrientation) { - case DISPLAY_ORIENTATION_90: - x = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate; - left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; - top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; - orientation -= M_PI_2; - if (orientation < mOrientedRanges.orientation.min) { - orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); - } - break; - case DISPLAY_ORIENTATION_180: - x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate; - y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate; - left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; - right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; - bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; - top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; - orientation -= M_PI; - if (orientation < mOrientedRanges.orientation.min) { - orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); - } - break; - case DISPLAY_ORIENTATION_270: - x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate; - y = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; - right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; - bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - orientation += M_PI_2; - if (orientation > mOrientedRanges.orientation.max) { - orientation -= (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); - } - break; - default: - x = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - y = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - break; - } - - // Write output coords. - PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i]; - out.clear(); - out.setAxisValue(AMOTION_EVENT_AXIS_X, x); - out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); - out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); - out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); - out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom); - } else { - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); - } - - // Write output properties. - PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i]; - uint32_t id = in.id; - properties.clear(); - properties.id = id; - properties.toolType = in.toolType; - - // Write id index. - mCurrentCookedPointerData.idToIndex[id] = i; - } -} - -void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, - PointerUsage pointerUsage) { - if (pointerUsage != mPointerUsage) { - abortPointerUsage(when, policyFlags); - mPointerUsage = pointerUsage; - } - - switch (mPointerUsage) { - case POINTER_USAGE_GESTURES: - dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); - break; - case POINTER_USAGE_STYLUS: - dispatchPointerStylus(when, policyFlags); - break; - case POINTER_USAGE_MOUSE: - dispatchPointerMouse(when, policyFlags); - break; - default: - break; - } -} - -void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) { - switch (mPointerUsage) { - case POINTER_USAGE_GESTURES: - abortPointerGestures(when, policyFlags); - break; - case POINTER_USAGE_STYLUS: - abortPointerStylus(when, policyFlags); - break; - case POINTER_USAGE_MOUSE: - abortPointerMouse(when, policyFlags); - break; - default: - break; - } - - mPointerUsage = POINTER_USAGE_NONE; -} - -void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, - bool isTimeout) { - // Update current gesture coordinates. - bool cancelPreviousGesture, finishPreviousGesture; - bool sendEvents = preparePointerGestures(when, - &cancelPreviousGesture, &finishPreviousGesture, isTimeout); - if (!sendEvents) { - return; - } - if (finishPreviousGesture) { - cancelPreviousGesture = false; - } - - // Update the pointer presentation and spots. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - if (finishPreviousGesture || cancelPreviousGesture) { - mPointerController->clearSpots(); - } - mPointerController->setSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits); - } else { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - } - - // Show or hide the pointer if needed. - switch (mPointerGesture.currentGestureMode) { - case PointerGesture::NEUTRAL: - case PointerGesture::QUIET: - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS - && (mPointerGesture.lastGestureMode == PointerGesture::SWIPE - || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)) { - // Remind the user of where the pointer is after finishing a gesture with spots. - mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL); - } - break; - case PointerGesture::TAP: - case PointerGesture::TAP_DRAG: - case PointerGesture::BUTTON_CLICK_OR_DRAG: - case PointerGesture::HOVER: - case PointerGesture::PRESS: - // Unfade the pointer when the current gesture manipulates the - // area directly under the pointer. - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - break; - case PointerGesture::SWIPE: - case PointerGesture::FREEFORM: - // Fade the pointer when the current gesture manipulates a different - // area and there are spots to guide the user experience. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } else { - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } - break; - } - - // Send events! - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; - - // Update last coordinates of pointers that have moved so that we observe the new - // pointer positions at the same time as other pointers that have just gone up. - bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP - || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG - || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG - || mPointerGesture.currentGestureMode == PointerGesture::PRESS - || mPointerGesture.currentGestureMode == PointerGesture::SWIPE - || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM; - bool moveNeeded = false; - if (down && !cancelPreviousGesture && !finishPreviousGesture - && !mPointerGesture.lastGestureIdBits.isEmpty() - && !mPointerGesture.currentGestureIdBits.isEmpty()) { - BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value - & mPointerGesture.lastGestureIdBits.value); - moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - movedGestureIdBits); - if (buttonState != mLastButtonState) { - moveNeeded = true; - } - } - - // Send motion events for all pointers that went up or were canceled. - BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); - if (!dispatchedGestureIdBits.isEmpty()) { - if (cancelPreviousGesture) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - - dispatchedGestureIdBits.clear(); - } else { - BitSet32 upGestureIdBits; - if (finishPreviousGesture) { - upGestureIdBits = dispatchedGestureIdBits; - } else { - upGestureIdBits.value = dispatchedGestureIdBits.value - & ~mPointerGesture.currentGestureIdBits.value; - } - while (!upGestureIdBits.isEmpty()) { - uint32_t id = upGestureIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, id, - 0, 0, mPointerGesture.downTime); - - dispatchedGestureIdBits.clearBit(id); - } - } - } - - // Send motion events for all pointers that moved. - if (moveNeeded) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - dispatchedGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } - - // Send motion events for all pointers that went down. - if (down) { - BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value - & ~dispatchedGestureIdBits.value); - while (!downGestureIdBits.isEmpty()) { - uint32_t id = downGestureIdBits.clearFirstMarkedBit(); - dispatchedGestureIdBits.markBit(id); - - if (dispatchedGestureIdBits.count() == 1) { - mPointerGesture.downTime = when; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - dispatchedGestureIdBits, id, - 0, 0, mPointerGesture.downTime); - } - } - - // Send motion events for hover. - if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } else if (dispatchedGestureIdBits.isEmpty() - && !mPointerGesture.lastGestureIdBits.isEmpty()) { - // Synthesize a hover move event after all pointers go up to indicate that - // the pointer is hovering again even if the user is not currently touching - // the touch pad. This ensures that a view will receive a fresh hover enter - // event after a tap. - float x, y; - mPointerController->getPosition(&x, &y); - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - - PointerCoords pointerCoords; - pointerCoords.clear(); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mViewport.displayId, 1, &pointerProperties, &pointerCoords, - 0, 0, mPointerGesture.downTime); - getListener()->notifyMotion(&args); - } - - // Update state. - mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode; - if (!down) { - mPointerGesture.lastGestureIdBits.clear(); - } else { - mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits; - for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - mPointerGesture.lastGestureProperties[index].copyFrom( - mPointerGesture.currentGestureProperties[index]); - mPointerGesture.lastGestureCoords[index].copyFrom( - mPointerGesture.currentGestureCoords[index]); - mPointerGesture.lastGestureIdToIndex[id] = index; - } - } -} - -void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) { - // Cancel previously dispatches pointers. - if (!mPointerGesture.lastGestureIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - mPointerGesture.lastGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } - - // Reset the current pointer gesture. - mPointerGesture.reset(); - mPointerVelocityControl.reset(); - - // Remove any current spots. - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - mPointerController->clearSpots(); - } -} - -bool TouchInputMapper::preparePointerGestures(nsecs_t when, - bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) { - *outCancelPreviousGesture = false; - *outFinishPreviousGesture = false; - - // Handle TAP timeout. - if (isTimeout) { -#if DEBUG_GESTURES - ALOGD("Gestures: Processing timeout"); -#endif - - if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - // The tap/drag timeout has not yet expired. - getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime - + mConfig.pointerGestureTapDragInterval); - } else { - // The tap is finished. -#if DEBUG_GESTURES - ALOGD("Gestures: TAP finished"); -#endif - *outFinishPreviousGesture = true; - - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; - mPointerGesture.currentGestureIdBits.clear(); - - mPointerVelocityControl.reset(); - return true; - } - } - - // We did not handle this timeout. - return false; - } - - const uint32_t currentFingerCount = mCurrentFingerIdBits.count(); - const uint32_t lastFingerCount = mLastFingerIdBits.count(); - - // Update the velocity tracker. - { - VelocityTracker::Position positions[MAX_POINTERS]; - uint32_t count = 0; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - positions[count].x = pointer.x * mPointerXMovementScale; - positions[count].y = pointer.y * mPointerYMovementScale; - } - mPointerGesture.velocityTracker.addMovement(when, - mCurrentFingerIdBits, positions); - } - - // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning - // to NEUTRAL, then we should not generate tap event. - if (mPointerGesture.lastGestureMode != PointerGesture::HOVER - && mPointerGesture.lastGestureMode != PointerGesture::TAP - && mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) { - mPointerGesture.resetTap(); - } - - // Pick a new active touch id if needed. - // Choose an arbitrary pointer that just went down, if there is one. - // Otherwise choose an arbitrary remaining pointer. - // This guarantees we always have an active touch id when there is at least one pointer. - // We keep the same active touch id for as long as possible. - bool activeTouchChanged = false; - int32_t lastActiveTouchId = mPointerGesture.activeTouchId; - int32_t activeTouchId = lastActiveTouchId; - if (activeTouchId < 0) { - if (!mCurrentFingerIdBits.isEmpty()) { - activeTouchChanged = true; - activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); - mPointerGesture.firstTouchTime = when; - } - } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) { - activeTouchChanged = true; - if (!mCurrentFingerIdBits.isEmpty()) { - activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); - } else { - activeTouchId = mPointerGesture.activeTouchId = -1; - } - } - - // Determine whether we are in quiet time. - bool isQuietTime = false; - if (activeTouchId < 0) { - mPointerGesture.resetQuietTime(); - } else { - isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval; - if (!isQuietTime) { - if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS - || mPointerGesture.lastGestureMode == PointerGesture::SWIPE - || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) - && currentFingerCount < 2) { - // Enter quiet time when exiting swipe or freeform state. - // This is to prevent accidentally entering the hover state and flinging the - // pointer when finishing a swipe and there is still one pointer left onscreen. - isQuietTime = true; - } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG - && currentFingerCount >= 2 - && !isPointerDown(mCurrentButtonState)) { - // Enter quiet time when releasing the button and there are still two or more - // fingers down. This may indicate that one finger was used to press the button - // but it has not gone up yet. - isQuietTime = true; - } - if (isQuietTime) { - mPointerGesture.quietTime = when; - } - } - } - - // Switch states based on button and pointer state. - if (isQuietTime) { - // Case 1: Quiet time. (QUIET) -#if DEBUG_GESTURES - ALOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime - + mConfig.pointerGestureQuietInterval - when) * 0.000001f); -#endif - if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) { - *outFinishPreviousGesture = true; - } - - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::QUIET; - mPointerGesture.currentGestureIdBits.clear(); - - mPointerVelocityControl.reset(); - } else if (isPointerDown(mCurrentButtonState)) { - // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) - // The pointer follows the active touch point. - // Emit DOWN, MOVE, UP events at the pointer location. - // - // Only the active touch matters; other fingers are ignored. This policy helps - // to handle the case where the user places a second finger on the touch pad - // to apply the necessary force to depress an integrated button below the surface. - // We don't want the second finger to be delivered to applications. - // - // For this to work well, we need to make sure to track the pointer that is really - // active. If the user first puts one finger down to click then adds another - // finger to drag then the active pointer should switch to the finger that is - // being dragged. -#if DEBUG_GESTURES - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " - "currentFingerCount=%d", activeTouchId, currentFingerCount); -#endif - // Reset state when just starting. - if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) { - *outFinishPreviousGesture = true; - mPointerGesture.activeGestureId = 0; - } - - // Switch pointers if needed. - // Find the fastest pointer and follow it. - if (activeTouchId >= 0 && currentFingerCount > 1) { - int32_t bestId = -1; - float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - float vx, vy; - if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { - float speed = hypotf(vx, vy); - if (speed > bestSpeed) { - bestId = id; - bestSpeed = speed; - } - } - } - if (bestId >= 0 && bestId != activeTouchId) { - mPointerGesture.activeTouchId = activeTouchId = bestId; - activeTouchChanged = true; -#if DEBUG_GESTURES - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " - "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); -#endif - } - } - - if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); - float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; - float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. - // When using spots, the click will occur at the position of the anchor - // spot and all other spots will move there. - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - float x, y; - mPointerController->getPosition(&x, &y); - - mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG; - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (currentFingerCount == 0) { - // Case 3. No fingers down and button is not pressed. (NEUTRAL) - if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { - *outFinishPreviousGesture = true; - } - - // Watch for taps coming out of HOVER or TAP_DRAG mode. - // Checking for taps after TAP_DRAG allows us to detect double-taps. - bool tapped = false; - if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER - || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) - && lastFingerCount == 1) { - if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - float x, y; - mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop - && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { -#if DEBUG_GESTURES - ALOGD("Gestures: TAP"); -#endif - - mPointerGesture.tapUpTime = when; - getContext()->requestTimeoutAtTime(when - + mConfig.pointerGestureTapDragInterval); - - mPointerGesture.activeGestureId = 0; - mPointerGesture.currentGestureMode = PointerGesture::TAP; - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit( - mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[ - mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = - mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_X, mPointerGesture.tapX); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_Y, mPointerGesture.tapY); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - - tapped = true; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", - x - mPointerGesture.tapX, - y - mPointerGesture.tapY); -#endif - } - } else { -#if DEBUG_GESTURES - if (mPointerGesture.tapDownTime != LLONG_MIN) { - ALOGD("Gestures: Not a TAP, %0.3fms since down", - (when - mPointerGesture.tapDownTime) * 0.000001f); - } else { - ALOGD("Gestures: Not a TAP, incompatible mode transitions"); - } -#endif - } - } - - mPointerVelocityControl.reset(); - - if (!tapped) { -#if DEBUG_GESTURES - ALOGD("Gestures: NEUTRAL"); -#endif - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; - mPointerGesture.currentGestureIdBits.clear(); - } - } else if (currentFingerCount == 1) { - // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) - // The pointer follows the active touch point. - // When in HOVER, emit HOVER_MOVE events at the pointer location. - // When in TAP_DRAG, emit MOVE events at the pointer location. - ALOG_ASSERT(activeTouchId >= 0); - - mPointerGesture.currentGestureMode = PointerGesture::HOVER; - if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - float x, y; - mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop - && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { - mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", - x - mPointerGesture.tapX, - y - mPointerGesture.tapY); -#endif - } - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up", - (when - mPointerGesture.tapUpTime) * 0.000001f); -#endif - } - } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) { - mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; - } - - if (mLastFingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); - float deltaX = (currentPointer.x - lastPointer.x) - * mPointerXMovementScale; - float deltaY = (currentPointer.y - lastPointer.y) - * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. - // When using spots, the hover or drag will occur at the position of the anchor spot. - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - bool down; - if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) { -#if DEBUG_GESTURES - ALOGD("Gestures: TAP_DRAG"); -#endif - down = true; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: HOVER"); -#endif - if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) { - *outFinishPreviousGesture = true; - } - mPointerGesture.activeGestureId = 0; - down = false; - } - - float x, y; - mPointerController->getPosition(&x, &y); - - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - down ? 1.0f : 0.0f); - - if (lastFingerCount == 0 && currentFingerCount != 0) { - mPointerGesture.resetTap(); - mPointerGesture.tapDownTime = when; - mPointerGesture.tapX = x; - mPointerGesture.tapY = y; - } - } else { - // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM) - // We need to provide feedback for each finger that goes down so we cannot wait - // for the fingers to move before deciding what to do. - // - // The ambiguous case is deciding what to do when there are two fingers down but they - // have not moved enough to determine whether they are part of a drag or part of a - // freeform gesture, or just a press or long-press at the pointer location. - // - // When there are two fingers we start with the PRESS hypothesis and we generate a - // down at the pointer location. - // - // When the two fingers move enough or when additional fingers are added, we make - // a decision to transition into SWIPE or FREEFORM mode accordingly. - ALOG_ASSERT(activeTouchId >= 0); - - bool settled = when >= mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval; - if (mPointerGesture.lastGestureMode != PointerGesture::PRESS - && mPointerGesture.lastGestureMode != PointerGesture::SWIPE - && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { - *outFinishPreviousGesture = true; - } else if (!settled && currentFingerCount > lastFingerCount) { - // Additional pointers have gone down but not yet settled. - // Reset the gesture. -#if DEBUG_GESTURES - ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " - "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval - when) - * 0.000001f); -#endif - *outCancelPreviousGesture = true; - } else { - // Continue previous gesture. - mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; - } - - if (*outFinishPreviousGesture || *outCancelPreviousGesture) { - mPointerGesture.currentGestureMode = PointerGesture::PRESS; - mPointerGesture.activeGestureId = 0; - mPointerGesture.referenceIdBits.clear(); - mPointerVelocityControl.reset(); - - // Use the centroid and pointer location as the reference points for the gesture. -#if DEBUG_GESTURES - ALOGD("Gestures: Using centroid as reference for MULTITOUCH, " - "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval - when) - * 0.000001f); -#endif - mCurrentRawPointerData.getCentroidOfTouchingPointers( - &mPointerGesture.referenceTouchX, - &mPointerGesture.referenceTouchY); - mPointerController->getPosition(&mPointerGesture.referenceGestureX, - &mPointerGesture.referenceGestureY); - } - - // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentFingerIdBits.value - & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - mPointerGesture.referenceDeltas[id].dx = 0; - mPointerGesture.referenceDeltas[id].dy = 0; - } - mPointerGesture.referenceIdBits = mCurrentFingerIdBits; - - // Add delta for all fingers and calculate a common movement delta. - float commonDeltaX = 0, commonDeltaY = 0; - BitSet32 commonIdBits(mLastFingerIdBits.value - & mCurrentFingerIdBits.value); - for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { - bool first = (idBits == commonIdBits); - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id); - const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx += cpd.x - lpd.x; - delta.dy += cpd.y - lpd.y; - - if (first) { - commonDeltaX = delta.dx; - commonDeltaY = delta.dy; - } else { - commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); - commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); - } - } - - // Consider transitions from PRESS to SWIPE or MULTITOUCH. - if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { - float dist[MAX_POINTER_ID + 1]; - int32_t distOverThreshold = 0; - for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - dist[id] = hypotf(delta.dx * mPointerXZoomScale, - delta.dy * mPointerYZoomScale); - if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) { - distOverThreshold += 1; - } - } - - // Only transition when at least two pointers have moved further than - // the minimum distance threshold. - if (distOverThreshold >= 2) { - if (currentFingerCount > 2) { - // There are more than two pointers, switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are exactly two pointers. - BitSet32 idBits(mCurrentFingerIdBits); - uint32_t id1 = idBits.clearFirstMarkedBit(); - uint32_t id2 = idBits.firstMarkedBit(); - const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1); - const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2); - float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); - if (mutualDistance > mPointerGestureMaxSwipeWidth) { - // There are two pointers but they are too far apart for a SWIPE, - // switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", - mutualDistance, mPointerGestureMaxSwipeWidth); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are two pointers. Wait for both pointers to start moving - // before deciding whether this is a SWIPE or FREEFORM gesture. - float dist1 = dist[id1]; - float dist2 = dist[id2]; - if (dist1 >= mConfig.pointerGestureMultitouchMinDistance - && dist2 >= mConfig.pointerGestureMultitouchMinDistance) { - // Calculate the dot product of the displacement vectors. - // When the vectors are oriented in approximately the same direction, - // the angle betweeen them is near zero and the cosine of the angle - // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). - PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; - PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; - float dx1 = delta1.dx * mPointerXZoomScale; - float dy1 = delta1.dy * mPointerYZoomScale; - float dx2 = delta2.dx * mPointerXZoomScale; - float dy2 = delta2.dy * mPointerYZoomScale; - float dot = dx1 * dx2 + dy1 * dy2; - float cosine = dot / (dist1 * dist2); // denominator always > 0 - if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { - // Pointers are moving in the same direction. Switch to SWIPE. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to SWIPE, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f >= %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, - dist2, mConfig.pointerGestureMultitouchMinDistance, - cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); -#endif - mPointerGesture.currentGestureMode = PointerGesture::SWIPE; - } else { - // Pointers are moving in different directions. Switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f < %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, - dist2, mConfig.pointerGestureMultitouchMinDistance, - cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } - } - } - } - } - } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { - // Switch from SWIPE to FREEFORM if additional pointers go down. - // Cancel previous gesture. - if (currentFingerCount > 2) { -#if DEBUG_GESTURES - ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } - } - - // Move the reference points based on the overall group motion of the fingers - // except in PRESS mode while waiting for a transition to occur. - if (mPointerGesture.currentGestureMode != PointerGesture::PRESS - && (commonDeltaX || commonDeltaY)) { - for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx = 0; - delta.dy = 0; - } - - mPointerGesture.referenceTouchX += commonDeltaX; - mPointerGesture.referenceTouchY += commonDeltaY; - - commonDeltaX *= mPointerXMovementScale; - commonDeltaY *= mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); - mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); - - mPointerGesture.referenceGestureX += commonDeltaX; - mPointerGesture.referenceGestureY += commonDeltaY; - } - - // Report gestures. - if (mPointerGesture.currentGestureMode == PointerGesture::PRESS - || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { - // PRESS or SWIPE mode. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); -#endif - ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); - - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, - mPointerGesture.referenceGestureX); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, - mPointerGesture.referenceGestureY); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { - // FREEFORM mode. -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); -#endif - ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); - - mPointerGesture.currentGestureIdBits.clear(); - - BitSet32 mappedTouchIdBits; - BitSet32 usedGestureIdBits; - if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { - // Initially, assign the active gesture id to the active touch point - // if there is one. No other touch id bits are mapped yet. - if (!*outCancelPreviousGesture) { - mappedTouchIdBits.markBit(activeTouchId); - usedGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] = - mPointerGesture.activeGestureId; - } else { - mPointerGesture.activeGestureId = -1; - } - } else { - // Otherwise, assume we mapped all touches from the previous frame. - // Reuse all mappings that are still applicable. - mappedTouchIdBits.value = mLastFingerIdBits.value - & mCurrentFingerIdBits.value; - usedGestureIdBits = mPointerGesture.lastGestureIdBits; - - // Check whether we need to choose a new active gesture id because the - // current went went up. - for (BitSet32 upTouchIdBits(mLastFingerIdBits.value - & ~mCurrentFingerIdBits.value); - !upTouchIdBits.isEmpty(); ) { - uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); - uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; - if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) { - mPointerGesture.activeGestureId = -1; - break; - } - } - } - -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM follow up " - "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, " - "activeGestureId=%d", - mappedTouchIdBits.value, usedGestureIdBits.value, - mPointerGesture.activeGestureId); -#endif - - BitSet32 idBits(mCurrentFingerIdBits); - for (uint32_t i = 0; i < currentFingerCount; i++) { - uint32_t touchId = idBits.clearFirstMarkedBit(); - uint32_t gestureId; - if (!mappedTouchIdBits.hasBit(touchId)) { - gestureId = usedGestureIdBits.markFirstUnmarkedBit(); - mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM " - "new mapping for touch id %d -> gesture id %d", - touchId, gestureId); -#endif - } else { - gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM " - "existing mapping for touch id %d -> gesture id %d", - touchId, gestureId); -#endif - } - mPointerGesture.currentGestureIdBits.markBit(gestureId); - mPointerGesture.currentGestureIdToIndex[gestureId] = i; - - const RawPointerData::Pointer& pointer = - mCurrentRawPointerData.pointerForId(touchId); - float deltaX = (pointer.x - mPointerGesture.referenceTouchX) - * mPointerXZoomScale; - float deltaY = (pointer.y - mPointerGesture.referenceTouchY) - * mPointerYZoomScale; - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - - mPointerGesture.currentGestureProperties[i].clear(); - mPointerGesture.currentGestureProperties[i].id = gestureId; - mPointerGesture.currentGestureProperties[i].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[i].clear(); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } - - if (mPointerGesture.activeGestureId < 0) { - mPointerGesture.activeGestureId = - mPointerGesture.currentGestureIdBits.firstMarkedBit(); -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM new " - "activeGestureId=%d", mPointerGesture.activeGestureId); -#endif - } - } - } - - mPointerController->setButtonState(mCurrentButtonState); - -#if DEBUG_GESTURES - ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " - "currentGestureMode=%d, currentGestureIdBits=0x%08x, " - "lastGestureMode=%d, lastGestureIdBits=0x%08x", - toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture), - mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value, - mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value); - for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; - const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; - ALOGD(" currentGesture[%d]: index=%d, toolType=%d, " - "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, - coords.getAxisValue(AMOTION_EVENT_AXIS_X), - coords.getAxisValue(AMOTION_EVENT_AXIS_Y), - coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } - for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; - const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; - const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; - ALOGD(" lastGesture[%d]: index=%d, toolType=%d, " - "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, - coords.getAxisValue(AMOTION_EVENT_AXIS_X), - coords.getAxisValue(AMOTION_EVENT_AXIS_Y), - coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } -#endif - return true; -} - -void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - bool down, hovering; - if (!mCurrentStylusIdBits.isEmpty()) { - uint32_t id = mCurrentStylusIdBits.firstMarkedBit(); - uint32_t index = mCurrentCookedPointerData.idToIndex[id]; - float x = mCurrentCookedPointerData.pointerCoords[index].getX(); - float y = mCurrentCookedPointerData.pointerCoords[index].getY(); - mPointerController->setPosition(x, y); - - hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id); - down = !hovering; - - mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerSimple.currentProperties.id = 0; - mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[index].toolType; - } else { - down = false; - hovering = false; - } - - dispatchPointerSimple(when, policyFlags, down, hovering); -} - -void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) { - abortPointerSimple(when, policyFlags); -} - -void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - bool down, hovering; - if (!mCurrentMouseIdBits.isEmpty()) { - uint32_t id = mCurrentMouseIdBits.firstMarkedBit(); - uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id]; - if (mLastMouseIdBits.hasBit(id)) { - uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id]; - float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x - - mLastRawPointerData.pointers[lastIndex].x) - * mPointerXMovementScale; - float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y - - mLastRawPointerData.pointers[lastIndex].y) - * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - down = isPointerDown(mCurrentButtonState); - hovering = !down; - - float x, y; - mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom( - mCurrentCookedPointerData.pointerCoords[currentIndex]); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - hovering ? 0.0f : 1.0f); - mPointerSimple.currentProperties.id = 0; - mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[currentIndex].toolType; - } else { - mPointerVelocityControl.reset(); - - down = false; - hovering = false; - } - - dispatchPointerSimple(when, policyFlags, down, hovering); -} - -void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { - abortPointerSimple(when, policyFlags); - - mPointerVelocityControl.reset(); -} - -void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, - bool down, bool hovering) { - int32_t metaState = getContext()->getGlobalMetaState(); - - if (mPointerController != NULL) { - if (down || hovering) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentButtonState); - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } - } - - if (mPointerSimple.down && !down) { - mPointerSimple.down = false; - - // Send up. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (mPointerSimple.hovering && !hovering) { - mPointerSimple.hovering = false; - - // Send hover exit. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (down) { - if (!mPointerSimple.down) { - mPointerSimple.down = true; - mPointerSimple.downTime = when; - - // Send down. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - // Send move. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (hovering) { - if (!mPointerSimple.hovering) { - mPointerSimple.hovering = true; - - // Send hover enter. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - // Send hover move. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (mCurrentRawVScroll || mCurrentRawHScroll) { - float vscroll = mCurrentRawVScroll; - float hscroll = mCurrentRawHScroll; - mWheelYVelocityControl.move(when, NULL, &vscroll); - mWheelXVelocityControl.move(when, &hscroll, NULL); - - // Send scroll. - PointerCoords pointerCoords; - pointerCoords.copyFrom(mPointerSimple.currentCoords); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &pointerCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - // Save state. - if (down || hovering) { - mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); - mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); - } else { - mPointerSimple.reset(); - } -} - -void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - dispatchPointerSimple(when, policyFlags, false, false); -} - -void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, - const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, - int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { - PointerCoords pointerCoords[MAX_POINTERS]; - PointerProperties pointerProperties[MAX_POINTERS]; - uint32_t pointerCount = 0; - while (!idBits.isEmpty()) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = idToIndex[id]; - pointerProperties[pointerCount].copyFrom(properties[index]); - pointerCoords[pointerCount].copyFrom(coords[index]); - - if (changedId >= 0 && id == uint32_t(changedId)) { - action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - } - - pointerCount += 1; - } - - ALOG_ASSERT(pointerCount != 0); - - if (changedId >= 0 && pointerCount == 1) { - // Replace initial down and final up action. - // We can compare the action without masking off the changed pointer index - // because we know the index is 0. - if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { - action = AMOTION_EVENT_ACTION_DOWN; - } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { - action = AMOTION_EVENT_ACTION_UP; - } else { - // Can't happen. - ALOG_ASSERT(false); - } - } - - NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, - action, flags, metaState, buttonState, edgeFlags, - mViewport.displayId, pointerCount, pointerProperties, pointerCoords, - xPrecision, yPrecision, downTime); - getListener()->notifyMotion(&args); -} - -bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties, - const PointerCoords* inCoords, const uint32_t* inIdToIndex, - PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex, - BitSet32 idBits) const { - bool changed = false; - while (!idBits.isEmpty()) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t inIndex = inIdToIndex[id]; - uint32_t outIndex = outIdToIndex[id]; - - const PointerProperties& curInProperties = inProperties[inIndex]; - const PointerCoords& curInCoords = inCoords[inIndex]; - PointerProperties& curOutProperties = outProperties[outIndex]; - PointerCoords& curOutCoords = outCoords[outIndex]; - - if (curInProperties != curOutProperties) { - curOutProperties.copyFrom(curInProperties); - changed = true; - } - - if (curInCoords != curOutCoords) { - curOutCoords.copyFrom(curInCoords); - changed = true; - } - } - return changed; -} - -void TouchInputMapper::fadePointer() { - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - -bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { - return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue - && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue; -} - -const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit( - int32_t x, int32_t y) { - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " - "left=%d, top=%d, right=%d, bottom=%d", - x, y, - virtualKey.keyCode, virtualKey.scanCode, - virtualKey.hitLeft, virtualKey.hitTop, - virtualKey.hitRight, virtualKey.hitBottom); -#endif - - if (virtualKey.isHit(x, y)) { - return & virtualKey; - } - } - - return NULL; -} - -void TouchInputMapper::assignPointerIds() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; - uint32_t lastPointerCount = mLastRawPointerData.pointerCount; - - mCurrentRawPointerData.clearIdBits(); - - if (currentPointerCount == 0) { - // No pointers to assign. - return; - } - - if (lastPointerCount == 0) { - // All pointers are new. - for (uint32_t i = 0; i < currentPointerCount; i++) { - uint32_t id = i; - mCurrentRawPointerData.pointers[i].id = id; - mCurrentRawPointerData.idToIndex[id] = i; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i)); - } - return; - } - - if (currentPointerCount == 1 && lastPointerCount == 1 - && mCurrentRawPointerData.pointers[0].toolType - == mLastRawPointerData.pointers[0].toolType) { - // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = mLastRawPointerData.pointers[0].id; - mCurrentRawPointerData.pointers[0].id = id; - mCurrentRawPointerData.idToIndex[id] = 0; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0)); - return; - } - - // General case. - // We build a heap of squared euclidean distances between current and last pointers - // associated with the current and last pointer indices. Then, we find the best - // match (by distance) for each current pointer. - // The pointers must have the same tool type but it is possible for them to - // transition from hovering to touching or vice-versa while retaining the same id. - PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; - - uint32_t heapSize = 0; - for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; - currentPointerIndex++) { - for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; - lastPointerIndex++) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointers[currentPointerIndex]; - const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointers[lastPointerIndex]; - if (currentPointer.toolType == lastPointer.toolType) { - int64_t deltaX = currentPointer.x - lastPointer.x; - int64_t deltaY = currentPointer.y - lastPointer.y; - - uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); - - // Insert new element into the heap (sift up). - heap[heapSize].currentPointerIndex = currentPointerIndex; - heap[heapSize].lastPointerIndex = lastPointerIndex; - heap[heapSize].distance = distance; - heapSize += 1; - } - } - } - - // Heapify - for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { - startIndex -= 1; - for (uint32_t parentIndex = startIndex; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - } - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - - // Pull matches out by increasing order of distance. - // To avoid reassigning pointers that have already been matched, the loop keeps track - // of which last and current pointers have been matched using the matchedXXXBits variables. - // It also tracks the used pointer id bits. - BitSet32 matchedLastBits(0); - BitSet32 matchedCurrentBits(0); - BitSet32 usedIdBits(0); - bool first = true; - for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) { - while (heapSize > 0) { - if (first) { - // The first time through the loop, we just consume the root element of - // the heap (the one with smallest distance). - first = false; - } else { - // Previous iterations consumed the root element of the heap. - // Pop root element off of the heap (sift down). - heap[0] = heap[heapSize]; - for (uint32_t parentIndex = 0; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - } - - heapSize -= 1; - - uint32_t currentPointerIndex = heap[0].currentPointerIndex; - if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched - - uint32_t lastPointerIndex = heap[0].lastPointerIndex; - if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched - - matchedCurrentBits.markBit(currentPointerIndex); - matchedLastBits.markBit(lastPointerIndex); - - uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id; - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); - usedIdBits.markBit(id); - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld", - lastPointerIndex, currentPointerIndex, id, heap[0].distance); -#endif - break; - } - } - - // Assign fresh ids to pointers that were not matched in the process. - for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) { - uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); - uint32_t id = usedIdBits.markFirstUnmarkedBit(); - - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - assigned: cur=%d, id=%d", - currentPointerIndex, id); -#endif - } -} - -int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) { - return AKEY_STATE_VIRTUAL; - } - - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - if (virtualKey.keyCode == keyCode) { - return AKEY_STATE_UP; - } - } - - return AKEY_STATE_UNKNOWN; -} - -int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) { - return AKEY_STATE_VIRTUAL; - } - - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - if (virtualKey.scanCode == scanCode) { - return AKEY_STATE_UP; - } - } - - return AKEY_STATE_UNKNOWN; -} - -bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - - for (size_t i = 0; i < numCodes; i++) { - if (virtualKey.keyCode == keyCodes[i]) { - outFlags[i] = 1; - } - } - } - - return true; -} - - -// --- SingleTouchInputMapper --- - -SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { -} - -SingleTouchInputMapper::~SingleTouchInputMapper() { -} - -void SingleTouchInputMapper::reset(nsecs_t when) { - mSingleTouchMotionAccumulator.reset(getDevice()); - - TouchInputMapper::reset(when); -} - -void SingleTouchInputMapper::process(const RawEvent* rawEvent) { - TouchInputMapper::process(rawEvent); - - mSingleTouchMotionAccumulator.process(rawEvent); -} - -void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { - if (mTouchButtonAccumulator.isToolActive()) { - mCurrentRawPointerData.pointerCount = 1; - mCurrentRawPointerData.idToIndex[0] = 0; - - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE - && (mTouchButtonAccumulator.isHovering() - || (mRawPointerAxes.pressure.valid - && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); - mCurrentRawPointerData.markIdBit(0, isHovering); - - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0]; - outPointer.id = 0; - outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); - outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); - outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); - outPointer.touchMajor = 0; - outPointer.touchMinor = 0; - outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); - outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); - outPointer.orientation = 0; - outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance(); - outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); - outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); - outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - } - outPointer.isHovering = isHovering; - } -} - -void SingleTouchInputMapper::configureRawPointerAxes() { - TouchInputMapper::configureRawPointerAxes(); - - getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x); - getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y); - getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure); - getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor); - getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance); - getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX); - getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY); -} - -bool SingleTouchInputMapper::hasStylus() const { - return mTouchButtonAccumulator.hasStylus(); -} - - -// --- MultiTouchInputMapper --- - -MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { -} - -MultiTouchInputMapper::~MultiTouchInputMapper() { -} - -void MultiTouchInputMapper::reset(nsecs_t when) { - mMultiTouchMotionAccumulator.reset(getDevice()); - - mPointerIdBits.clear(); - - TouchInputMapper::reset(when); -} - -void MultiTouchInputMapper::process(const RawEvent* rawEvent) { - TouchInputMapper::process(rawEvent); - - mMultiTouchMotionAccumulator.process(rawEvent); -} - -void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { - size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); - size_t outCount = 0; - BitSet32 newPointerIdBits; - - for (size_t inIndex = 0; inIndex < inCount; inIndex++) { - const MultiTouchMotionAccumulator::Slot* inSlot = - mMultiTouchMotionAccumulator.getSlot(inIndex); - if (!inSlot->isInUse()) { - continue; - } - - if (outCount >= MAX_POINTERS) { -#if DEBUG_POINTERS - ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; " - "ignoring the rest.", - getDeviceName().string(), MAX_POINTERS); -#endif - break; // too many fingers! - } - - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount]; - outPointer.x = inSlot->getX(); - outPointer.y = inSlot->getY(); - outPointer.pressure = inSlot->getPressure(); - outPointer.touchMajor = inSlot->getTouchMajor(); - outPointer.touchMinor = inSlot->getTouchMinor(); - outPointer.toolMajor = inSlot->getToolMajor(); - outPointer.toolMinor = inSlot->getToolMinor(); - outPointer.orientation = inSlot->getOrientation(); - outPointer.distance = inSlot->getDistance(); - outPointer.tiltX = 0; - outPointer.tiltY = 0; - - outPointer.toolType = inSlot->getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - } - } - - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE - && (mTouchButtonAccumulator.isHovering() - || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); - outPointer.isHovering = isHovering; - - // Assign pointer id using tracking id if available. - if (*outHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); - int32_t id = -1; - if (trackingId >= 0) { - for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { - uint32_t n = idBits.clearFirstMarkedBit(); - if (mPointerTrackingIdMap[n] == trackingId) { - id = n; - } - } - - if (id < 0 && !mPointerIdBits.isFull()) { - id = mPointerIdBits.markFirstUnmarkedBit(); - mPointerTrackingIdMap[id] = trackingId; - } - } - if (id < 0) { - *outHavePointerIds = false; - mCurrentRawPointerData.clearIdBits(); - newPointerIdBits.clear(); - } else { - outPointer.id = id; - mCurrentRawPointerData.idToIndex[id] = outCount; - mCurrentRawPointerData.markIdBit(id, isHovering); - newPointerIdBits.markBit(id); - } - } - - outCount += 1; - } - - mCurrentRawPointerData.pointerCount = outCount; - mPointerIdBits = newPointerIdBits; - - mMultiTouchMotionAccumulator.finishSync(); -} - -void MultiTouchInputMapper::configureRawPointerAxes() { - TouchInputMapper::configureRawPointerAxes(); - - getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); - getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); - getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); - getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor); - getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor); - getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor); - getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation); - getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure); - getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance); - getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId); - getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot); - - if (mRawPointerAxes.trackingId.valid - && mRawPointerAxes.slot.valid - && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { - size_t slotCount = mRawPointerAxes.slot.maxValue + 1; - if (slotCount > MAX_SLOTS) { - ALOGW("MultiTouch Device %s reported %d slots but the framework " - "only supports a maximum of %d slots at this time.", - getDeviceName().string(), slotCount, MAX_SLOTS); - slotCount = MAX_SLOTS; - } - mMultiTouchMotionAccumulator.configure(getDevice(), - slotCount, true /*usingSlotsProtocol*/); - } else { - mMultiTouchMotionAccumulator.configure(getDevice(), - MAX_POINTERS, false /*usingSlotsProtocol*/); - } -} - -bool MultiTouchInputMapper::hasStylus() const { - return mMultiTouchMotionAccumulator.hasStylus() - || mTouchButtonAccumulator.hasStylus(); -} - - -// --- JoystickInputMapper --- - -JoystickInputMapper::JoystickInputMapper(InputDevice* device) : - InputMapper(device) { -} - -JoystickInputMapper::~JoystickInputMapper() { -} - -uint32_t JoystickInputMapper::getSources() { - return AINPUT_SOURCE_JOYSTICK; -} - -void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - for (size_t i = 0; i < mAxes.size(); i++) { - const Axis& axis = mAxes.valueAt(i); - addMotionRange(axis.axisInfo.axis, axis, info); - - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - addMotionRange(axis.axisInfo.highAxis, axis, info); - - } - } -} - -void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, - InputDeviceInfo* info) { - info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - /* In order to ease the transition for developers from using the old axes - * to the newer, more semantically correct axes, we'll continue to register - * the old axes as duplicates of their corresponding new ones. */ - int32_t compatAxis = getCompatAxis(axisId); - if (compatAxis >= 0) { - info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - } -} - -/* A mapping from axes the joystick actually has to the axes that should be - * artificially created for compatibility purposes. - * Returns -1 if no compatibility axis is needed. */ -int32_t JoystickInputMapper::getCompatAxis(int32_t axis) { - switch(axis) { - case AMOTION_EVENT_AXIS_LTRIGGER: - return AMOTION_EVENT_AXIS_BRAKE; - case AMOTION_EVENT_AXIS_RTRIGGER: - return AMOTION_EVENT_AXIS_GAS; - } - return -1; -} - -void JoystickInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Joystick Input Mapper:\n"); - - dump.append(INDENT3 "Axes:\n"); - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - const char* label = getAxisLabel(axis.axisInfo.axis); - if (label) { - dump.appendFormat(INDENT4 "%s", label); - } else { - dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis); - } - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - label = getAxisLabel(axis.axisInfo.highAxis); - if (label) { - dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue); - } else { - dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis, - axis.axisInfo.splitValue); - } - } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { - dump.append(" (invert)"); - } - - dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, " - "highScale=%0.5f, highOffset=%0.5f\n", - axis.scale, axis.offset, axis.highScale, axis.highOffset); - dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " - "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", - mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, - axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution); - } -} - -void JoystickInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - // Collect all axes. - for (int32_t abs = 0; abs <= ABS_MAX; abs++) { - if (!(getAbsAxisUsage(abs, getDevice()->getClasses()) - & INPUT_DEVICE_CLASS_JOYSTICK)) { - continue; // axis must be claimed by a different device - } - - RawAbsoluteAxisInfo rawAxisInfo; - getAbsoluteAxisInfo(abs, &rawAxisInfo); - if (rawAxisInfo.valid) { - // Map axis. - AxisInfo axisInfo; - bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); - if (!explicitlyMapped) { - // Axis is not explicitly mapped, will choose a generic axis later. - axisInfo.mode = AxisInfo::MODE_NORMAL; - axisInfo.axis = -1; - } - - // Apply flat override. - int32_t rawFlat = axisInfo.flatOverride < 0 - ? rawAxisInfo.flat : axisInfo.flatOverride; - - // Calculate scaling factors and limits. - Axis axis; - if (axisInfo.mode == AxisInfo::MODE_SPLIT) { - float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); - float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, 0.0f, highScale, 0.0f, - 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } else if (isCenteredAxis(axisInfo.axis)) { - float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, offset, scale, offset, - -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } else { - float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, 0.0f, scale, 0.0f, - 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } - - // To eliminate noise while the joystick is at rest, filter out small variations - // in axis values up front. - axis.filter = axis.flat * 0.25f; - - mAxes.add(abs, axis); - } - } - - // If there are too many axes, start dropping them. - // Prefer to keep explicitly mapped axes. - if (mAxes.size() > PointerCoords::MAX_AXES) { - ALOGI("Joystick '%s' has %d axes but the framework only supports a maximum of %d.", - getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES); - pruneAxes(true); - pruneAxes(false); - } - - // Assign generic axis ids to remaining axes. - int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - if (axis.axisInfo.axis < 0) { - while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 - && haveAxis(nextGenericAxisId)) { - nextGenericAxisId += 1; - } - - if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { - axis.axisInfo.axis = nextGenericAxisId; - nextGenericAxisId += 1; - } else { - ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " - "have already been assigned to other axes.", - getDeviceName().string(), mAxes.keyAt(i)); - mAxes.removeItemsAt(i--); - numAxes -= 1; - } - } - } - } -} - -bool JoystickInputMapper::haveAxis(int32_t axisId) { - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - if (axis.axisInfo.axis == axisId - || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT - && axis.axisInfo.highAxis == axisId)) { - return true; - } - } - return false; -} - -void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { - size_t i = mAxes.size(); - while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) { - if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) { - continue; - } - ALOGI("Discarding joystick '%s' axis %d because there are too many axes.", - getDeviceName().string(), mAxes.keyAt(i)); - mAxes.removeItemsAt(i); - } -} - -bool JoystickInputMapper::isCenteredAxis(int32_t axis) { - switch (axis) { - case AMOTION_EVENT_AXIS_X: - case AMOTION_EVENT_AXIS_Y: - case AMOTION_EVENT_AXIS_Z: - case AMOTION_EVENT_AXIS_RX: - case AMOTION_EVENT_AXIS_RY: - case AMOTION_EVENT_AXIS_RZ: - case AMOTION_EVENT_AXIS_HAT_X: - case AMOTION_EVENT_AXIS_HAT_Y: - case AMOTION_EVENT_AXIS_ORIENTATION: - case AMOTION_EVENT_AXIS_RUDDER: - case AMOTION_EVENT_AXIS_WHEEL: - return true; - default: - return false; - } -} - -void JoystickInputMapper::reset(nsecs_t when) { - // Recenter all axes. - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - axis.resetValue(); - } - - InputMapper::reset(when); -} - -void JoystickInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_ABS: { - ssize_t index = mAxes.indexOfKey(rawEvent->code); - if (index >= 0) { - Axis& axis = mAxes.editValueAt(index); - float newValue, highNewValue; - switch (axis.axisInfo.mode) { - case AxisInfo::MODE_INVERT: - newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) - * axis.scale + axis.offset; - highNewValue = 0.0f; - break; - case AxisInfo::MODE_SPLIT: - if (rawEvent->value < axis.axisInfo.splitValue) { - newValue = (axis.axisInfo.splitValue - rawEvent->value) - * axis.scale + axis.offset; - highNewValue = 0.0f; - } else if (rawEvent->value > axis.axisInfo.splitValue) { - newValue = 0.0f; - highNewValue = (rawEvent->value - axis.axisInfo.splitValue) - * axis.highScale + axis.highOffset; - } else { - newValue = 0.0f; - highNewValue = 0.0f; - } - break; - default: - newValue = rawEvent->value * axis.scale + axis.offset; - highNewValue = 0.0f; - break; - } - axis.newValue = newValue; - axis.highNewValue = highNewValue; - } - break; - } - - case EV_SYN: - switch (rawEvent->code) { - case SYN_REPORT: - sync(rawEvent->when, false /*force*/); - break; - } - break; - } -} - -void JoystickInputMapper::sync(nsecs_t when, bool force) { - if (!filterAxes(force)) { - return; - } - - int32_t metaState = mContext->getGlobalMetaState(); - int32_t buttonState = 0; - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; - - PointerCoords pointerCoords; - pointerCoords.clear(); - - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue); - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis, - axis.highCurrentValue); - } - } - - // Moving a joystick axis should not wake the device because joysticks can - // be fairly noisy even when not in use. On the other hand, pushing a gamepad - // button will likely wake the device. - // TODO: Use the input device configuration to control this behavior more finely. - uint32_t policyFlags = 0; - - NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0); - getListener()->notifyMotion(&args); -} - -void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, - int32_t axis, float value) { - pointerCoords->setAxisValue(axis, value); - /* In order to ease the transition for developers from using the old axes - * to the newer, more semantically correct axes, we'll continue to produce - * values for the old axes as mirrors of the value of their corresponding - * new axes. */ - int32_t compatAxis = getCompatAxis(axis); - if (compatAxis >= 0) { - pointerCoords->setAxisValue(compatAxis, value); - } -} - -bool JoystickInputMapper::filterAxes(bool force) { - bool atLeastOneSignificantChange = force; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - if (force || hasValueChangedSignificantly(axis.filter, - axis.newValue, axis.currentValue, axis.min, axis.max)) { - axis.currentValue = axis.newValue; - atLeastOneSignificantChange = true; - } - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - if (force || hasValueChangedSignificantly(axis.filter, - axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) { - axis.highCurrentValue = axis.highNewValue; - atLeastOneSignificantChange = true; - } - } - } - return atLeastOneSignificantChange; -} - -bool JoystickInputMapper::hasValueChangedSignificantly( - float filter, float newValue, float currentValue, float min, float max) { - if (newValue != currentValue) { - // Filter out small changes in value unless the value is converging on the axis - // bounds or center point. This is intended to reduce the amount of information - // sent to applications by particularly noisy joysticks (such as PS3). - if (fabs(newValue - currentValue) > filter - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { - return true; - } - } - return false; -} - -bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange( - float filter, float newValue, float currentValue, float thresholdValue) { - float newDistance = fabs(newValue - thresholdValue); - if (newDistance < filter) { - float oldDistance = fabs(currentValue - thresholdValue); - if (newDistance < oldDistance) { - return true; - } - } - return false; -} - -} // namespace android diff --git a/services/input/InputReader.h b/services/input/InputReader.h deleted file mode 100644 index a8bb636..0000000 --- a/services/input/InputReader.h +++ /dev/null @@ -1,1816 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_READER_H -#define _UI_INPUT_READER_H - -#include "EventHub.h" -#include "PointerController.h" -#include "InputListener.h" - -#include <input/Input.h> -#include <input/VelocityControl.h> -#include <input/VelocityTracker.h> -#include <utils/KeyedVector.h> -#include <utils/threads.h> -#include <utils/Timers.h> -#include <utils/RefBase.h> -#include <utils/String8.h> -#include <utils/BitSet.h> - -#include <stddef.h> -#include <unistd.h> - -// Maximum supported size of a vibration pattern. -// Must be at least 2. -#define MAX_VIBRATE_PATTERN_SIZE 100 - -// Maximum allowable delay value in a vibration pattern before -// which the delay will be truncated. -#define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL) - -namespace android { - -class InputDevice; -class InputMapper; - -/* - * Describes how coordinates are mapped on a physical display. - * See com.android.server.display.DisplayViewport. - */ -struct DisplayViewport { - int32_t displayId; // -1 if invalid - int32_t orientation; - int32_t logicalLeft; - int32_t logicalTop; - int32_t logicalRight; - int32_t logicalBottom; - int32_t physicalLeft; - int32_t physicalTop; - int32_t physicalRight; - int32_t physicalBottom; - int32_t deviceWidth; - int32_t deviceHeight; - - DisplayViewport() : - displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0), - logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0), - physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0), - deviceWidth(0), deviceHeight(0) { - } - - bool operator==(const DisplayViewport& other) const { - return displayId == other.displayId - && orientation == other.orientation - && logicalLeft == other.logicalLeft - && logicalTop == other.logicalTop - && logicalRight == other.logicalRight - && logicalBottom == other.logicalBottom - && physicalLeft == other.physicalLeft - && physicalTop == other.physicalTop - && physicalRight == other.physicalRight - && physicalBottom == other.physicalBottom - && deviceWidth == other.deviceWidth - && deviceHeight == other.deviceHeight; - } - - bool operator!=(const DisplayViewport& other) const { - return !(*this == other); - } - - inline bool isValid() const { - return displayId >= 0; - } - - void setNonDisplayViewport(int32_t width, int32_t height) { - displayId = ADISPLAY_ID_NONE; - orientation = DISPLAY_ORIENTATION_0; - logicalLeft = 0; - logicalTop = 0; - logicalRight = width; - logicalBottom = height; - physicalLeft = 0; - physicalTop = 0; - physicalRight = width; - physicalBottom = height; - deviceWidth = width; - deviceHeight = height; - } -}; - -/* - * Input reader configuration. - * - * Specifies various options that modify the behavior of the input reader. - */ -struct InputReaderConfiguration { - // Describes changes that have occurred. - enum { - // The pointer speed changed. - CHANGE_POINTER_SPEED = 1 << 0, - - // The pointer gesture control changed. - CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1, - - // The display size or orientation changed. - CHANGE_DISPLAY_INFO = 1 << 2, - - // The visible touches option changed. - CHANGE_SHOW_TOUCHES = 1 << 3, - - // The keyboard layouts must be reloaded. - CHANGE_KEYBOARD_LAYOUTS = 1 << 4, - - // The device name alias supplied by the may have changed for some devices. - CHANGE_DEVICE_ALIAS = 1 << 5, - - // All devices must be reopened. - CHANGE_MUST_REOPEN = 1 << 31, - }; - - // Gets the amount of time to disable virtual keys after the screen is touched - // in order to filter out accidental virtual key presses due to swiping gestures - // or taps near the edge of the display. May be 0 to disable the feature. - nsecs_t virtualKeyQuietTime; - - // The excluded device names for the platform. - // Devices with these names will be ignored. - Vector<String8> excludedDeviceNames; - - // Velocity control parameters for mouse pointer movements. - VelocityControlParameters pointerVelocityControlParameters; - - // Velocity control parameters for mouse wheel movements. - VelocityControlParameters wheelVelocityControlParameters; - - // True if pointer gestures are enabled. - bool pointerGesturesEnabled; - - // Quiet time between certain pointer gesture transitions. - // Time to allow for all fingers or buttons to settle into a stable state before - // starting a new gesture. - nsecs_t pointerGestureQuietInterval; - - // The minimum speed that a pointer must travel for us to consider switching the active - // touch pointer to it during a drag. This threshold is set to avoid switching due - // to noise from a finger resting on the touch pad (perhaps just pressing it down). - float pointerGestureDragMinSwitchSpeed; // in pixels per second - - // Tap gesture delay time. - // The time between down and up must be less than this to be considered a tap. - nsecs_t pointerGestureTapInterval; - - // Tap drag gesture delay time. - // The time between the previous tap's up and the next down must be less than - // this to be considered a drag. Otherwise, the previous tap is finished and a - // new tap begins. - // - // Note that the previous tap will be held down for this entire duration so this - // interval must be shorter than the long press timeout. - nsecs_t pointerGestureTapDragInterval; - - // The distance in pixels that the pointer is allowed to move from initial down - // to up and still be called a tap. - float pointerGestureTapSlop; // in pixels - - // Time after the first touch points go down to settle on an initial centroid. - // This is intended to be enough time to handle cases where the user puts down two - // fingers at almost but not quite exactly the same time. - nsecs_t pointerGestureMultitouchSettleInterval; - - // The transition from PRESS to SWIPE or FREEFORM gesture mode is made when - // at least two pointers have moved at least this far from their starting place. - float pointerGestureMultitouchMinDistance; // in pixels - - // The transition from PRESS to SWIPE gesture mode can only occur when the - // cosine of the angle between the two vectors is greater than or equal to than this value - // which indicates that the vectors are oriented in the same direction. - // When the vectors are oriented in the exactly same direction, the cosine is 1.0. - // (In exactly opposite directions, the cosine is -1.0.) - float pointerGestureSwipeTransitionAngleCosine; - - // The transition from PRESS to SWIPE gesture mode can only occur when the - // fingers are no more than this far apart relative to the diagonal size of - // the touch pad. For example, a ratio of 0.5 means that the fingers must be - // no more than half the diagonal size of the touch pad apart. - float pointerGestureSwipeMaxWidthRatio; - - // The gesture movement speed factor relative to the size of the display. - // Movement speed applies when the fingers are moving in the same direction. - // Without acceleration, a full swipe of the touch pad diagonal in movement mode - // will cover this portion of the display diagonal. - float pointerGestureMovementSpeedRatio; - - // The gesture zoom speed factor relative to the size of the display. - // Zoom speed applies when the fingers are mostly moving relative to each other - // to execute a scale gesture or similar. - // Without acceleration, a full swipe of the touch pad diagonal in zoom mode - // will cover this portion of the display diagonal. - float pointerGestureZoomSpeedRatio; - - // True to show the location of touches on the touch screen as spots. - bool showTouches; - - InputReaderConfiguration() : - virtualKeyQuietTime(0), - pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f), - wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f), - pointerGesturesEnabled(true), - pointerGestureQuietInterval(100 * 1000000LL), // 100 ms - pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second - pointerGestureTapInterval(150 * 1000000LL), // 150 ms - pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms - pointerGestureTapSlop(10.0f), // 10 pixels - pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms - pointerGestureMultitouchMinDistance(15), // 15 pixels - pointerGestureSwipeTransitionAngleCosine(0.2588f), // cosine of 75 degrees - pointerGestureSwipeMaxWidthRatio(0.25f), - pointerGestureMovementSpeedRatio(0.8f), - pointerGestureZoomSpeedRatio(0.3f), - showTouches(false) { } - - bool getDisplayInfo(bool external, DisplayViewport* outViewport) const; - void setDisplayInfo(bool external, const DisplayViewport& viewport); - -private: - DisplayViewport mInternalDisplay; - DisplayViewport mExternalDisplay; -}; - - -/* - * Input reader policy interface. - * - * The input reader policy is used by the input reader to interact with the Window Manager - * and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - * - * These methods must NOT re-enter the input reader since they may be called while - * holding the input reader lock. - */ -class InputReaderPolicyInterface : public virtual RefBase { -protected: - InputReaderPolicyInterface() { } - virtual ~InputReaderPolicyInterface() { } - -public: - /* Gets the input reader configuration. */ - virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0; - - /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ - virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0; - - /* Notifies the input reader policy that some input devices have changed - * and provides information about all current input devices. - */ - virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) = 0; - - /* Gets the keyboard layout for a particular input device. */ - virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) = 0; - - /* Gets a user-supplied alias for a particular input device, or an empty string if none. */ - virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0; -}; - - -/* Processes raw input events and sends cooked event data to an input listener. */ -class InputReaderInterface : public virtual RefBase { -protected: - InputReaderInterface() { } - virtual ~InputReaderInterface() { } - -public: - /* Dumps the state of the input reader. - * - * This method may be called on any thread (usually by the input manager). */ - virtual void dump(String8& dump) = 0; - - /* Called by the heatbeat to ensures that the reader has not deadlocked. */ - virtual void monitor() = 0; - - /* Runs a single iteration of the processing loop. - * Nominally reads and processes one incoming message from the EventHub. - * - * This method should be called on the input reader thread. - */ - virtual void loopOnce() = 0; - - /* Gets information about all input devices. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices) = 0; - - /* Query current input state. */ - virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode) = 0; - virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode) = 0; - virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, - int32_t sw) = 0; - - /* Determine whether physical keys exist for the given framework-domain key codes. */ - virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0; - - /* Requests that a reconfiguration of all input devices. - * The changes flag is a bitfield that indicates what has changed and whether - * the input devices must all be reopened. */ - virtual void requestRefreshConfiguration(uint32_t changes) = 0; - - /* Controls the vibrator of a particular input device. */ - virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token) = 0; - virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0; -}; - - -/* Internal interface used by individual input devices to access global input device state - * and parameters maintained by the input reader. - */ -class InputReaderContext { -public: - InputReaderContext() { } - virtual ~InputReaderContext() { } - - virtual void updateGlobalMetaState() = 0; - virtual int32_t getGlobalMetaState() = 0; - - virtual void disableVirtualKeysUntil(nsecs_t time) = 0; - virtual bool shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) = 0; - - virtual void fadePointer() = 0; - - virtual void requestTimeoutAtTime(nsecs_t when) = 0; - virtual int32_t bumpGeneration() = 0; - - virtual InputReaderPolicyInterface* getPolicy() = 0; - virtual InputListenerInterface* getListener() = 0; - virtual EventHubInterface* getEventHub() = 0; -}; - - -/* The input reader reads raw event data from the event hub and processes it into input events - * that it sends to the input listener. Some functions of the input reader, such as early - * event filtering in low power states, are controlled by a separate policy object. - * - * The InputReader owns a collection of InputMappers. Most of the work it does happens - * on the input reader thread but the InputReader can receive queries from other system - * components running on arbitrary threads. To keep things manageable, the InputReader - * uses a single Mutex to guard its state. The Mutex may be held while calling into the - * EventHub or the InputReaderPolicy but it is never held while calling into the - * InputListener. - */ -class InputReader : public InputReaderInterface { -public: - InputReader(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener); - virtual ~InputReader(); - - virtual void dump(String8& dump); - virtual void monitor(); - - virtual void loopOnce(); - - virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices); - - virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode); - virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode); - virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, - int32_t sw); - - virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); - - virtual void requestRefreshConfiguration(uint32_t changes); - - virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token); - virtual void cancelVibrate(int32_t deviceId, int32_t token); - -protected: - // These members are protected so they can be instrumented by test cases. - virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, uint32_t classes); - - class ContextImpl : public InputReaderContext { - InputReader* mReader; - - public: - ContextImpl(InputReader* reader); - - virtual void updateGlobalMetaState(); - virtual int32_t getGlobalMetaState(); - virtual void disableVirtualKeysUntil(nsecs_t time); - virtual bool shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode); - virtual void fadePointer(); - virtual void requestTimeoutAtTime(nsecs_t when); - virtual int32_t bumpGeneration(); - virtual InputReaderPolicyInterface* getPolicy(); - virtual InputListenerInterface* getListener(); - virtual EventHubInterface* getEventHub(); - } mContext; - - friend class ContextImpl; - -private: - Mutex mLock; - - Condition mReaderIsAliveCondition; - - sp<EventHubInterface> mEventHub; - sp<InputReaderPolicyInterface> mPolicy; - sp<QueuedInputListener> mQueuedListener; - - InputReaderConfiguration mConfig; - - // The event queue. - static const int EVENT_BUFFER_SIZE = 256; - RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; - - KeyedVector<int32_t, InputDevice*> mDevices; - - // low-level input event decoding and device management - void processEventsLocked(const RawEvent* rawEvents, size_t count); - - void addDeviceLocked(nsecs_t when, int32_t deviceId); - void removeDeviceLocked(nsecs_t when, int32_t deviceId); - void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); - void timeoutExpiredLocked(nsecs_t when); - - void handleConfigurationChangedLocked(nsecs_t when); - - int32_t mGlobalMetaState; - void updateGlobalMetaStateLocked(); - int32_t getGlobalMetaStateLocked(); - - void fadePointerLocked(); - - int32_t mGeneration; - int32_t bumpGenerationLocked(); - - void getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices); - - nsecs_t mDisableVirtualKeysTimeout; - void disableVirtualKeysUntilLocked(nsecs_t time); - bool shouldDropVirtualKeyLocked(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode); - - nsecs_t mNextTimeout; - void requestTimeoutAtTimeLocked(nsecs_t when); - - uint32_t mConfigurationChangesToRefresh; - void refreshConfigurationLocked(uint32_t changes); - - // state queries - typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); - int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc); - bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); -}; - - -/* Reads raw events from the event hub and processes them, endlessly. */ -class InputReaderThread : public Thread { -public: - InputReaderThread(const sp<InputReaderInterface>& reader); - virtual ~InputReaderThread(); - -private: - sp<InputReaderInterface> mReader; - - virtual bool threadLoop(); -}; - - -/* Represents the state of a single input device. */ -class InputDevice { -public: - InputDevice(InputReaderContext* context, int32_t id, int32_t generation, int32_t - controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes); - ~InputDevice(); - - inline InputReaderContext* getContext() { return mContext; } - inline int32_t getId() const { return mId; } - inline int32_t getControllerNumber() const { return mControllerNumber; } - inline int32_t getGeneration() const { return mGeneration; } - inline const String8& getName() const { return mIdentifier.name; } - inline uint32_t getClasses() const { return mClasses; } - inline uint32_t getSources() const { return mSources; } - - inline bool isExternal() { return mIsExternal; } - inline void setExternal(bool external) { mIsExternal = external; } - - inline bool isIgnored() { return mMappers.isEmpty(); } - - void dump(String8& dump); - void addMapper(InputMapper* mapper); - void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - void reset(nsecs_t when); - void process(const RawEvent* rawEvents, size_t count); - void timeoutExpired(nsecs_t when); - - void getDeviceInfo(InputDeviceInfo* outDeviceInfo); - int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); - void cancelVibrate(int32_t token); - - int32_t getMetaState(); - - void fadePointer(); - - void bumpGeneration(); - - void notifyReset(nsecs_t when); - - inline const PropertyMap& getConfiguration() { return mConfiguration; } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - - bool hasKey(int32_t code) { - return getEventHub()->hasScanCode(mId, code); - } - - bool hasAbsoluteAxis(int32_t code) { - RawAbsoluteAxisInfo info; - getEventHub()->getAbsoluteAxisInfo(mId, code, &info); - return info.valid; - } - - bool isKeyPressed(int32_t code) { - return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; - } - - int32_t getAbsoluteAxisValue(int32_t code) { - int32_t value; - getEventHub()->getAbsoluteAxisValue(mId, code, &value); - return value; - } - -private: - InputReaderContext* mContext; - int32_t mId; - int32_t mControllerNumber; - int32_t mGeneration; - InputDeviceIdentifier mIdentifier; - String8 mAlias; - uint32_t mClasses; - - Vector<InputMapper*> mMappers; - - uint32_t mSources; - bool mIsExternal; - bool mDropUntilNextSync; - - typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); - int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); - - PropertyMap mConfiguration; -}; - - -/* Keeps track of the state of mouse or touch pad buttons. */ -class CursorButtonAccumulator { -public: - CursorButtonAccumulator(); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - - uint32_t getButtonState() const; - -private: - bool mBtnLeft; - bool mBtnRight; - bool mBtnMiddle; - bool mBtnBack; - bool mBtnSide; - bool mBtnForward; - bool mBtnExtra; - bool mBtnTask; - - void clearButtons(); -}; - - -/* Keeps track of cursor movements. */ - -class CursorMotionAccumulator { -public: - CursorMotionAccumulator(); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - void finishSync(); - - inline int32_t getRelativeX() const { return mRelX; } - inline int32_t getRelativeY() const { return mRelY; } - -private: - int32_t mRelX; - int32_t mRelY; - - void clearRelativeAxes(); -}; - - -/* Keeps track of cursor scrolling motions. */ - -class CursorScrollAccumulator { -public: - CursorScrollAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - void finishSync(); - - inline bool haveRelativeVWheel() const { return mHaveRelWheel; } - inline bool haveRelativeHWheel() const { return mHaveRelHWheel; } - - inline int32_t getRelativeX() const { return mRelX; } - inline int32_t getRelativeY() const { return mRelY; } - inline int32_t getRelativeVWheel() const { return mRelWheel; } - inline int32_t getRelativeHWheel() const { return mRelHWheel; } - -private: - bool mHaveRelWheel; - bool mHaveRelHWheel; - - int32_t mRelX; - int32_t mRelY; - int32_t mRelWheel; - int32_t mRelHWheel; - - void clearRelativeAxes(); -}; - - -/* Keeps track of the state of touch, stylus and tool buttons. */ -class TouchButtonAccumulator { -public: - TouchButtonAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - - uint32_t getButtonState() const; - int32_t getToolType() const; - bool isToolActive() const; - bool isHovering() const; - bool hasStylus() const; - -private: - bool mHaveBtnTouch; - bool mHaveStylus; - - bool mBtnTouch; - bool mBtnStylus; - bool mBtnStylus2; - bool mBtnToolFinger; - bool mBtnToolPen; - bool mBtnToolRubber; - bool mBtnToolBrush; - bool mBtnToolPencil; - bool mBtnToolAirbrush; - bool mBtnToolMouse; - bool mBtnToolLens; - bool mBtnToolDoubleTap; - bool mBtnToolTripleTap; - bool mBtnToolQuadTap; - - void clearButtons(); -}; - - -/* Raw axis information from the driver. */ -struct RawPointerAxes { - RawAbsoluteAxisInfo x; - RawAbsoluteAxisInfo y; - RawAbsoluteAxisInfo pressure; - RawAbsoluteAxisInfo touchMajor; - RawAbsoluteAxisInfo touchMinor; - RawAbsoluteAxisInfo toolMajor; - RawAbsoluteAxisInfo toolMinor; - RawAbsoluteAxisInfo orientation; - RawAbsoluteAxisInfo distance; - RawAbsoluteAxisInfo tiltX; - RawAbsoluteAxisInfo tiltY; - RawAbsoluteAxisInfo trackingId; - RawAbsoluteAxisInfo slot; - - RawPointerAxes(); - void clear(); -}; - - -/* Raw data for a collection of pointers including a pointer id mapping table. */ -struct RawPointerData { - struct Pointer { - uint32_t id; - int32_t x; - int32_t y; - int32_t pressure; - int32_t touchMajor; - int32_t touchMinor; - int32_t toolMajor; - int32_t toolMinor; - int32_t orientation; - int32_t distance; - int32_t tiltX; - int32_t tiltY; - int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant - bool isHovering; - }; - - uint32_t pointerCount; - Pointer pointers[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; - uint32_t idToIndex[MAX_POINTER_ID + 1]; - - RawPointerData(); - void clear(); - void copyFrom(const RawPointerData& other); - void getCentroidOfTouchingPointers(float* outX, float* outY) const; - - inline void markIdBit(uint32_t id, bool isHovering) { - if (isHovering) { - hoveringIdBits.markBit(id); - } else { - touchingIdBits.markBit(id); - } - } - - inline void clearIdBits() { - hoveringIdBits.clear(); - touchingIdBits.clear(); - } - - inline const Pointer& pointerForId(uint32_t id) const { - return pointers[idToIndex[id]]; - } - - inline bool isHovering(uint32_t pointerIndex) { - return pointers[pointerIndex].isHovering; - } -}; - - -/* Cooked data for a collection of pointers including a pointer id mapping table. */ -struct CookedPointerData { - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; - uint32_t idToIndex[MAX_POINTER_ID + 1]; - - CookedPointerData(); - void clear(); - void copyFrom(const CookedPointerData& other); - - inline const PointerCoords& pointerCoordsForId(uint32_t id) const { - return pointerCoords[idToIndex[id]]; - } - - inline bool isHovering(uint32_t pointerIndex) { - return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); - } -}; - - -/* Keeps track of the state of single-touch protocol. */ -class SingleTouchMotionAccumulator { -public: - SingleTouchMotionAccumulator(); - - void process(const RawEvent* rawEvent); - void reset(InputDevice* device); - - inline int32_t getAbsoluteX() const { return mAbsX; } - inline int32_t getAbsoluteY() const { return mAbsY; } - inline int32_t getAbsolutePressure() const { return mAbsPressure; } - inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; } - inline int32_t getAbsoluteDistance() const { return mAbsDistance; } - inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; } - inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; } - -private: - int32_t mAbsX; - int32_t mAbsY; - int32_t mAbsPressure; - int32_t mAbsToolWidth; - int32_t mAbsDistance; - int32_t mAbsTiltX; - int32_t mAbsTiltY; - - void clearAbsoluteAxes(); -}; - - -/* Keeps track of the state of multi-touch protocol. */ -class MultiTouchMotionAccumulator { -public: - class Slot { - public: - inline bool isInUse() const { return mInUse; } - inline int32_t getX() const { return mAbsMTPositionX; } - inline int32_t getY() const { return mAbsMTPositionY; } - inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } - inline int32_t getTouchMinor() const { - return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; } - inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } - inline int32_t getToolMinor() const { - return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; } - inline int32_t getOrientation() const { return mAbsMTOrientation; } - inline int32_t getTrackingId() const { return mAbsMTTrackingId; } - inline int32_t getPressure() const { return mAbsMTPressure; } - inline int32_t getDistance() const { return mAbsMTDistance; } - inline int32_t getToolType() const; - - private: - friend class MultiTouchMotionAccumulator; - - bool mInUse; - bool mHaveAbsMTTouchMinor; - bool mHaveAbsMTWidthMinor; - bool mHaveAbsMTToolType; - - int32_t mAbsMTPositionX; - int32_t mAbsMTPositionY; - int32_t mAbsMTTouchMajor; - int32_t mAbsMTTouchMinor; - int32_t mAbsMTWidthMajor; - int32_t mAbsMTWidthMinor; - int32_t mAbsMTOrientation; - int32_t mAbsMTTrackingId; - int32_t mAbsMTPressure; - int32_t mAbsMTDistance; - int32_t mAbsMTToolType; - - Slot(); - void clear(); - }; - - MultiTouchMotionAccumulator(); - ~MultiTouchMotionAccumulator(); - - void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol); - void reset(InputDevice* device); - void process(const RawEvent* rawEvent); - void finishSync(); - bool hasStylus() const; - - inline size_t getSlotCount() const { return mSlotCount; } - inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } - -private: - int32_t mCurrentSlot; - Slot* mSlots; - size_t mSlotCount; - bool mUsingSlotsProtocol; - bool mHaveStylus; - - void clearSlots(int32_t initialSlot); -}; - - -/* An input mapper transforms raw input events into cooked event data. - * A single input device can have multiple associated input mappers in order to interpret - * different classes of events. - * - * InputMapper lifecycle: - * - create - * - configure with 0 changes - * - reset - * - process, process, process (may occasionally reconfigure with non-zero changes or reset) - * - reset - * - destroy - */ -class InputMapper { -public: - InputMapper(InputDevice* device); - virtual ~InputMapper(); - - inline InputDevice* getDevice() { return mDevice; } - inline int32_t getDeviceId() { return mDevice->getId(); } - inline const String8 getDeviceName() { return mDevice->getName(); } - inline InputReaderContext* getContext() { return mContext; } - inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } - inline InputListenerInterface* getListener() { return mContext->getListener(); } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - - virtual uint32_t getSources() = 0; - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent) = 0; - virtual void timeoutExpired(nsecs_t when); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token); - virtual void cancelVibrate(int32_t token); - - virtual int32_t getMetaState(); - - virtual void fadePointer(); - -protected: - InputDevice* mDevice; - InputReaderContext* mContext; - - status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); - void bumpGeneration(); - - static void dumpRawAbsoluteAxisInfo(String8& dump, - const RawAbsoluteAxisInfo& axis, const char* name); -}; - - -class SwitchInputMapper : public InputMapper { -public: - SwitchInputMapper(InputDevice* device); - virtual ~SwitchInputMapper(); - - virtual uint32_t getSources(); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - -private: - uint32_t mUpdatedSwitchValues; - uint32_t mUpdatedSwitchMask; - - void processSwitch(int32_t switchCode, int32_t switchValue); - void sync(nsecs_t when); -}; - - -class VibratorInputMapper : public InputMapper { -public: - VibratorInputMapper(InputDevice* device); - virtual ~VibratorInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void process(const RawEvent* rawEvent); - - virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token); - virtual void cancelVibrate(int32_t token); - virtual void timeoutExpired(nsecs_t when); - virtual void dump(String8& dump); - -private: - bool mVibrating; - nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE]; - size_t mPatternSize; - ssize_t mRepeat; - int32_t mToken; - ssize_t mIndex; - nsecs_t mNextStepTime; - - void nextStep(); - void stopVibrating(); -}; - - -class KeyboardInputMapper : public InputMapper { -public: - KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType); - virtual ~KeyboardInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual int32_t getMetaState(); - -private: - struct KeyDown { - int32_t keyCode; - int32_t scanCode; - }; - - uint32_t mSource; - int32_t mKeyboardType; - - int32_t mOrientation; // orientation for dpad keys - - Vector<KeyDown> mKeyDowns; // keys that are down - int32_t mMetaState; - nsecs_t mDownTime; // time of most recent key down - - int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none - - struct LedState { - bool avail; // led is available - bool on; // we think the led is currently on - }; - LedState mCapsLockLedState; - LedState mNumLockLedState; - LedState mScrollLockLedState; - - // Immutable configuration parameters. - struct Parameters { - bool hasAssociatedDisplay; - bool orientationAware; - } mParameters; - - void configureParameters(); - void dumpParameters(String8& dump); - - bool isKeyboardOrGamepadKey(int32_t scanCode); - - void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, - uint32_t policyFlags); - - ssize_t findKeyDown(int32_t scanCode); - - void resetLedState(); - void initializeLedState(LedState& ledState, int32_t led); - void updateLedState(bool reset); - void updateLedStateForModifier(LedState& ledState, int32_t led, - int32_t modifier, bool reset); -}; - - -class CursorInputMapper : public InputMapper { -public: - CursorInputMapper(InputDevice* device); - virtual ~CursorInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - - virtual void fadePointer(); - -private: - // Amount that trackball needs to move in order to generate a key event. - static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; - - // Immutable configuration parameters. - struct Parameters { - enum Mode { - MODE_POINTER, - MODE_NAVIGATION, - }; - - Mode mode; - bool hasAssociatedDisplay; - bool orientationAware; - } mParameters; - - CursorButtonAccumulator mCursorButtonAccumulator; - CursorMotionAccumulator mCursorMotionAccumulator; - CursorScrollAccumulator mCursorScrollAccumulator; - - int32_t mSource; - float mXScale; - float mYScale; - float mXPrecision; - float mYPrecision; - - float mVWheelScale; - float mHWheelScale; - - // Velocity controls for mouse pointer and wheel movements. - // The controls for X and Y wheel movements are separate to keep them decoupled. - VelocityControl mPointerVelocityControl; - VelocityControl mWheelXVelocityControl; - VelocityControl mWheelYVelocityControl; - - int32_t mOrientation; - - sp<PointerControllerInterface> mPointerController; - - int32_t mButtonState; - nsecs_t mDownTime; - - void configureParameters(); - void dumpParameters(String8& dump); - - void sync(nsecs_t when); -}; - - -class TouchInputMapper : public InputMapper { -public: - TouchInputMapper(InputDevice* device); - virtual ~TouchInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual void fadePointer(); - virtual void timeoutExpired(nsecs_t when); - -protected: - CursorButtonAccumulator mCursorButtonAccumulator; - CursorScrollAccumulator mCursorScrollAccumulator; - TouchButtonAccumulator mTouchButtonAccumulator; - - struct VirtualKey { - int32_t keyCode; - int32_t scanCode; - uint32_t flags; - - // computed hit box, specified in touch screen coords based on known display size - int32_t hitLeft; - int32_t hitTop; - int32_t hitRight; - int32_t hitBottom; - - inline bool isHit(int32_t x, int32_t y) const { - return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; - } - }; - - // Input sources and device mode. - uint32_t mSource; - - enum DeviceMode { - DEVICE_MODE_DISABLED, // input is disabled - DEVICE_MODE_DIRECT, // direct mapping (touchscreen) - DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad) - DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation) - DEVICE_MODE_POINTER, // pointer mapping (pointer) - }; - DeviceMode mDeviceMode; - - // The reader's configuration. - InputReaderConfiguration mConfig; - - // Immutable configuration parameters. - struct Parameters { - enum DeviceType { - DEVICE_TYPE_TOUCH_SCREEN, - DEVICE_TYPE_TOUCH_PAD, - DEVICE_TYPE_TOUCH_NAVIGATION, - DEVICE_TYPE_POINTER, - }; - - DeviceType deviceType; - bool hasAssociatedDisplay; - bool associatedDisplayIsExternal; - bool orientationAware; - bool hasButtonUnderPad; - - enum GestureMode { - GESTURE_MODE_POINTER, - GESTURE_MODE_SPOTS, - }; - GestureMode gestureMode; - } mParameters; - - // Immutable calibration parameters in parsed form. - struct Calibration { - // Size - enum SizeCalibration { - SIZE_CALIBRATION_DEFAULT, - SIZE_CALIBRATION_NONE, - SIZE_CALIBRATION_GEOMETRIC, - SIZE_CALIBRATION_DIAMETER, - SIZE_CALIBRATION_BOX, - SIZE_CALIBRATION_AREA, - }; - - SizeCalibration sizeCalibration; - - bool haveSizeScale; - float sizeScale; - bool haveSizeBias; - float sizeBias; - bool haveSizeIsSummed; - bool sizeIsSummed; - - // Pressure - enum PressureCalibration { - PRESSURE_CALIBRATION_DEFAULT, - PRESSURE_CALIBRATION_NONE, - PRESSURE_CALIBRATION_PHYSICAL, - PRESSURE_CALIBRATION_AMPLITUDE, - }; - - PressureCalibration pressureCalibration; - bool havePressureScale; - float pressureScale; - - // Orientation - enum OrientationCalibration { - ORIENTATION_CALIBRATION_DEFAULT, - ORIENTATION_CALIBRATION_NONE, - ORIENTATION_CALIBRATION_INTERPOLATED, - ORIENTATION_CALIBRATION_VECTOR, - }; - - OrientationCalibration orientationCalibration; - - // Distance - enum DistanceCalibration { - DISTANCE_CALIBRATION_DEFAULT, - DISTANCE_CALIBRATION_NONE, - DISTANCE_CALIBRATION_SCALED, - }; - - DistanceCalibration distanceCalibration; - bool haveDistanceScale; - float distanceScale; - - enum CoverageCalibration { - COVERAGE_CALIBRATION_DEFAULT, - COVERAGE_CALIBRATION_NONE, - COVERAGE_CALIBRATION_BOX, - }; - - CoverageCalibration coverageCalibration; - - inline void applySizeScaleAndBias(float* outSize) const { - if (haveSizeScale) { - *outSize *= sizeScale; - } - if (haveSizeBias) { - *outSize += sizeBias; - } - if (*outSize < 0) { - *outSize = 0; - } - } - } mCalibration; - - // Raw pointer axis information from the driver. - RawPointerAxes mRawPointerAxes; - - // Raw pointer sample data. - RawPointerData mCurrentRawPointerData; - RawPointerData mLastRawPointerData; - - // Cooked pointer sample data. - CookedPointerData mCurrentCookedPointerData; - CookedPointerData mLastCookedPointerData; - - // Button state. - int32_t mCurrentButtonState; - int32_t mLastButtonState; - - // Scroll state. - int32_t mCurrentRawVScroll; - int32_t mCurrentRawHScroll; - - // Id bits used to differentiate fingers, stylus and mouse tools. - BitSet32 mCurrentFingerIdBits; // finger or unknown - BitSet32 mLastFingerIdBits; - BitSet32 mCurrentStylusIdBits; // stylus or eraser - BitSet32 mLastStylusIdBits; - BitSet32 mCurrentMouseIdBits; // mouse or lens - BitSet32 mLastMouseIdBits; - - // True if we sent a HOVER_ENTER event. - bool mSentHoverEnter; - - // The time the primary pointer last went down. - nsecs_t mDownTime; - - // The pointer controller, or null if the device is not a pointer. - sp<PointerControllerInterface> mPointerController; - - Vector<VirtualKey> mVirtualKeys; - - virtual void configureParameters(); - virtual void dumpParameters(String8& dump); - virtual void configureRawPointerAxes(); - virtual void dumpRawPointerAxes(String8& dump); - virtual void configureSurface(nsecs_t when, bool* outResetNeeded); - virtual void dumpSurface(String8& dump); - virtual void configureVirtualKeys(); - virtual void dumpVirtualKeys(String8& dump); - virtual void parseCalibration(); - virtual void resolveCalibration(); - virtual void dumpCalibration(String8& dump); - virtual bool hasStylus() const = 0; - - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0; - -private: - // The current viewport. - // The components of the viewport are specified in the display's rotated orientation. - DisplayViewport mViewport; - - // The surface orientation, width and height set by configureSurface(). - // The width and height are derived from the viewport but are specified - // in the natural orientation. - // The surface origin specifies how the surface coordinates should be translated - // to align with the logical display coordinate space. - // The orientation may be different from the viewport orientation as it specifies - // the rotation of the surface coordinates required to produce the viewport's - // requested orientation, so it will depend on whether the device is orientation aware. - int32_t mSurfaceWidth; - int32_t mSurfaceHeight; - int32_t mSurfaceLeft; - int32_t mSurfaceTop; - int32_t mSurfaceOrientation; - - // Translation and scaling factors, orientation-independent. - float mXTranslate; - float mXScale; - float mXPrecision; - - float mYTranslate; - float mYScale; - float mYPrecision; - - float mGeometricScale; - - float mPressureScale; - - float mSizeScale; - - float mOrientationScale; - - float mDistanceScale; - - bool mHaveTilt; - float mTiltXCenter; - float mTiltXScale; - float mTiltYCenter; - float mTiltYScale; - - // Oriented motion ranges for input device info. - struct OrientedRanges { - InputDeviceInfo::MotionRange x; - InputDeviceInfo::MotionRange y; - InputDeviceInfo::MotionRange pressure; - - bool haveSize; - InputDeviceInfo::MotionRange size; - - bool haveTouchSize; - InputDeviceInfo::MotionRange touchMajor; - InputDeviceInfo::MotionRange touchMinor; - - bool haveToolSize; - InputDeviceInfo::MotionRange toolMajor; - InputDeviceInfo::MotionRange toolMinor; - - bool haveOrientation; - InputDeviceInfo::MotionRange orientation; - - bool haveDistance; - InputDeviceInfo::MotionRange distance; - - bool haveTilt; - InputDeviceInfo::MotionRange tilt; - - OrientedRanges() { - clear(); - } - - void clear() { - haveSize = false; - haveTouchSize = false; - haveToolSize = false; - haveOrientation = false; - haveDistance = false; - haveTilt = false; - } - } mOrientedRanges; - - // Oriented dimensions and precision. - float mOrientedXPrecision; - float mOrientedYPrecision; - - struct CurrentVirtualKeyState { - bool down; - bool ignored; - nsecs_t downTime; - int32_t keyCode; - int32_t scanCode; - } mCurrentVirtualKey; - - // Scale factor for gesture or mouse based pointer movements. - float mPointerXMovementScale; - float mPointerYMovementScale; - - // Scale factor for gesture based zooming and other freeform motions. - float mPointerXZoomScale; - float mPointerYZoomScale; - - // The maximum swipe width. - float mPointerGestureMaxSwipeWidth; - - struct PointerDistanceHeapElement { - uint32_t currentPointerIndex : 8; - uint32_t lastPointerIndex : 8; - uint64_t distance : 48; // squared distance - }; - - enum PointerUsage { - POINTER_USAGE_NONE, - POINTER_USAGE_GESTURES, - POINTER_USAGE_STYLUS, - POINTER_USAGE_MOUSE, - }; - PointerUsage mPointerUsage; - - struct PointerGesture { - enum Mode { - // No fingers, button is not pressed. - // Nothing happening. - NEUTRAL, - - // No fingers, button is not pressed. - // Tap detected. - // Emits DOWN and UP events at the pointer location. - TAP, - - // Exactly one finger dragging following a tap. - // Pointer follows the active finger. - // Emits DOWN, MOVE and UP events at the pointer location. - // - // Detect double-taps when the finger goes up while in TAP_DRAG mode. - TAP_DRAG, - - // Button is pressed. - // Pointer follows the active finger if there is one. Other fingers are ignored. - // Emits DOWN, MOVE and UP events at the pointer location. - BUTTON_CLICK_OR_DRAG, - - // Exactly one finger, button is not pressed. - // Pointer follows the active finger. - // Emits HOVER_MOVE events at the pointer location. - // - // Detect taps when the finger goes up while in HOVER mode. - HOVER, - - // Exactly two fingers but neither have moved enough to clearly indicate - // whether a swipe or freeform gesture was intended. We consider the - // pointer to be pressed so this enables clicking or long-pressing on buttons. - // Pointer does not move. - // Emits DOWN, MOVE and UP events with a single stationary pointer coordinate. - PRESS, - - // Exactly two fingers moving in the same direction, button is not pressed. - // Pointer does not move. - // Emits DOWN, MOVE and UP events with a single pointer coordinate that - // follows the midpoint between both fingers. - SWIPE, - - // Two or more fingers moving in arbitrary directions, button is not pressed. - // Pointer does not move. - // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow - // each finger individually relative to the initial centroid of the finger. - FREEFORM, - - // Waiting for quiet time to end before starting the next gesture. - QUIET, - }; - - // Time the first finger went down. - nsecs_t firstTouchTime; - - // The active pointer id from the raw touch data. - int32_t activeTouchId; // -1 if none - - // The active pointer id from the gesture last delivered to the application. - int32_t activeGestureId; // -1 if none - - // Pointer coords and ids for the current and previous pointer gesture. - Mode currentGestureMode; - BitSet32 currentGestureIdBits; - uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1]; - PointerProperties currentGestureProperties[MAX_POINTERS]; - PointerCoords currentGestureCoords[MAX_POINTERS]; - - Mode lastGestureMode; - BitSet32 lastGestureIdBits; - uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; - PointerProperties lastGestureProperties[MAX_POINTERS]; - PointerCoords lastGestureCoords[MAX_POINTERS]; - - // Time the pointer gesture last went down. - nsecs_t downTime; - - // Time when the pointer went down for a TAP. - nsecs_t tapDownTime; - - // Time when the pointer went up for a TAP. - nsecs_t tapUpTime; - - // Location of initial tap. - float tapX, tapY; - - // Time we started waiting for quiescence. - nsecs_t quietTime; - - // Reference points for multitouch gestures. - float referenceTouchX; // reference touch X/Y coordinates in surface units - float referenceTouchY; - float referenceGestureX; // reference gesture X/Y coordinates in pixels - float referenceGestureY; - - // Distance that each pointer has traveled which has not yet been - // subsumed into the reference gesture position. - BitSet32 referenceIdBits; - struct Delta { - float dx, dy; - }; - Delta referenceDeltas[MAX_POINTER_ID + 1]; - - // Describes how touch ids are mapped to gesture ids for freeform gestures. - uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1]; - - // A velocity tracker for determining whether to switch active pointers during drags. - VelocityTracker velocityTracker; - - void reset() { - firstTouchTime = LLONG_MIN; - activeTouchId = -1; - activeGestureId = -1; - currentGestureMode = NEUTRAL; - currentGestureIdBits.clear(); - lastGestureMode = NEUTRAL; - lastGestureIdBits.clear(); - downTime = 0; - velocityTracker.clear(); - resetTap(); - resetQuietTime(); - } - - void resetTap() { - tapDownTime = LLONG_MIN; - tapUpTime = LLONG_MIN; - } - - void resetQuietTime() { - quietTime = LLONG_MIN; - } - } mPointerGesture; - - struct PointerSimple { - PointerCoords currentCoords; - PointerProperties currentProperties; - PointerCoords lastCoords; - PointerProperties lastProperties; - - // True if the pointer is down. - bool down; - - // True if the pointer is hovering. - bool hovering; - - // Time the pointer last went down. - nsecs_t downTime; - - void reset() { - currentCoords.clear(); - currentProperties.clear(); - lastCoords.clear(); - lastProperties.clear(); - down = false; - hovering = false; - downTime = 0; - } - } mPointerSimple; - - // The pointer and scroll velocity controls. - VelocityControl mPointerVelocityControl; - VelocityControl mWheelXVelocityControl; - VelocityControl mWheelYVelocityControl; - - void sync(nsecs_t when); - - bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); - void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags); - - void dispatchTouches(nsecs_t when, uint32_t policyFlags); - void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); - void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); - void cookPointerData(); - - void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); - void abortPointerUsage(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); - void abortPointerGestures(nsecs_t when, uint32_t policyFlags); - bool preparePointerGestures(nsecs_t when, - bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, - bool isTimeout); - - void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags); - void abortPointerStylus(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags); - void abortPointerMouse(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, - bool down, bool hovering); - void abortPointerSimple(nsecs_t when, uint32_t policyFlags); - - // Dispatches a motion event. - // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the - // method will take care of setting the index and transmuting the action to DOWN or UP - // it is the first / last pointer to go down / up. - void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, - const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, - int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); - - // Updates pointer coords and properties for pointers with specified ids that have moved. - // Returns true if any of them changed. - bool updateMovedPointers(const PointerProperties* inProperties, - const PointerCoords* inCoords, const uint32_t* inIdToIndex, - PointerProperties* outProperties, PointerCoords* outCoords, - const uint32_t* outIdToIndex, BitSet32 idBits) const; - - bool isPointInsideSurface(int32_t x, int32_t y); - const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); - - void assignPointerIds(); -}; - - -class SingleTouchInputMapper : public TouchInputMapper { -public: - SingleTouchInputMapper(InputDevice* device); - virtual ~SingleTouchInputMapper(); - - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); - virtual void configureRawPointerAxes(); - virtual bool hasStylus() const; - -private: - SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; -}; - - -class MultiTouchInputMapper : public TouchInputMapper { -public: - MultiTouchInputMapper(InputDevice* device); - virtual ~MultiTouchInputMapper(); - - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); - virtual void configureRawPointerAxes(); - virtual bool hasStylus() const; - -private: - MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; - - // Specifies the pointer id bits that are in use, and their associated tracking id. - BitSet32 mPointerIdBits; - int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; -}; - - -class JoystickInputMapper : public InputMapper { -public: - JoystickInputMapper(InputDevice* device); - virtual ~JoystickInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -private: - struct Axis { - RawAbsoluteAxisInfo rawAxisInfo; - AxisInfo axisInfo; - - bool explicitlyMapped; // true if the axis was explicitly assigned an axis id - - float scale; // scale factor from raw to normalized values - float offset; // offset to add after scaling for normalization - float highScale; // scale factor from raw to normalized values of high split - float highOffset; // offset to add after scaling for normalization of high split - - float min; // normalized inclusive minimum - float max; // normalized inclusive maximum - float flat; // normalized flat region size - float fuzz; // normalized error tolerance - float resolution; // normalized resolution in units/mm - - float filter; // filter out small variations of this size - float currentValue; // current value - float newValue; // most recent value - float highCurrentValue; // current value of high split - float highNewValue; // most recent value of high split - - void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, - bool explicitlyMapped, float scale, float offset, - float highScale, float highOffset, - float min, float max, float flat, float fuzz, float resolution) { - this->rawAxisInfo = rawAxisInfo; - this->axisInfo = axisInfo; - this->explicitlyMapped = explicitlyMapped; - this->scale = scale; - this->offset = offset; - this->highScale = highScale; - this->highOffset = highOffset; - this->min = min; - this->max = max; - this->flat = flat; - this->fuzz = fuzz; - this->resolution = resolution; - this->filter = 0; - resetValue(); - } - - void resetValue() { - this->currentValue = 0; - this->newValue = 0; - this->highCurrentValue = 0; - this->highNewValue = 0; - } - }; - - // Axes indexed by raw ABS_* axis index. - KeyedVector<int32_t, Axis> mAxes; - - void sync(nsecs_t when, bool force); - - bool haveAxis(int32_t axisId); - void pruneAxes(bool ignoreExplicitlyMappedAxes); - bool filterAxes(bool force); - - static bool hasValueChangedSignificantly(float filter, - float newValue, float currentValue, float min, float max); - static bool hasMovedNearerToValueWithinFilteredRange(float filter, - float newValue, float currentValue, float thresholdValue); - - static bool isCenteredAxis(int32_t axis); - static int32_t getCompatAxis(int32_t axis); - - static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info); - static void setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, - float value); -}; - -} // namespace android - -#endif // _UI_INPUT_READER_H diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp deleted file mode 100644 index fe61918..0000000 --- a/services/input/InputWindow.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "InputWindow" - -#include "InputWindow.h" - -#include <cutils/log.h> - -namespace android { - -// --- InputWindowInfo --- - -bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { - return touchableRegion.contains(x, y); -} - -bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x <= frameRight - && y >= frameTop && y <= frameBottom; -} - -bool InputWindowInfo::isTrustedOverlay() const { - return layoutParamsType == TYPE_INPUT_METHOD - || layoutParamsType == TYPE_INPUT_METHOD_DIALOG - || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; -} - -bool InputWindowInfo::supportsSplitTouch() const { - return layoutParamsFlags & FLAG_SPLIT_TOUCH; -} - - -// --- InputWindowHandle --- - -InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) : - inputApplicationHandle(inputApplicationHandle), mInfo(NULL) { -} - -InputWindowHandle::~InputWindowHandle() { - delete mInfo; -} - -void InputWindowHandle::releaseInfo() { - if (mInfo) { - delete mInfo; - mInfo = NULL; - } -} - -} // namespace android diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h deleted file mode 100644 index 28fa7ab..0000000 --- a/services/input/InputWindow.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_WINDOW_H -#define _UI_INPUT_WINDOW_H - -#include <input/Input.h> -#include <input/InputTransport.h> -#include <utils/RefBase.h> -#include <utils/Timers.h> -#include <utils/String8.h> - -#include <SkRegion.h> - -#include "InputApplication.h" - -namespace android { - -/* - * Describes the properties of a window that can receive input. - */ -struct InputWindowInfo { - // Window flags from WindowManager.LayoutParams - enum { - FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, - FLAG_DIM_BEHIND = 0x00000002, - FLAG_BLUR_BEHIND = 0x00000004, - FLAG_NOT_FOCUSABLE = 0x00000008, - FLAG_NOT_TOUCHABLE = 0x00000010, - FLAG_NOT_TOUCH_MODAL = 0x00000020, - FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, - FLAG_KEEP_SCREEN_ON = 0x00000080, - FLAG_LAYOUT_IN_SCREEN = 0x00000100, - FLAG_LAYOUT_NO_LIMITS = 0x00000200, - FLAG_FULLSCREEN = 0x00000400, - FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, - FLAG_DITHER = 0x00001000, - FLAG_SECURE = 0x00002000, - FLAG_SCALED = 0x00004000, - FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, - FLAG_LAYOUT_INSET_DECOR = 0x00010000, - FLAG_ALT_FOCUSABLE_IM = 0x00020000, - FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, - FLAG_SHOW_WHEN_LOCKED = 0x00080000, - FLAG_SHOW_WALLPAPER = 0x00100000, - FLAG_TURN_SCREEN_ON = 0x00200000, - FLAG_DISMISS_KEYGUARD = 0x00400000, - FLAG_SPLIT_TOUCH = 0x00800000, - FLAG_SLIPPERY = 0x20000000, - FLAG_NEEDS_MENU_KEY = 0x40000000, - }; - - // Private Window flags from WindowManager.LayoutParams - enum { - PRIVATE_FLAG_SYSTEM_ERROR = 0x00000100, - }; - - // Window types from WindowManager.LayoutParams - enum { - FIRST_APPLICATION_WINDOW = 1, - TYPE_BASE_APPLICATION = 1, - TYPE_APPLICATION = 2, - TYPE_APPLICATION_STARTING = 3, - LAST_APPLICATION_WINDOW = 99, - FIRST_SUB_WINDOW = 1000, - TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, - TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, - TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, - TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, - TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, - LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, - TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, - TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, - TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, - TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, - TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, - TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, - TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, - TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, - TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, - TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, - TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, - TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, - TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, - TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14, - TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, - TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, - TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17, - TYPE_POINTER = FIRST_SYSTEM_WINDOW+18, - TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19, - TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20, - TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21, - LAST_SYSTEM_WINDOW = 2999, - }; - - enum { - INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001, - INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002, - INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004, - }; - - sp<InputChannel> inputChannel; - String8 name; - int32_t layoutParamsFlags; - int32_t layoutParamsPrivateFlags; - int32_t layoutParamsType; - nsecs_t dispatchingTimeout; - int32_t frameLeft; - int32_t frameTop; - int32_t frameRight; - int32_t frameBottom; - float scaleFactor; - SkRegion touchableRegion; - bool visible; - bool canReceiveKeys; - bool hasFocus; - bool hasWallpaper; - bool paused; - int32_t layer; - int32_t ownerPid; - int32_t ownerUid; - int32_t inputFeatures; - int32_t displayId; - - bool touchableRegionContainsPoint(int32_t x, int32_t y) const; - bool frameContainsPoint(int32_t x, int32_t y) const; - - /* Returns true if the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool isTrustedOverlay() const; - - bool supportsSplitTouch() const; -}; - - -/* - * Handle for a window that can receive input. - * - * Used by the native input dispatcher to indirectly refer to the window manager objects - * that describe a window. - */ -class InputWindowHandle : public RefBase { -public: - const sp<InputApplicationHandle> inputApplicationHandle; - - inline const InputWindowInfo* getInfo() const { - return mInfo; - } - - inline sp<InputChannel> getInputChannel() const { - return mInfo ? mInfo->inputChannel : NULL; - } - - inline String8 getName() const { - return mInfo ? mInfo->name : String8("<invalid>"); - } - - inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { - return mInfo ? mInfo->dispatchingTimeout : defaultValue; - } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() = 0; - - /** - * Releases the storage used by the associated information when it is - * no longer needed. - */ - void releaseInfo(); - -protected: - InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle); - virtual ~InputWindowHandle(); - - InputWindowInfo* mInfo; -}; - -} // namespace android - -#endif // _UI_INPUT_WINDOW_H diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp deleted file mode 100644 index 9af521b..0000000 --- a/services/input/PointerController.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "PointerController" - -//#define LOG_NDEBUG 0 - -// Log debug messages about pointer updates -#define DEBUG_POINTER_UPDATES 0 - -#include "PointerController.h" - -#include <cutils/log.h> - -#include <SkBitmap.h> -#include <SkCanvas.h> -#include <SkColor.h> -#include <SkPaint.h> -#include <SkXfermode.h> - -namespace android { - -// --- PointerController --- - -// Time to wait before starting the fade when the pointer is inactive. -static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds -static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds - -// Time to wait between animation frames. -static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60; - -// Time to spend fading out the spot completely. -static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms - -// Time to spend fading out the pointer completely. -static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms - - -// --- PointerController --- - -PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy, - const sp<Looper>& looper, const sp<SpriteController>& spriteController) : - mPolicy(policy), mLooper(looper), mSpriteController(spriteController) { - mHandler = new WeakMessageHandler(this); - - AutoMutex _l(mLock); - - mLocked.animationPending = false; - - mLocked.displayWidth = -1; - mLocked.displayHeight = -1; - mLocked.displayOrientation = DISPLAY_ORIENTATION_0; - - mLocked.presentation = PRESENTATION_POINTER; - mLocked.presentationChanged = false; - - mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL; - - mLocked.pointerFadeDirection = 0; - mLocked.pointerX = 0; - mLocked.pointerY = 0; - mLocked.pointerAlpha = 0.0f; // pointer is initially faded - mLocked.pointerSprite = mSpriteController->createSprite(); - mLocked.pointerIconChanged = false; - - mLocked.buttonState = 0; - - loadResources(); -} - -PointerController::~PointerController() { - mLooper->removeMessages(mHandler); - - AutoMutex _l(mLock); - - mLocked.pointerSprite.clear(); - - for (size_t i = 0; i < mLocked.spots.size(); i++) { - delete mLocked.spots.itemAt(i); - } - mLocked.spots.clear(); - mLocked.recycledSprites.clear(); -} - -bool PointerController::getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const { - AutoMutex _l(mLock); - - return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); -} - -bool PointerController::getBoundsLocked(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const { - if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) { - return false; - } - - *outMinX = 0; - *outMinY = 0; - switch (mLocked.displayOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: - *outMaxX = mLocked.displayHeight - 1; - *outMaxY = mLocked.displayWidth - 1; - break; - default: - *outMaxX = mLocked.displayWidth - 1; - *outMaxY = mLocked.displayHeight - 1; - break; - } - return true; -} - -void PointerController::move(float deltaX, float deltaY) { -#if DEBUG_POINTER_UPDATES - ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY); -#endif - if (deltaX == 0.0f && deltaY == 0.0f) { - return; - } - - AutoMutex _l(mLock); - - setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); -} - -void PointerController::setButtonState(int32_t buttonState) { -#if DEBUG_POINTER_UPDATES - ALOGD("Set button state 0x%08x", buttonState); -#endif - AutoMutex _l(mLock); - - if (mLocked.buttonState != buttonState) { - mLocked.buttonState = buttonState; - } -} - -int32_t PointerController::getButtonState() const { - AutoMutex _l(mLock); - - return mLocked.buttonState; -} - -void PointerController::setPosition(float x, float y) { -#if DEBUG_POINTER_UPDATES - ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y); -#endif - AutoMutex _l(mLock); - - setPositionLocked(x, y); -} - -void PointerController::setPositionLocked(float x, float y) { - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - if (x <= minX) { - mLocked.pointerX = minX; - } else if (x >= maxX) { - mLocked.pointerX = maxX; - } else { - mLocked.pointerX = x; - } - if (y <= minY) { - mLocked.pointerY = minY; - } else if (y >= maxY) { - mLocked.pointerY = maxY; - } else { - mLocked.pointerY = y; - } - updatePointerLocked(); - } -} - -void PointerController::getPosition(float* outX, float* outY) const { - AutoMutex _l(mLock); - - *outX = mLocked.pointerX; - *outY = mLocked.pointerY; -} - -void PointerController::fade(Transition transition) { - AutoMutex _l(mLock); - - // Remove the inactivity timeout, since we are fading now. - removeInactivityTimeoutLocked(); - - // Start fading. - if (transition == TRANSITION_IMMEDIATE) { - mLocked.pointerFadeDirection = 0; - mLocked.pointerAlpha = 0.0f; - updatePointerLocked(); - } else { - mLocked.pointerFadeDirection = -1; - startAnimationLocked(); - } -} - -void PointerController::unfade(Transition transition) { - AutoMutex _l(mLock); - - // Always reset the inactivity timer. - resetInactivityTimeoutLocked(); - - // Start unfading. - if (transition == TRANSITION_IMMEDIATE) { - mLocked.pointerFadeDirection = 0; - mLocked.pointerAlpha = 1.0f; - updatePointerLocked(); - } else { - mLocked.pointerFadeDirection = 1; - startAnimationLocked(); - } -} - -void PointerController::setPresentation(Presentation presentation) { - AutoMutex _l(mLock); - - if (mLocked.presentation != presentation) { - mLocked.presentation = presentation; - mLocked.presentationChanged = true; - - if (presentation != PRESENTATION_SPOT) { - fadeOutAndReleaseAllSpotsLocked(); - } - - updatePointerLocked(); - } -} - -void PointerController::setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { -#if DEBUG_POINTER_UPDATES - ALOGD("setSpots: idBits=%08x", spotIdBits.value); - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.firstMarkedBit(); - idBits.clearBit(id); - const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id, - c.getAxisValue(AMOTION_EVENT_AXIS_X), - c.getAxisValue(AMOTION_EVENT_AXIS_Y), - c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } -#endif - - AutoMutex _l(mLock); - - mSpriteController->openTransaction(); - - // Add or move spots for fingers that are down. - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0 - ? mResources.spotTouch : mResources.spotHover; - float x = c.getAxisValue(AMOTION_EVENT_AXIS_X); - float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y); - - Spot* spot = getSpotLocked(id); - if (!spot) { - spot = createAndAddSpotLocked(id); - } - - spot->updateSprite(&icon, x, y); - } - - // Remove spots for fingers that went up. - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id != Spot::INVALID_ID - && !spotIdBits.hasBit(spot->id)) { - fadeOutAndReleaseSpotLocked(spot); - } - } - - mSpriteController->closeTransaction(); -} - -void PointerController::clearSpots() { -#if DEBUG_POINTER_UPDATES - ALOGD("clearSpots"); -#endif - - AutoMutex _l(mLock); - - fadeOutAndReleaseAllSpotsLocked(); -} - -void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) { - AutoMutex _l(mLock); - - if (mLocked.inactivityTimeout != inactivityTimeout) { - mLocked.inactivityTimeout = inactivityTimeout; - resetInactivityTimeoutLocked(); - } -} - -void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) { - AutoMutex _l(mLock); - - // Adjust to use the display's unrotated coordinate frame. - if (orientation == DISPLAY_ORIENTATION_90 - || orientation == DISPLAY_ORIENTATION_270) { - int32_t temp = height; - height = width; - width = temp; - } - - if (mLocked.displayWidth != width || mLocked.displayHeight != height) { - mLocked.displayWidth = width; - mLocked.displayHeight = height; - - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - mLocked.pointerX = (minX + maxX) * 0.5f; - mLocked.pointerY = (minY + maxY) * 0.5f; - } else { - mLocked.pointerX = 0; - mLocked.pointerY = 0; - } - - fadeOutAndReleaseAllSpotsLocked(); - } - - if (mLocked.displayOrientation != orientation) { - // Apply offsets to convert from the pixel top-left corner position to the pixel center. - // This creates an invariant frame of reference that we can easily rotate when - // taking into account that the pointer may be located at fractional pixel offsets. - float x = mLocked.pointerX + 0.5f; - float y = mLocked.pointerY + 0.5f; - float temp; - - // Undo the previous rotation. - switch (mLocked.displayOrientation) { - case DISPLAY_ORIENTATION_90: - temp = x; - x = mLocked.displayWidth - y; - y = temp; - break; - case DISPLAY_ORIENTATION_180: - x = mLocked.displayWidth - x; - y = mLocked.displayHeight - y; - break; - case DISPLAY_ORIENTATION_270: - temp = x; - x = y; - y = mLocked.displayHeight - temp; - break; - } - - // Perform the new rotation. - switch (orientation) { - case DISPLAY_ORIENTATION_90: - temp = x; - x = y; - y = mLocked.displayWidth - temp; - break; - case DISPLAY_ORIENTATION_180: - x = mLocked.displayWidth - x; - y = mLocked.displayHeight - y; - break; - case DISPLAY_ORIENTATION_270: - temp = x; - x = mLocked.displayHeight - y; - y = temp; - break; - } - - // Apply offsets to convert from the pixel center to the pixel top-left corner position - // and save the results. - mLocked.pointerX = x - 0.5f; - mLocked.pointerY = y - 0.5f; - mLocked.displayOrientation = orientation; - } - - updatePointerLocked(); -} - -void PointerController::setPointerIcon(const SpriteIcon& icon) { - AutoMutex _l(mLock); - - mLocked.pointerIcon = icon.copy(); - mLocked.pointerIconChanged = true; - - updatePointerLocked(); -} - -void PointerController::handleMessage(const Message& message) { - switch (message.what) { - case MSG_ANIMATE: - doAnimate(); - break; - case MSG_INACTIVITY_TIMEOUT: - doInactivityTimeout(); - break; - } -} - -void PointerController::doAnimate() { - AutoMutex _l(mLock); - - bool keepAnimating = false; - mLocked.animationPending = false; - nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime; - - // Animate pointer fade. - if (mLocked.pointerFadeDirection < 0) { - mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION; - if (mLocked.pointerAlpha <= 0.0f) { - mLocked.pointerAlpha = 0.0f; - mLocked.pointerFadeDirection = 0; - } else { - keepAnimating = true; - } - updatePointerLocked(); - } else if (mLocked.pointerFadeDirection > 0) { - mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION; - if (mLocked.pointerAlpha >= 1.0f) { - mLocked.pointerAlpha = 1.0f; - mLocked.pointerFadeDirection = 0; - } else { - keepAnimating = true; - } - updatePointerLocked(); - } - - // Animate spots that are fading out and being removed. - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == Spot::INVALID_ID) { - spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION; - if (spot->alpha <= 0) { - mLocked.spots.removeAt(i--); - releaseSpotLocked(spot); - } else { - spot->sprite->setAlpha(spot->alpha); - keepAnimating = true; - } - } - } - - if (keepAnimating) { - startAnimationLocked(); - } -} - -void PointerController::doInactivityTimeout() { - fade(TRANSITION_GRADUAL); -} - -void PointerController::startAnimationLocked() { - if (!mLocked.animationPending) { - mLocked.animationPending = true; - mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC); - mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE)); - } -} - -void PointerController::resetInactivityTimeoutLocked() { - mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); - - nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT - ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL; - mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT); -} - -void PointerController::removeInactivityTimeoutLocked() { - mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); -} - -void PointerController::updatePointerLocked() { - mSpriteController->openTransaction(); - - mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER); - mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY); - - if (mLocked.pointerAlpha > 0) { - mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha); - mLocked.pointerSprite->setVisible(true); - } else { - mLocked.pointerSprite->setVisible(false); - } - - if (mLocked.pointerIconChanged || mLocked.presentationChanged) { - mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER - ? mLocked.pointerIcon : mResources.spotAnchor); - mLocked.pointerIconChanged = false; - mLocked.presentationChanged = false; - } - - mSpriteController->closeTransaction(); -} - -PointerController::Spot* PointerController::getSpotLocked(uint32_t id) { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == id) { - return spot; - } - } - return NULL; -} - -PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) { - // Remove spots until we have fewer than MAX_SPOTS remaining. - while (mLocked.spots.size() >= MAX_SPOTS) { - Spot* spot = removeFirstFadingSpotLocked(); - if (!spot) { - spot = mLocked.spots.itemAt(0); - mLocked.spots.removeAt(0); - } - releaseSpotLocked(spot); - } - - // Obtain a sprite from the recycled pool. - sp<Sprite> sprite; - if (! mLocked.recycledSprites.isEmpty()) { - sprite = mLocked.recycledSprites.top(); - mLocked.recycledSprites.pop(); - } else { - sprite = mSpriteController->createSprite(); - } - - // Return the new spot. - Spot* spot = new Spot(id, sprite); - mLocked.spots.push(spot); - return spot; -} - -PointerController::Spot* PointerController::removeFirstFadingSpotLocked() { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == Spot::INVALID_ID) { - mLocked.spots.removeAt(i); - return spot; - } - } - return NULL; -} - -void PointerController::releaseSpotLocked(Spot* spot) { - spot->sprite->clearIcon(); - - if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) { - mLocked.recycledSprites.push(spot->sprite); - } - - delete spot; -} - -void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) { - if (spot->id != Spot::INVALID_ID) { - spot->id = Spot::INVALID_ID; - startAnimationLocked(); - } -} - -void PointerController::fadeOutAndReleaseAllSpotsLocked() { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - fadeOutAndReleaseSpotLocked(spot); - } -} - -void PointerController::loadResources() { - mPolicy->loadPointerResources(&mResources); -} - - -// --- PointerController::Spot --- - -void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) { - sprite->setLayer(Sprite::BASE_LAYER_SPOT + id); - sprite->setAlpha(alpha); - sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale)); - sprite->setPosition(x, y); - - this->x = x; - this->y = y; - - if (icon != lastIcon) { - lastIcon = icon; - if (icon) { - sprite->setIcon(*icon); - sprite->setVisible(true); - } else { - sprite->setVisible(false); - } - } -} - -} // namespace android diff --git a/services/input/PointerController.h b/services/input/PointerController.h deleted file mode 100644 index 790c0bb..0000000 --- a/services/input/PointerController.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_POINTER_CONTROLLER_H -#define _UI_POINTER_CONTROLLER_H - -#include "SpriteController.h" - -#include <ui/DisplayInfo.h> -#include <input/Input.h> -#include <utils/BitSet.h> -#include <utils/RefBase.h> -#include <utils/Looper.h> -#include <utils/String8.h> - -#include <SkBitmap.h> - -namespace android { - -/** - * Interface for tracking a mouse / touch pad pointer and touch pad spots. - * - * The spots are sprites on screen that visually represent the positions of - * fingers - * - * The pointer controller is responsible for providing synchronization and for tracking - * display orientation changes if needed. - */ -class PointerControllerInterface : public virtual RefBase { -protected: - PointerControllerInterface() { } - virtual ~PointerControllerInterface() { } - -public: - /* Gets the bounds of the region that the pointer can traverse. - * Returns true if the bounds are available. */ - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const = 0; - - /* Move the pointer. */ - virtual void move(float deltaX, float deltaY) = 0; - - /* Sets a mask that indicates which buttons are pressed. */ - virtual void setButtonState(int32_t buttonState) = 0; - - /* Gets a mask that indicates which buttons are pressed. */ - virtual int32_t getButtonState() const = 0; - - /* Sets the absolute location of the pointer. */ - virtual void setPosition(float x, float y) = 0; - - /* Gets the absolute location of the pointer. */ - virtual void getPosition(float* outX, float* outY) const = 0; - - enum Transition { - // Fade/unfade immediately. - TRANSITION_IMMEDIATE, - // Fade/unfade gradually. - TRANSITION_GRADUAL, - }; - - /* Fades the pointer out now. */ - virtual void fade(Transition transition) = 0; - - /* Makes the pointer visible if it has faded out. - * The pointer never unfades itself automatically. This method must be called - * by the client whenever the pointer is moved or a button is pressed and it - * wants to ensure that the pointer becomes visible again. */ - virtual void unfade(Transition transition) = 0; - - enum Presentation { - // Show the mouse pointer. - PRESENTATION_POINTER, - // Show spots and a spot anchor in place of the mouse pointer. - PRESENTATION_SPOT, - }; - - /* Sets the mode of the pointer controller. */ - virtual void setPresentation(Presentation presentation) = 0; - - /* Sets the spots for the current gesture. - * The spots are not subject to the inactivity timeout like the pointer - * itself it since they are expected to remain visible for so long as - * the fingers are on the touch pad. - * - * The values of the AMOTION_EVENT_AXIS_PRESSURE axis is significant. - * For spotCoords, pressure != 0 indicates that the spot's location is being - * pressed (not hovering). - */ - virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits) = 0; - - /* Removes all spots. */ - virtual void clearSpots() = 0; -}; - - -/* - * Pointer resources. - */ -struct PointerResources { - SpriteIcon spotHover; - SpriteIcon spotTouch; - SpriteIcon spotAnchor; -}; - - -/* - * Pointer controller policy interface. - * - * The pointer controller policy is used by the pointer controller to interact with - * the Window Manager and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - */ -class PointerControllerPolicyInterface : public virtual RefBase { -protected: - PointerControllerPolicyInterface() { } - virtual ~PointerControllerPolicyInterface() { } - -public: - virtual void loadPointerResources(PointerResources* outResources) = 0; -}; - - -/* - * Tracks pointer movements and draws the pointer sprite to a surface. - * - * Handles pointer acceleration and animation. - */ -class PointerController : public PointerControllerInterface, public MessageHandler { -protected: - virtual ~PointerController(); - -public: - enum InactivityTimeout { - INACTIVITY_TIMEOUT_NORMAL = 0, - INACTIVITY_TIMEOUT_SHORT = 1, - }; - - PointerController(const sp<PointerControllerPolicyInterface>& policy, - const sp<Looper>& looper, const sp<SpriteController>& spriteController); - - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const; - virtual void move(float deltaX, float deltaY); - virtual void setButtonState(int32_t buttonState); - virtual int32_t getButtonState() const; - virtual void setPosition(float x, float y); - virtual void getPosition(float* outX, float* outY) const; - virtual void fade(Transition transition); - virtual void unfade(Transition transition); - - virtual void setPresentation(Presentation presentation); - virtual void setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits); - virtual void clearSpots(); - - void setDisplayViewport(int32_t width, int32_t height, int32_t orientation); - void setPointerIcon(const SpriteIcon& icon); - void setInactivityTimeout(InactivityTimeout inactivityTimeout); - -private: - static const size_t MAX_RECYCLED_SPRITES = 12; - static const size_t MAX_SPOTS = 12; - - enum { - MSG_ANIMATE, - MSG_INACTIVITY_TIMEOUT, - }; - - struct Spot { - static const uint32_t INVALID_ID = 0xffffffff; - - uint32_t id; - sp<Sprite> sprite; - float alpha; - float scale; - float x, y; - - inline Spot(uint32_t id, const sp<Sprite>& sprite) - : id(id), sprite(sprite), alpha(1.0f), scale(1.0f), - x(0.0f), y(0.0f), lastIcon(NULL) { } - - void updateSprite(const SpriteIcon* icon, float x, float y); - - private: - const SpriteIcon* lastIcon; - }; - - mutable Mutex mLock; - - sp<PointerControllerPolicyInterface> mPolicy; - sp<Looper> mLooper; - sp<SpriteController> mSpriteController; - sp<WeakMessageHandler> mHandler; - - PointerResources mResources; - - struct Locked { - bool animationPending; - nsecs_t animationTime; - - int32_t displayWidth; - int32_t displayHeight; - int32_t displayOrientation; - - InactivityTimeout inactivityTimeout; - - Presentation presentation; - bool presentationChanged; - - int32_t pointerFadeDirection; - float pointerX; - float pointerY; - float pointerAlpha; - sp<Sprite> pointerSprite; - SpriteIcon pointerIcon; - bool pointerIconChanged; - - int32_t buttonState; - - Vector<Spot*> spots; - Vector<sp<Sprite> > recycledSprites; - } mLocked; - - bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; - void setPositionLocked(float x, float y); - - void handleMessage(const Message& message); - void doAnimate(); - void doInactivityTimeout(); - - void startAnimationLocked(); - - void resetInactivityTimeoutLocked(); - void removeInactivityTimeoutLocked(); - void updatePointerLocked(); - - Spot* getSpotLocked(uint32_t id); - Spot* createAndAddSpotLocked(uint32_t id); - Spot* removeFirstFadingSpotLocked(); - void releaseSpotLocked(Spot* spot); - void fadeOutAndReleaseSpotLocked(Spot* spot); - void fadeOutAndReleaseAllSpotsLocked(); - - void loadResources(); -}; - -} // namespace android - -#endif // _UI_POINTER_CONTROLLER_H diff --git a/services/input/SpriteController.cpp b/services/input/SpriteController.cpp deleted file mode 100644 index fd9c66b..0000000 --- a/services/input/SpriteController.cpp +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "Sprites" - -//#define LOG_NDEBUG 0 - -#include "SpriteController.h" - -#include <cutils/log.h> -#include <utils/String8.h> -#include <gui/Surface.h> - -#include <SkBitmap.h> -#include <SkCanvas.h> -#include <SkColor.h> -#include <SkPaint.h> -#include <SkXfermode.h> -#include <android/native_window.h> - -namespace android { - -// --- SpriteController --- - -SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLayer) : - mLooper(looper), mOverlayLayer(overlayLayer) { - mHandler = new WeakMessageHandler(this); - - mLocked.transactionNestingCount = 0; - mLocked.deferredSpriteUpdate = false; -} - -SpriteController::~SpriteController() { - mLooper->removeMessages(mHandler); - - if (mSurfaceComposerClient != NULL) { - mSurfaceComposerClient->dispose(); - mSurfaceComposerClient.clear(); - } -} - -sp<Sprite> SpriteController::createSprite() { - return new SpriteImpl(this); -} - -void SpriteController::openTransaction() { - AutoMutex _l(mLock); - - mLocked.transactionNestingCount += 1; -} - -void SpriteController::closeTransaction() { - AutoMutex _l(mLock); - - LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0, - "Sprite closeTransaction() called but there is no open sprite transaction"); - - mLocked.transactionNestingCount -= 1; - if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) { - mLocked.deferredSpriteUpdate = false; - mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); - } -} - -void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) { - bool wasEmpty = mLocked.invalidatedSprites.isEmpty(); - mLocked.invalidatedSprites.push(sprite); - if (wasEmpty) { - if (mLocked.transactionNestingCount != 0) { - mLocked.deferredSpriteUpdate = true; - } else { - mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); - } - } -} - -void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) { - bool wasEmpty = mLocked.disposedSurfaces.isEmpty(); - mLocked.disposedSurfaces.push(surfaceControl); - if (wasEmpty) { - mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES)); - } -} - -void SpriteController::handleMessage(const Message& message) { - switch (message.what) { - case MSG_UPDATE_SPRITES: - doUpdateSprites(); - break; - case MSG_DISPOSE_SURFACES: - doDisposeSurfaces(); - break; - } -} - -void SpriteController::doUpdateSprites() { - // Collect information about sprite updates. - // Each sprite update record includes a reference to its associated sprite so we can - // be certain the sprites will not be deleted while this function runs. Sprites - // may invalidate themselves again during this time but we will handle those changes - // in the next iteration. - Vector<SpriteUpdate> updates; - size_t numSprites; - { // acquire lock - AutoMutex _l(mLock); - - numSprites = mLocked.invalidatedSprites.size(); - for (size_t i = 0; i < numSprites; i++) { - const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i); - - updates.push(SpriteUpdate(sprite, sprite->getStateLocked())); - sprite->resetDirtyLocked(); - } - mLocked.invalidatedSprites.clear(); - } // release lock - - // Create missing surfaces. - bool surfaceChanged = false; - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - - if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) { - update.state.surfaceWidth = update.state.icon.bitmap.width(); - update.state.surfaceHeight = update.state.icon.bitmap.height(); - update.state.surfaceDrawn = false; - update.state.surfaceVisible = false; - update.state.surfaceControl = obtainSurface( - update.state.surfaceWidth, update.state.surfaceHeight); - if (update.state.surfaceControl != NULL) { - update.surfaceChanged = surfaceChanged = true; - } - } - } - - // Resize sprites if needed, inside a global transaction. - bool haveGlobalTransaction = false; - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - - if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) { - int32_t desiredWidth = update.state.icon.bitmap.width(); - int32_t desiredHeight = update.state.icon.bitmap.height(); - if (update.state.surfaceWidth < desiredWidth - || update.state.surfaceHeight < desiredHeight) { - if (!haveGlobalTransaction) { - SurfaceComposerClient::openGlobalTransaction(); - haveGlobalTransaction = true; - } - - status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight); - if (status) { - ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d", - status, update.state.surfaceWidth, update.state.surfaceHeight, - desiredWidth, desiredHeight); - } else { - update.state.surfaceWidth = desiredWidth; - update.state.surfaceHeight = desiredHeight; - update.state.surfaceDrawn = false; - update.surfaceChanged = surfaceChanged = true; - - if (update.state.surfaceVisible) { - status = update.state.surfaceControl->hide(); - if (status) { - ALOGE("Error %d hiding sprite surface after resize.", status); - } else { - update.state.surfaceVisible = false; - } - } - } - } - } - } - if (haveGlobalTransaction) { - SurfaceComposerClient::closeGlobalTransaction(); - } - - // Redraw sprites if needed. - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - - if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) { - update.state.surfaceDrawn = false; - update.surfaceChanged = surfaceChanged = true; - } - - if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn - && update.state.wantSurfaceVisible()) { - sp<Surface> surface = update.state.surfaceControl->getSurface(); - ANativeWindow_Buffer outBuffer; - status_t status = surface->lock(&outBuffer, NULL); - if (status) { - ALOGE("Error %d locking sprite surface before drawing.", status); - } else { - SkBitmap surfaceBitmap; - ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); - surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, - outBuffer.width, outBuffer.height, bpr); - surfaceBitmap.setPixels(outBuffer.bits); - - SkCanvas surfaceCanvas(surfaceBitmap); - - SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint); - - if (outBuffer.width > uint32_t(update.state.icon.bitmap.width())) { - paint.setColor(0); // transparent fill color - surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0, - outBuffer.width, update.state.icon.bitmap.height(), paint); - } - if (outBuffer.height > uint32_t(update.state.icon.bitmap.height())) { - paint.setColor(0); // transparent fill color - surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(), - outBuffer.width, outBuffer.height, paint); - } - - status = surface->unlockAndPost(); - if (status) { - ALOGE("Error %d unlocking and posting sprite surface after drawing.", status); - } else { - update.state.surfaceDrawn = true; - update.surfaceChanged = surfaceChanged = true; - } - } - } - } - - // Set sprite surface properties and make them visible. - bool haveTransaction = false; - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - - bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible() - && update.state.surfaceDrawn; - bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible; - bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible; - if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden - || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA - | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER - | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) { - status_t status; - if (!haveTransaction) { - SurfaceComposerClient::openGlobalTransaction(); - haveTransaction = true; - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) { - status = update.state.surfaceControl->setAlpha(update.state.alpha); - if (status) { - ALOGE("Error %d setting sprite surface alpha.", status); - } - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & (DIRTY_POSITION - | DIRTY_HOTSPOT)))) { - status = update.state.surfaceControl->setPosition( - update.state.positionX - update.state.icon.hotSpotX, - update.state.positionY - update.state.icon.hotSpotY); - if (status) { - ALOGE("Error %d setting sprite surface position.", status); - } - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible - || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) { - status = update.state.surfaceControl->setMatrix( - update.state.transformationMatrix.dsdx, - update.state.transformationMatrix.dtdx, - update.state.transformationMatrix.dsdy, - update.state.transformationMatrix.dtdy); - if (status) { - ALOGE("Error %d setting sprite surface transformation matrix.", status); - } - } - - int32_t surfaceLayer = mOverlayLayer + update.state.layer; - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) { - status = update.state.surfaceControl->setLayer(surfaceLayer); - if (status) { - ALOGE("Error %d setting sprite surface layer.", status); - } - } - - if (becomingVisible) { - status = update.state.surfaceControl->show(); - if (status) { - ALOGE("Error %d showing sprite surface.", status); - } else { - update.state.surfaceVisible = true; - update.surfaceChanged = surfaceChanged = true; - } - } else if (becomingHidden) { - status = update.state.surfaceControl->hide(); - if (status) { - ALOGE("Error %d hiding sprite surface.", status); - } else { - update.state.surfaceVisible = false; - update.surfaceChanged = surfaceChanged = true; - } - } - } - } - - if (haveTransaction) { - SurfaceComposerClient::closeGlobalTransaction(); - } - - // If any surfaces were changed, write back the new surface properties to the sprites. - if (surfaceChanged) { // acquire lock - AutoMutex _l(mLock); - - for (size_t i = 0; i < numSprites; i++) { - const SpriteUpdate& update = updates.itemAt(i); - - if (update.surfaceChanged) { - update.sprite->setSurfaceLocked(update.state.surfaceControl, - update.state.surfaceWidth, update.state.surfaceHeight, - update.state.surfaceDrawn, update.state.surfaceVisible); - } - } - } // release lock - - // Clear the sprite update vector outside the lock. It is very important that - // we do not clear sprite references inside the lock since we could be releasing - // the last remaining reference to the sprite here which would result in the - // sprite being deleted and the lock being reacquired by the sprite destructor - // while already held. - updates.clear(); -} - -void SpriteController::doDisposeSurfaces() { - // Collect disposed surfaces. - Vector<sp<SurfaceControl> > disposedSurfaces; - { // acquire lock - AutoMutex _l(mLock); - - disposedSurfaces = mLocked.disposedSurfaces; - mLocked.disposedSurfaces.clear(); - } // release lock - - // Release the last reference to each surface outside of the lock. - // We don't want the surfaces to be deleted while we are holding our lock. - disposedSurfaces.clear(); -} - -void SpriteController::ensureSurfaceComposerClient() { - if (mSurfaceComposerClient == NULL) { - mSurfaceComposerClient = new SurfaceComposerClient(); - } -} - -sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) { - ensureSurfaceComposerClient(); - - sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface( - String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eHidden); - if (surfaceControl == NULL || !surfaceControl->isValid()) { - ALOGE("Error creating sprite surface."); - return NULL; - } - return surfaceControl; -} - - -// --- SpriteController::SpriteImpl --- - -SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) : - mController(controller) { -} - -SpriteController::SpriteImpl::~SpriteImpl() { - AutoMutex _m(mController->mLock); - - // Let the controller take care of deleting the last reference to sprite - // surfaces so that we do not block the caller on an IPC here. - if (mLocked.state.surfaceControl != NULL) { - mController->disposeSurfaceLocked(mLocked.state.surfaceControl); - mLocked.state.surfaceControl.clear(); - } -} - -void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) { - AutoMutex _l(mController->mLock); - - uint32_t dirty; - if (icon.isValid()) { - icon.bitmap.copyTo(&mLocked.state.icon.bitmap, SkBitmap::kARGB_8888_Config); - - if (!mLocked.state.icon.isValid() - || mLocked.state.icon.hotSpotX != icon.hotSpotX - || mLocked.state.icon.hotSpotY != icon.hotSpotY) { - mLocked.state.icon.hotSpotX = icon.hotSpotX; - mLocked.state.icon.hotSpotY = icon.hotSpotY; - dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; - } else { - dirty = DIRTY_BITMAP; - } - } else if (mLocked.state.icon.isValid()) { - mLocked.state.icon.bitmap.reset(); - dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; - } else { - return; // setting to invalid icon and already invalid so nothing to do - } - - invalidateLocked(dirty); -} - -void SpriteController::SpriteImpl::setVisible(bool visible) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.visible != visible) { - mLocked.state.visible = visible; - invalidateLocked(DIRTY_VISIBILITY); - } -} - -void SpriteController::SpriteImpl::setPosition(float x, float y) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.positionX != x || mLocked.state.positionY != y) { - mLocked.state.positionX = x; - mLocked.state.positionY = y; - invalidateLocked(DIRTY_POSITION); - } -} - -void SpriteController::SpriteImpl::setLayer(int32_t layer) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.layer != layer) { - mLocked.state.layer = layer; - invalidateLocked(DIRTY_LAYER); - } -} - -void SpriteController::SpriteImpl::setAlpha(float alpha) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.alpha != alpha) { - mLocked.state.alpha = alpha; - invalidateLocked(DIRTY_ALPHA); - } -} - -void SpriteController::SpriteImpl::setTransformationMatrix( - const SpriteTransformationMatrix& matrix) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.transformationMatrix != matrix) { - mLocked.state.transformationMatrix = matrix; - invalidateLocked(DIRTY_TRANSFORMATION_MATRIX); - } -} - -void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) { - bool wasDirty = mLocked.state.dirty; - mLocked.state.dirty |= dirty; - - if (!wasDirty) { - mController->invalidateSpriteLocked(this); - } -} - -} // namespace android diff --git a/services/input/SpriteController.h b/services/input/SpriteController.h deleted file mode 100644 index 75e4843..0000000 --- a/services/input/SpriteController.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_SPRITES_H -#define _UI_SPRITES_H - -#include <utils/RefBase.h> -#include <utils/Looper.h> - -#include <gui/SurfaceComposerClient.h> - -#include <SkBitmap.h> - -namespace android { - -/* - * Transformation matrix for a sprite. - */ -struct SpriteTransformationMatrix { - inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { } - inline SpriteTransformationMatrix(float dsdx, float dtdx, float dsdy, float dtdy) : - dsdx(dsdx), dtdx(dtdx), dsdy(dsdy), dtdy(dtdy) { } - - float dsdx; - float dtdx; - float dsdy; - float dtdy; - - inline bool operator== (const SpriteTransformationMatrix& other) { - return dsdx == other.dsdx - && dtdx == other.dtdx - && dsdy == other.dsdy - && dtdy == other.dtdy; - } - - inline bool operator!= (const SpriteTransformationMatrix& other) { - return !(*this == other); - } -}; - -/* - * Icon that a sprite displays, including its hotspot. - */ -struct SpriteIcon { - inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { } - inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) : - bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { } - - SkBitmap bitmap; - float hotSpotX; - float hotSpotY; - - inline SpriteIcon copy() const { - SkBitmap bitmapCopy; - bitmap.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config); - return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY); - } - - inline void reset() { - bitmap.reset(); - hotSpotX = 0; - hotSpotY = 0; - } - - inline bool isValid() const { - return !bitmap.isNull() && !bitmap.empty(); - } -}; - -/* - * A sprite is a simple graphical object that is displayed on-screen above other layers. - * The basic sprite class is an interface. - * The implementation is provided by the sprite controller. - */ -class Sprite : public RefBase { -protected: - Sprite() { } - virtual ~Sprite() { } - -public: - enum { - // The base layer for pointer sprites. - BASE_LAYER_POINTER = 0, // reserve space for 1 pointer - - // The base layer for spot sprites. - BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots - }; - - /* Sets the bitmap that is drawn by the sprite. - * The sprite retains a copy of the bitmap for subsequent rendering. */ - virtual void setIcon(const SpriteIcon& icon) = 0; - - inline void clearIcon() { - setIcon(SpriteIcon()); - } - - /* Sets whether the sprite is visible. */ - virtual void setVisible(bool visible) = 0; - - /* Sets the sprite position on screen, relative to the sprite's hot spot. */ - virtual void setPosition(float x, float y) = 0; - - /* Sets the layer of the sprite, relative to the system sprite overlay layer. - * Layer 0 is the overlay layer, > 0 appear above this layer. */ - virtual void setLayer(int32_t layer) = 0; - - /* Sets the sprite alpha blend ratio between 0.0 and 1.0. */ - virtual void setAlpha(float alpha) = 0; - - /* Sets the sprite transformation matrix. */ - virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0; -}; - -/* - * Displays sprites on the screen. - * - * This interface is used by PointerController and SpotController to draw pointers or - * spot representations of fingers. It is not intended for general purpose use - * by other components. - * - * All sprite position updates and rendering is performed asynchronously. - * - * Clients are responsible for animating sprites by periodically updating their properties. - */ -class SpriteController : public MessageHandler { -protected: - virtual ~SpriteController(); - -public: - SpriteController(const sp<Looper>& looper, int32_t overlayLayer); - - /* Creates a new sprite, initially invisible. */ - sp<Sprite> createSprite(); - - /* Opens or closes a transaction to perform a batch of sprite updates as part of - * a single operation such as setPosition and setAlpha. It is not necessary to - * open a transaction when updating a single property. - * Calls to openTransaction() nest and must be matched by an equal number - * of calls to closeTransaction(). */ - void openTransaction(); - void closeTransaction(); - -private: - enum { - MSG_UPDATE_SPRITES, - MSG_DISPOSE_SURFACES, - }; - - enum { - DIRTY_BITMAP = 1 << 0, - DIRTY_ALPHA = 1 << 1, - DIRTY_POSITION = 1 << 2, - DIRTY_TRANSFORMATION_MATRIX = 1 << 3, - DIRTY_LAYER = 1 << 4, - DIRTY_VISIBILITY = 1 << 5, - DIRTY_HOTSPOT = 1 << 6, - }; - - /* Describes the state of a sprite. - * This structure is designed so that it can be copied during updates so that - * surfaces can be resized and redrawn without blocking the client by holding a lock - * on the sprites for a long time. - * Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */ - struct SpriteState { - inline SpriteState() : - dirty(0), visible(false), - positionX(0), positionY(0), layer(0), alpha(1.0f), - surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) { - } - - uint32_t dirty; - - SpriteIcon icon; - bool visible; - float positionX; - float positionY; - int32_t layer; - float alpha; - SpriteTransformationMatrix transformationMatrix; - - sp<SurfaceControl> surfaceControl; - int32_t surfaceWidth; - int32_t surfaceHeight; - bool surfaceDrawn; - bool surfaceVisible; - - inline bool wantSurfaceVisible() const { - return visible && alpha > 0.0f && icon.isValid(); - } - }; - - /* Client interface for a sprite. - * Requests acquire a lock on the controller, update local state and request the - * controller to invalidate the sprite. - * The real heavy lifting of creating, resizing and redrawing surfaces happens - * asynchronously with no locks held except in short critical section to copy - * the sprite state before the work and update the sprite surface control afterwards. - */ - class SpriteImpl : public Sprite { - protected: - virtual ~SpriteImpl(); - - public: - SpriteImpl(const sp<SpriteController> controller); - - virtual void setIcon(const SpriteIcon& icon); - virtual void setVisible(bool visible); - virtual void setPosition(float x, float y); - virtual void setLayer(int32_t layer); - virtual void setAlpha(float alpha); - virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix); - - inline const SpriteState& getStateLocked() const { - return mLocked.state; - } - - inline void resetDirtyLocked() { - mLocked.state.dirty = 0; - } - - inline void setSurfaceLocked(const sp<SurfaceControl>& surfaceControl, - int32_t width, int32_t height, bool drawn, bool visible) { - mLocked.state.surfaceControl = surfaceControl; - mLocked.state.surfaceWidth = width; - mLocked.state.surfaceHeight = height; - mLocked.state.surfaceDrawn = drawn; - mLocked.state.surfaceVisible = visible; - } - - private: - sp<SpriteController> mController; - - struct Locked { - SpriteState state; - } mLocked; // guarded by mController->mLock - - void invalidateLocked(uint32_t dirty); - }; - - /* Stores temporary information collected during the sprite update cycle. */ - struct SpriteUpdate { - inline SpriteUpdate() : surfaceChanged(false) { } - inline SpriteUpdate(const sp<SpriteImpl> sprite, const SpriteState& state) : - sprite(sprite), state(state), surfaceChanged(false) { - } - - sp<SpriteImpl> sprite; - SpriteState state; - bool surfaceChanged; - }; - - mutable Mutex mLock; - - sp<Looper> mLooper; - const int32_t mOverlayLayer; - sp<WeakMessageHandler> mHandler; - - sp<SurfaceComposerClient> mSurfaceComposerClient; - - struct Locked { - Vector<sp<SpriteImpl> > invalidatedSprites; - Vector<sp<SurfaceControl> > disposedSurfaces; - uint32_t transactionNestingCount; - bool deferredSpriteUpdate; - } mLocked; // guarded by mLock - - void invalidateSpriteLocked(const sp<SpriteImpl>& sprite); - void disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl); - - void handleMessage(const Message& message); - void doUpdateSprites(); - void doDisposeSurfaces(); - - void ensureSurfaceComposerClient(); - sp<SurfaceControl> obtainSurface(int32_t width, int32_t height); -}; - -} // namespace android - -#endif // _UI_SPRITES_H diff --git a/services/input/tests/Android.mk b/services/input/tests/Android.mk deleted file mode 100644 index 9278f41..0000000 --- a/services/input/tests/Android.mk +++ /dev/null @@ -1,48 +0,0 @@ -# Build the unit tests. -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# Build the unit tests. -test_src_files := \ - InputReader_test.cpp \ - InputDispatcher_test.cpp - -shared_libraries := \ - libcutils \ - liblog \ - libandroidfw \ - libutils \ - libhardware \ - libhardware_legacy \ - libui \ - libskia \ - libstlport \ - libinput \ - libinputservice - -static_libraries := \ - libgtest \ - libgtest_main - -c_includes := \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ - external/skia/include/core - -module_tags := eng tests - -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_C_INCLUDES := $(c_includes)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ - $(eval include $(BUILD_NATIVE_TEST)) \ -) - -# Build the manual test programs. -include $(call all-makefiles-under, $(LOCAL_PATH)) diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp deleted file mode 100644 index 26b4fab..0000000 --- a/services/input/tests/InputDispatcher_test.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2010 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 "../InputDispatcher.h" - -#include <gtest/gtest.h> -#include <linux/input.h> - -namespace android { - -// An arbitrary time value. -static const nsecs_t ARBITRARY_TIME = 1234; - -// An arbitrary device id. -static const int32_t DEVICE_ID = 1; - -// An arbitrary injector pid / uid pair that has permission to inject events. -static const int32_t INJECTOR_PID = 999; -static const int32_t INJECTOR_UID = 1001; - - -// --- FakeInputDispatcherPolicy --- - -class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { - InputDispatcherConfiguration mConfig; - -protected: - virtual ~FakeInputDispatcherPolicy() { - } - -public: - FakeInputDispatcherPolicy() { - } - -private: - virtual void notifyConfigurationChanged(nsecs_t when) { - } - - virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputWindowHandle>& inputWindowHandle, - const String8& reason) { - return 0; - } - - virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) { - } - - virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { - *outConfig = mConfig; - } - - virtual bool isKeyRepeatEnabled() { - return true; - } - - virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) { - return true; - } - - virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) { - } - - virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { - } - - virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, - const KeyEvent* keyEvent, uint32_t policyFlags) { - return 0; - } - - virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, - const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) { - return false; - } - - virtual void notifySwitch(nsecs_t when, - uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) { - } - - virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) { - } - - virtual bool checkInjectEventsPermissionNonReentrant( - int32_t injectorPid, int32_t injectorUid) { - return false; - } -}; - - -// --- InputDispatcherTest --- - -class InputDispatcherTest : public testing::Test { -protected: - sp<FakeInputDispatcherPolicy> mFakePolicy; - sp<InputDispatcher> mDispatcher; - - virtual void SetUp() { - mFakePolicy = new FakeInputDispatcherPolicy(); - mDispatcher = new InputDispatcher(mFakePolicy); - } - - virtual void TearDown() { - mFakePolicy.clear(); - mDispatcher.clear(); - } -}; - - -TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { - KeyEvent event; - - // Rejects undefined key actions. - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - /*action*/ -1, 0, - AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject key events with undefined action."; - - // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API. - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - AKEY_EVENT_ACTION_MULTIPLE, 0, - AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject key events with ACTION_MULTIPLE."; -} - -TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { - MotionEvent event; - PointerProperties pointerProperties[MAX_POINTERS + 1]; - PointerCoords pointerCoords[MAX_POINTERS + 1]; - for (int i = 0; i <= MAX_POINTERS; i++) { - pointerProperties[i].clear(); - pointerProperties[i].id = i; - pointerCoords[i].clear(); - } - - // Rejects undefined motion actions. - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject motion events with undefined action."; - - // Rejects pointer down with invalid index. - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject motion events with pointer down index too large."; - - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject motion events with pointer down index too small."; - - // Rejects pointer up with invalid index. - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject motion events with pointer up index too large."; - - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject motion events with pointer up index too small."; - - // Rejects motion events with invalid number of pointers. - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 0, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject motion events with 0 pointers."; - - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject motion events with more than MAX_POINTERS pointers."; - - // Rejects motion events with invalid pointer ids. - pointerProperties[0].id = -1; - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject motion events with pointer ids less than 0."; - - pointerProperties[0].id = MAX_POINTER_ID + 1; - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject motion events with pointer ids greater than MAX_POINTER_ID."; - - // Rejects motion events with duplicate pointer ids. - pointerProperties[0].id = 1; - pointerProperties[1].id = 1; - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 2, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) - << "Should reject motion events with duplicate pointer ids."; -} - -} // namespace android diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp deleted file mode 100644 index f068732..0000000 --- a/services/input/tests/InputReader_test.cpp +++ /dev/null @@ -1,5099 +0,0 @@ -/* - * Copyright (C) 2010 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 "../InputReader.h" - -#include <utils/List.h> -#include <gtest/gtest.h> -#include <math.h> - -namespace android { - -// An arbitrary time value. -static const nsecs_t ARBITRARY_TIME = 1234; - -// Arbitrary display properties. -static const int32_t DISPLAY_ID = 0; -static const int32_t DISPLAY_WIDTH = 480; -static const int32_t DISPLAY_HEIGHT = 800; - -// Error tolerance for floating point assertions. -static const float EPSILON = 0.001f; - -template<typename T> -static inline T min(T a, T b) { - return a < b ? a : b; -} - -static inline float avg(float x, float y) { - return (x + y) / 2; -} - - -// --- FakePointerController --- - -class FakePointerController : public PointerControllerInterface { - bool mHaveBounds; - float mMinX, mMinY, mMaxX, mMaxY; - float mX, mY; - int32_t mButtonState; - -protected: - virtual ~FakePointerController() { } - -public: - FakePointerController() : - mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0), - mButtonState(0) { - } - - void setBounds(float minX, float minY, float maxX, float maxY) { - mHaveBounds = true; - mMinX = minX; - mMinY = minY; - mMaxX = maxX; - mMaxY = maxY; - } - - virtual void setPosition(float x, float y) { - mX = x; - mY = y; - } - - virtual void setButtonState(int32_t buttonState) { - mButtonState = buttonState; - } - - virtual int32_t getButtonState() const { - return mButtonState; - } - - virtual void getPosition(float* outX, float* outY) const { - *outX = mX; - *outY = mY; - } - -private: - virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const { - *outMinX = mMinX; - *outMinY = mMinY; - *outMaxX = mMaxX; - *outMaxY = mMaxY; - return mHaveBounds; - } - - virtual void move(float deltaX, float deltaY) { - mX += deltaX; - if (mX < mMinX) mX = mMinX; - if (mX > mMaxX) mX = mMaxX; - mY += deltaY; - if (mY < mMinY) mY = mMinY; - if (mY > mMaxY) mY = mMaxY; - } - - virtual void fade(Transition transition) { - } - - virtual void unfade(Transition transition) { - } - - virtual void setPresentation(Presentation presentation) { - } - - virtual void setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { - } - - virtual void clearSpots() { - } -}; - - -// --- FakeInputReaderPolicy --- - -class FakeInputReaderPolicy : public InputReaderPolicyInterface { - InputReaderConfiguration mConfig; - KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers; - Vector<InputDeviceInfo> mInputDevices; - -protected: - virtual ~FakeInputReaderPolicy() { } - -public: - FakeInputReaderPolicy() { - } - - void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) { - // Set the size of both the internal and external display at the same time. - bool isRotated = (orientation == DISPLAY_ORIENTATION_90 - || orientation == DISPLAY_ORIENTATION_270); - DisplayViewport v; - v.displayId = displayId; - v.orientation = orientation; - v.logicalLeft = 0; - v.logicalTop = 0; - v.logicalRight = isRotated ? height : width; - v.logicalBottom = isRotated ? width : height; - v.physicalLeft = 0; - v.physicalTop = 0; - v.physicalRight = isRotated ? height : width; - v.physicalBottom = isRotated ? width : height; - v.deviceWidth = isRotated ? height : width; - v.deviceHeight = isRotated ? width : height; - mConfig.setDisplayInfo(false /*external*/, v); - mConfig.setDisplayInfo(true /*external*/, v); - } - - void addExcludedDeviceName(const String8& deviceName) { - mConfig.excludedDeviceNames.push(deviceName); - } - - void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) { - mPointerControllers.add(deviceId, controller); - } - - const InputReaderConfiguration* getReaderConfiguration() const { - return &mConfig; - } - - const Vector<InputDeviceInfo>& getInputDevices() const { - return mInputDevices; - } - -private: - virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) { - *outConfig = mConfig; - } - - virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) { - return mPointerControllers.valueFor(deviceId); - } - - virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) { - mInputDevices = inputDevices; - } - - virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) { - return NULL; - } - - virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) { - return String8::empty(); - } -}; - - -// --- FakeInputListener --- - -class FakeInputListener : public InputListenerInterface { -private: - List<NotifyConfigurationChangedArgs> mNotifyConfigurationChangedArgsQueue; - List<NotifyDeviceResetArgs> mNotifyDeviceResetArgsQueue; - List<NotifyKeyArgs> mNotifyKeyArgsQueue; - List<NotifyMotionArgs> mNotifyMotionArgsQueue; - List<NotifySwitchArgs> mNotifySwitchArgsQueue; - -protected: - virtual ~FakeInputListener() { } - -public: - FakeInputListener() { - } - - void assertNotifyConfigurationChangedWasCalled( - NotifyConfigurationChangedArgs* outEventArgs = NULL) { - ASSERT_FALSE(mNotifyConfigurationChangedArgsQueue.empty()) - << "Expected notifyConfigurationChanged() to have been called."; - if (outEventArgs) { - *outEventArgs = *mNotifyConfigurationChangedArgsQueue.begin(); - } - mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin()); - } - - void assertNotifyDeviceResetWasCalled( - NotifyDeviceResetArgs* outEventArgs = NULL) { - ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty()) - << "Expected notifyDeviceReset() to have been called."; - if (outEventArgs) { - *outEventArgs = *mNotifyDeviceResetArgsQueue.begin(); - } - mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin()); - } - - void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) { - ASSERT_FALSE(mNotifyKeyArgsQueue.empty()) - << "Expected notifyKey() to have been called."; - if (outEventArgs) { - *outEventArgs = *mNotifyKeyArgsQueue.begin(); - } - mNotifyKeyArgsQueue.erase(mNotifyKeyArgsQueue.begin()); - } - - void assertNotifyKeyWasNotCalled() { - ASSERT_TRUE(mNotifyKeyArgsQueue.empty()) - << "Expected notifyKey() to not have been called."; - } - - void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = NULL) { - ASSERT_FALSE(mNotifyMotionArgsQueue.empty()) - << "Expected notifyMotion() to have been called."; - if (outEventArgs) { - *outEventArgs = *mNotifyMotionArgsQueue.begin(); - } - mNotifyMotionArgsQueue.erase(mNotifyMotionArgsQueue.begin()); - } - - void assertNotifyMotionWasNotCalled() { - ASSERT_TRUE(mNotifyMotionArgsQueue.empty()) - << "Expected notifyMotion() to not have been called."; - } - - void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = NULL) { - ASSERT_FALSE(mNotifySwitchArgsQueue.empty()) - << "Expected notifySwitch() to have been called."; - if (outEventArgs) { - *outEventArgs = *mNotifySwitchArgsQueue.begin(); - } - mNotifySwitchArgsQueue.erase(mNotifySwitchArgsQueue.begin()); - } - -private: - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { - mNotifyConfigurationChangedArgsQueue.push_back(*args); - } - - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) { - mNotifyDeviceResetArgsQueue.push_back(*args); - } - - virtual void notifyKey(const NotifyKeyArgs* args) { - mNotifyKeyArgsQueue.push_back(*args); - } - - virtual void notifyMotion(const NotifyMotionArgs* args) { - mNotifyMotionArgsQueue.push_back(*args); - } - - virtual void notifySwitch(const NotifySwitchArgs* args) { - mNotifySwitchArgsQueue.push_back(*args); - } -}; - - -// --- FakeEventHub --- - -class FakeEventHub : public EventHubInterface { - struct KeyInfo { - int32_t keyCode; - uint32_t flags; - }; - - struct Device { - InputDeviceIdentifier identifier; - uint32_t classes; - PropertyMap configuration; - KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes; - KeyedVector<int, bool> relativeAxes; - KeyedVector<int32_t, int32_t> keyCodeStates; - KeyedVector<int32_t, int32_t> scanCodeStates; - KeyedVector<int32_t, int32_t> switchStates; - KeyedVector<int32_t, int32_t> absoluteAxisValue; - KeyedVector<int32_t, KeyInfo> keysByScanCode; - KeyedVector<int32_t, KeyInfo> keysByUsageCode; - KeyedVector<int32_t, bool> leds; - Vector<VirtualKeyDefinition> virtualKeys; - - Device(uint32_t classes) : - classes(classes) { - } - }; - - KeyedVector<int32_t, Device*> mDevices; - Vector<String8> mExcludedDevices; - List<RawEvent> mEvents; - -protected: - virtual ~FakeEventHub() { - for (size_t i = 0; i < mDevices.size(); i++) { - delete mDevices.valueAt(i); - } - } - -public: - FakeEventHub() { } - - void addDevice(int32_t deviceId, const String8& name, uint32_t classes) { - Device* device = new Device(classes); - device->identifier.name = name; - mDevices.add(deviceId, device); - - enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0); - } - - void removeDevice(int32_t deviceId) { - delete mDevices.valueFor(deviceId); - mDevices.removeItem(deviceId); - - enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0); - } - - void finishDeviceScan() { - enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0); - } - - void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) { - Device* device = getDevice(deviceId); - device->configuration.addProperty(key, value); - } - - void addConfigurationMap(int32_t deviceId, const PropertyMap* configuration) { - Device* device = getDevice(deviceId); - device->configuration.addAll(configuration); - } - - void addAbsoluteAxis(int32_t deviceId, int axis, - int32_t minValue, int32_t maxValue, int flat, int fuzz, int resolution = 0) { - Device* device = getDevice(deviceId); - - RawAbsoluteAxisInfo info; - info.valid = true; - info.minValue = minValue; - info.maxValue = maxValue; - info.flat = flat; - info.fuzz = fuzz; - info.resolution = resolution; - device->absoluteAxes.add(axis, info); - } - - void addRelativeAxis(int32_t deviceId, int32_t axis) { - Device* device = getDevice(deviceId); - device->relativeAxes.add(axis, true); - } - - void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) { - Device* device = getDevice(deviceId); - device->keyCodeStates.replaceValueFor(keyCode, state); - } - - void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) { - Device* device = getDevice(deviceId); - device->scanCodeStates.replaceValueFor(scanCode, state); - } - - void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) { - Device* device = getDevice(deviceId); - device->switchStates.replaceValueFor(switchCode, state); - } - - void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) { - Device* device = getDevice(deviceId); - device->absoluteAxisValue.replaceValueFor(axis, value); - } - - void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t keyCode, uint32_t flags) { - Device* device = getDevice(deviceId); - KeyInfo info; - info.keyCode = keyCode; - info.flags = flags; - if (scanCode) { - device->keysByScanCode.add(scanCode, info); - } - if (usageCode) { - device->keysByUsageCode.add(usageCode, info); - } - } - - void addLed(int32_t deviceId, int32_t led, bool initialState) { - Device* device = getDevice(deviceId); - device->leds.add(led, initialState); - } - - bool getLedState(int32_t deviceId, int32_t led) { - Device* device = getDevice(deviceId); - return device->leds.valueFor(led); - } - - Vector<String8>& getExcludedDevices() { - return mExcludedDevices; - } - - void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) { - Device* device = getDevice(deviceId); - device->virtualKeys.push(definition); - } - - void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type, - int32_t code, int32_t value) { - RawEvent event; - event.when = when; - event.deviceId = deviceId; - event.type = type; - event.code = code; - event.value = value; - mEvents.push_back(event); - - if (type == EV_ABS) { - setAbsoluteAxisValue(deviceId, code, value); - } - } - - void assertQueueIsEmpty() { - ASSERT_EQ(size_t(0), mEvents.size()) - << "Expected the event queue to be empty (fully consumed)."; - } - -private: - Device* getDevice(int32_t deviceId) const { - ssize_t index = mDevices.indexOfKey(deviceId); - return index >= 0 ? mDevices.valueAt(index) : NULL; - } - - virtual uint32_t getDeviceClasses(int32_t deviceId) const { - Device* device = getDevice(deviceId); - return device ? device->classes : 0; - } - - virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const { - Device* device = getDevice(deviceId); - return device ? device->identifier : InputDeviceIdentifier(); - } - - virtual int32_t getDeviceControllerNumber(int32_t deviceId) const { - return 0; - } - - virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { - Device* device = getDevice(deviceId); - if (device) { - *outConfiguration = device->configuration; - } - } - - virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->absoluteAxes.indexOfKey(axis); - if (index >= 0) { - *outAxisInfo = device->absoluteAxes.valueAt(index); - return OK; - } - } - outAxisInfo->clear(); - return -1; - } - - virtual bool hasRelativeAxis(int32_t deviceId, int axis) const { - Device* device = getDevice(deviceId); - if (device) { - return device->relativeAxes.indexOfKey(axis) >= 0; - } - return false; - } - - virtual bool hasInputProperty(int32_t deviceId, int property) const { - return false; - } - - virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t* outKeycode, uint32_t* outFlags) const { - Device* device = getDevice(deviceId); - if (device) { - const KeyInfo* key = getKey(device, scanCode, usageCode); - if (key) { - if (outKeycode) { - *outKeycode = key->keyCode; - } - if (outFlags) { - *outFlags = key->flags; - } - return OK; - } - } - return NAME_NOT_FOUND; - } - - const KeyInfo* getKey(Device* device, int32_t scanCode, int32_t usageCode) const { - if (usageCode) { - ssize_t index = device->keysByUsageCode.indexOfKey(usageCode); - if (index >= 0) { - return &device->keysByUsageCode.valueAt(index); - } - } - if (scanCode) { - ssize_t index = device->keysByScanCode.indexOfKey(scanCode); - if (index >= 0) { - return &device->keysByScanCode.valueAt(index); - } - } - return NULL; - } - - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, - AxisInfo* outAxisInfo) const { - return NAME_NOT_FOUND; - } - - virtual void setExcludedDevices(const Vector<String8>& devices) { - mExcludedDevices = devices; - } - - virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { - if (mEvents.empty()) { - return 0; - } - - *buffer = *mEvents.begin(); - mEvents.erase(mEvents.begin()); - return 1; - } - - virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->scanCodeStates.indexOfKey(scanCode); - if (index >= 0) { - return device->scanCodeStates.valueAt(index); - } - } - return AKEY_STATE_UNKNOWN; - } - - virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->keyCodeStates.indexOfKey(keyCode); - if (index >= 0) { - return device->keyCodeStates.valueAt(index); - } - } - return AKEY_STATE_UNKNOWN; - } - - virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->switchStates.indexOfKey(sw); - if (index >= 0) { - return device->switchStates.valueAt(index); - } - } - return AKEY_STATE_UNKNOWN; - } - - virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, - int32_t* outValue) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->absoluteAxisValue.indexOfKey(axis); - if (index >= 0) { - *outValue = device->absoluteAxisValue.valueAt(index); - return OK; - } - } - *outValue = 0; - return -1; - } - - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags) const { - bool result = false; - Device* device = getDevice(deviceId); - if (device) { - for (size_t i = 0; i < numCodes; i++) { - for (size_t j = 0; j < device->keysByScanCode.size(); j++) { - if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) { - outFlags[i] = 1; - result = true; - } - } - for (size_t j = 0; j < device->keysByUsageCode.size(); j++) { - if (keyCodes[i] == device->keysByUsageCode.valueAt(j).keyCode) { - outFlags[i] = 1; - result = true; - } - } - } - } - return result; - } - - virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->keysByScanCode.indexOfKey(scanCode); - return index >= 0; - } - return false; - } - - virtual bool hasLed(int32_t deviceId, int32_t led) const { - Device* device = getDevice(deviceId); - return device && device->leds.indexOfKey(led) >= 0; - } - - virtual void setLedState(int32_t deviceId, int32_t led, bool on) { - Device* device = getDevice(deviceId); - if (device) { - ssize_t index = device->leds.indexOfKey(led); - if (index >= 0) { - device->leds.replaceValueAt(led, on); - } else { - ADD_FAILURE() - << "Attempted to set the state of an LED that the EventHub declared " - "was not present. led=" << led; - } - } - } - - virtual void getVirtualKeyDefinitions(int32_t deviceId, - Vector<VirtualKeyDefinition>& outVirtualKeys) const { - outVirtualKeys.clear(); - - Device* device = getDevice(deviceId); - if (device) { - outVirtualKeys.appendVector(device->virtualKeys); - } - } - - virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const { - return NULL; - } - - virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) { - return false; - } - - virtual void vibrate(int32_t deviceId, nsecs_t duration) { - } - - virtual void cancelVibrate(int32_t deviceId) { - } - - virtual bool isExternal(int32_t deviceId) const { - return false; - } - - virtual void dump(String8& dump) { - } - - virtual void monitor() { - } - - virtual void requestReopenDevices() { - } - - virtual void wake() { - } -}; - - -// --- FakeInputReaderContext --- - -class FakeInputReaderContext : public InputReaderContext { - sp<EventHubInterface> mEventHub; - sp<InputReaderPolicyInterface> mPolicy; - sp<InputListenerInterface> mListener; - int32_t mGlobalMetaState; - bool mUpdateGlobalMetaStateWasCalled; - int32_t mGeneration; - -public: - FakeInputReaderContext(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener) : - mEventHub(eventHub), mPolicy(policy), mListener(listener), - mGlobalMetaState(0) { - } - - virtual ~FakeInputReaderContext() { } - - void assertUpdateGlobalMetaStateWasCalled() { - ASSERT_TRUE(mUpdateGlobalMetaStateWasCalled) - << "Expected updateGlobalMetaState() to have been called."; - mUpdateGlobalMetaStateWasCalled = false; - } - - void setGlobalMetaState(int32_t state) { - mGlobalMetaState = state; - } - -private: - virtual void updateGlobalMetaState() { - mUpdateGlobalMetaStateWasCalled = true; - } - - virtual int32_t getGlobalMetaState() { - return mGlobalMetaState; - } - - virtual EventHubInterface* getEventHub() { - return mEventHub.get(); - } - - virtual InputReaderPolicyInterface* getPolicy() { - return mPolicy.get(); - } - - virtual InputListenerInterface* getListener() { - return mListener.get(); - } - - virtual void disableVirtualKeysUntil(nsecs_t time) { - } - - virtual bool shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) { - return false; - } - - virtual void fadePointer() { - } - - virtual void requestTimeoutAtTime(nsecs_t when) { - } - - virtual int32_t bumpGeneration() { - return ++mGeneration; - } -}; - - -// --- FakeInputMapper --- - -class FakeInputMapper : public InputMapper { - uint32_t mSources; - int32_t mKeyboardType; - int32_t mMetaState; - KeyedVector<int32_t, int32_t> mKeyCodeStates; - KeyedVector<int32_t, int32_t> mScanCodeStates; - KeyedVector<int32_t, int32_t> mSwitchStates; - Vector<int32_t> mSupportedKeyCodes; - RawEvent mLastEvent; - - bool mConfigureWasCalled; - bool mResetWasCalled; - bool mProcessWasCalled; - -public: - FakeInputMapper(InputDevice* device, uint32_t sources) : - InputMapper(device), - mSources(sources), mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE), - mMetaState(0), - mConfigureWasCalled(false), mResetWasCalled(false), mProcessWasCalled(false) { - } - - virtual ~FakeInputMapper() { } - - void setKeyboardType(int32_t keyboardType) { - mKeyboardType = keyboardType; - } - - void setMetaState(int32_t metaState) { - mMetaState = metaState; - } - - void assertConfigureWasCalled() { - ASSERT_TRUE(mConfigureWasCalled) - << "Expected configure() to have been called."; - mConfigureWasCalled = false; - } - - void assertResetWasCalled() { - ASSERT_TRUE(mResetWasCalled) - << "Expected reset() to have been called."; - mResetWasCalled = false; - } - - void assertProcessWasCalled(RawEvent* outLastEvent = NULL) { - ASSERT_TRUE(mProcessWasCalled) - << "Expected process() to have been called."; - if (outLastEvent) { - *outLastEvent = mLastEvent; - } - mProcessWasCalled = false; - } - - void setKeyCodeState(int32_t keyCode, int32_t state) { - mKeyCodeStates.replaceValueFor(keyCode, state); - } - - void setScanCodeState(int32_t scanCode, int32_t state) { - mScanCodeStates.replaceValueFor(scanCode, state); - } - - void setSwitchState(int32_t switchCode, int32_t state) { - mSwitchStates.replaceValueFor(switchCode, state); - } - - void addSupportedKeyCode(int32_t keyCode) { - mSupportedKeyCodes.add(keyCode); - } - -private: - virtual uint32_t getSources() { - return mSources; - } - - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) { - InputMapper::populateDeviceInfo(deviceInfo); - - if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) { - deviceInfo->setKeyboardType(mKeyboardType); - } - } - - virtual void configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - mConfigureWasCalled = true; - } - - virtual void reset(nsecs_t when) { - mResetWasCalled = true; - } - - virtual void process(const RawEvent* rawEvent) { - mLastEvent = *rawEvent; - mProcessWasCalled = true; - } - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - ssize_t index = mKeyCodeStates.indexOfKey(keyCode); - return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; - } - - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - ssize_t index = mScanCodeStates.indexOfKey(scanCode); - return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; - } - - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode) { - ssize_t index = mSwitchStates.indexOfKey(switchCode); - return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN; - } - - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - for (size_t i = 0; i < numCodes; i++) { - for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) { - if (keyCodes[i] == mSupportedKeyCodes[j]) { - outFlags[i] = 1; - result = true; - } - } - } - return result; - } - - virtual int32_t getMetaState() { - return mMetaState; - } - - virtual void fadePointer() { - } -}; - - -// --- InstrumentedInputReader --- - -class InstrumentedInputReader : public InputReader { - InputDevice* mNextDevice; - -public: - InstrumentedInputReader(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener) : - InputReader(eventHub, policy, listener), - mNextDevice(NULL) { - } - - virtual ~InstrumentedInputReader() { - if (mNextDevice) { - delete mNextDevice; - } - } - - void setNextDevice(InputDevice* device) { - mNextDevice = device; - } - - InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const String8& name, - uint32_t classes) { - InputDeviceIdentifier identifier; - identifier.name = name; - int32_t generation = deviceId + 1; - return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier, - classes); - } - -protected: - virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, uint32_t classes) { - if (mNextDevice) { - InputDevice* device = mNextDevice; - mNextDevice = NULL; - return device; - } - return InputReader::createDeviceLocked(deviceId, controllerNumber, identifier, classes); - } - - friend class InputReaderTest; -}; - - -// --- InputReaderTest --- - -class InputReaderTest : public testing::Test { -protected: - sp<FakeInputListener> mFakeListener; - sp<FakeInputReaderPolicy> mFakePolicy; - sp<FakeEventHub> mFakeEventHub; - sp<InstrumentedInputReader> mReader; - - virtual void SetUp() { - mFakeEventHub = new FakeEventHub(); - mFakePolicy = new FakeInputReaderPolicy(); - mFakeListener = new FakeInputListener(); - - mReader = new InstrumentedInputReader(mFakeEventHub, mFakePolicy, mFakeListener); - } - - virtual void TearDown() { - mReader.clear(); - - mFakeListener.clear(); - mFakePolicy.clear(); - mFakeEventHub.clear(); - } - - void addDevice(int32_t deviceId, const String8& name, uint32_t classes, - const PropertyMap* configuration) { - mFakeEventHub->addDevice(deviceId, name, classes); - - if (configuration) { - mFakeEventHub->addConfigurationMap(deviceId, configuration); - } - mFakeEventHub->finishDeviceScan(); - mReader->loopOnce(); - mReader->loopOnce(); - mFakeEventHub->assertQueueIsEmpty(); - } - - FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber, - const String8& name, uint32_t classes, uint32_t sources, - const PropertyMap* configuration) { - InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes); - FakeInputMapper* mapper = new FakeInputMapper(device, sources); - device->addMapper(mapper); - mReader->setNextDevice(device); - addDevice(deviceId, name, classes, configuration); - return mapper; - } -}; - -TEST_F(InputReaderTest, GetInputDevices) { - ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"), - INPUT_DEVICE_CLASS_KEYBOARD, NULL)); - ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("ignored"), - 0, NULL)); // no classes so device will be ignored - - Vector<InputDeviceInfo> inputDevices; - mReader->getInputDevices(inputDevices); - - ASSERT_EQ(1U, inputDevices.size()); - ASSERT_EQ(1, inputDevices[0].getId()); - ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string()); - ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType()); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources()); - ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size()); - - // Should also have received a notification describing the new input devices. - inputDevices = mFakePolicy->getInputDevices(); - ASSERT_EQ(1U, inputDevices.size()); - ASSERT_EQ(1, inputDevices[0].getId()); - ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.string()); - ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType()); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources()); - ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size()); -} - -TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = NULL; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); - mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0, - AINPUT_SOURCE_ANY, AKEYCODE_A)) - << "Should return unknown when the device id is >= 0 but unknown."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(1, - AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown when the device id is valid but the sources are not supported by the device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(-1, - AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(-1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; -} - -TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = NULL; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); - mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN); - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0, - AINPUT_SOURCE_ANY, KEY_A)) - << "Should return unknown when the device id is >= 0 but unknown."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(1, - AINPUT_SOURCE_TRACKBALL, KEY_A)) - << "Should return unknown when the device id is valid but the sources are not supported by the device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(-1, - AINPUT_SOURCE_TRACKBALL, KEY_A)) - << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(-1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) - << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; -} - -TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = NULL; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); - mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN); - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0, - AINPUT_SOURCE_ANY, SW_LID)) - << "Should return unknown when the device id is >= 0 but unknown."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(1, - AINPUT_SOURCE_TRACKBALL, SW_LID)) - << "Should return unknown when the device id is valid but the sources are not supported by the device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(-1, - AINPUT_SOURCE_TRACKBALL, SW_LID)) - << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; - - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(-1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) - << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; -} - -TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = NULL; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); - mapper->addSupportedKeyCode(AKEYCODE_A); - mapper->addSupportedKeyCode(AKEYCODE_B); - - const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; - uint8_t flags[4] = { 0, 0, 0, 1 }; - - ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, 4, keyCodes, flags)) - << "Should return false when device id is >= 0 but unknown."; - ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); - - flags[3] = 1; - ASSERT_FALSE(mReader->hasKeys(1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return false when device id is valid but the sources are not supported by the device."; - ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); - - flags[3] = 1; - ASSERT_TRUE(mReader->hasKeys(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; - ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); - - flags[3] = 1; - ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return false when the device id is < 0 but the sources are not supported by any device."; - ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); - - flags[3] = 1; - ASSERT_TRUE(mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; - ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); -} - -TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) { - addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD, NULL); - - NotifyConfigurationChangedArgs args; - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); -} - -TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { - FakeInputMapper* mapper = NULL; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); - - mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1); - mReader->loopOnce(); - ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty()); - - RawEvent event; - ASSERT_NO_FATAL_FAILURE(mapper->assertProcessWasCalled(&event)); - ASSERT_EQ(0, event.when); - ASSERT_EQ(1, event.deviceId); - ASSERT_EQ(EV_KEY, event.type); - ASSERT_EQ(KEY_A, event.code); - ASSERT_EQ(1, event.value); -} - - -// --- InputDeviceTest --- - -class InputDeviceTest : public testing::Test { -protected: - static const char* DEVICE_NAME; - static const int32_t DEVICE_ID; - static const int32_t DEVICE_GENERATION; - static const int32_t DEVICE_CONTROLLER_NUMBER; - static const uint32_t DEVICE_CLASSES; - - sp<FakeEventHub> mFakeEventHub; - sp<FakeInputReaderPolicy> mFakePolicy; - sp<FakeInputListener> mFakeListener; - FakeInputReaderContext* mFakeContext; - - InputDevice* mDevice; - - virtual void SetUp() { - mFakeEventHub = new FakeEventHub(); - mFakePolicy = new FakeInputReaderPolicy(); - mFakeListener = new FakeInputListener(); - mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener); - - mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); - InputDeviceIdentifier identifier; - identifier.name = DEVICE_NAME; - mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, - DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); - } - - virtual void TearDown() { - delete mDevice; - - delete mFakeContext; - mFakeListener.clear(); - mFakePolicy.clear(); - mFakeEventHub.clear(); - } -}; - -const char* InputDeviceTest::DEVICE_NAME = "device"; -const int32_t InputDeviceTest::DEVICE_ID = 1; -const int32_t InputDeviceTest::DEVICE_GENERATION = 2; -const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0; -const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD - | INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK; - -TEST_F(InputDeviceTest, ImmutableProperties) { - ASSERT_EQ(DEVICE_ID, mDevice->getId()); - ASSERT_STREQ(DEVICE_NAME, mDevice->getName()); - ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses()); -} - -TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { - // Configuration. - InputReaderConfiguration config; - mDevice->configure(ARBITRARY_TIME, &config, 0); - - // Reset. - mDevice->reset(ARBITRARY_TIME); - - NotifyDeviceResetArgs resetArgs; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); - ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); - - // Metadata. - ASSERT_TRUE(mDevice->isIgnored()); - ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mDevice->getSources()); - - InputDeviceInfo info; - mDevice->getDeviceInfo(&info); - ASSERT_EQ(DEVICE_ID, info.getId()); - ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string()); - ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NONE, info.getKeyboardType()); - ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, info.getSources()); - - // State queries. - ASSERT_EQ(0, mDevice->getMetaState()); - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, 0)) - << "Ignored device should return unknown key code state."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 0)) - << "Ignored device should return unknown scan code state."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 0)) - << "Ignored device should return unknown switch state."; - - const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; - uint8_t flags[2] = { 0, 1 }; - ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 2, keyCodes, flags)) - << "Ignored device should never mark any key codes."; - ASSERT_EQ(0, flags[0]) << "Flag for unsupported key should be unchanged."; - ASSERT_EQ(1, flags[1]) << "Flag for unsupported key should be unchanged."; -} - -TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) { - // Configuration. - mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value")); - - FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD); - mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC); - mapper1->setMetaState(AMETA_ALT_ON); - mapper1->addSupportedKeyCode(AKEYCODE_A); - mapper1->addSupportedKeyCode(AKEYCODE_B); - mapper1->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); - mapper1->setKeyCodeState(AKEYCODE_B, AKEY_STATE_UP); - mapper1->setScanCodeState(2, AKEY_STATE_DOWN); - mapper1->setScanCodeState(3, AKEY_STATE_UP); - mapper1->setSwitchState(4, AKEY_STATE_DOWN); - mDevice->addMapper(mapper1); - - FakeInputMapper* mapper2 = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN); - mapper2->setMetaState(AMETA_SHIFT_ON); - mDevice->addMapper(mapper2); - - InputReaderConfiguration config; - mDevice->configure(ARBITRARY_TIME, &config, 0); - - String8 propertyValue; - ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue)) - << "Device should have read configuration during configuration phase."; - ASSERT_STREQ("value", propertyValue.string()); - - ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper2->assertConfigureWasCalled()); - - // Reset - mDevice->reset(ARBITRARY_TIME); - ASSERT_NO_FATAL_FAILURE(mapper1->assertResetWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper2->assertResetWasCalled()); - - NotifyDeviceResetArgs resetArgs; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); - ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); - - // Metadata. - ASSERT_FALSE(mDevice->isIgnored()); - ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), mDevice->getSources()); - - InputDeviceInfo info; - mDevice->getDeviceInfo(&info); - ASSERT_EQ(DEVICE_ID, info.getId()); - ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.string()); - ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, info.getKeyboardType()); - ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), info.getSources()); - - // State queries. - ASSERT_EQ(AMETA_ALT_ON | AMETA_SHIFT_ON, mDevice->getMetaState()) - << "Should query mappers and combine meta states."; - - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown key code state when source not supported."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown scan code state when source not supported."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown switch state when source not supported."; - - ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, AKEYCODE_A)) - << "Should query mapper when source is supported."; - ASSERT_EQ(AKEY_STATE_UP, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 3)) - << "Should query mapper when source is supported."; - ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 4)) - << "Should query mapper when source is supported."; - - const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; - uint8_t flags[4] = { 0, 0, 0, 1 }; - ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should do nothing when source is unsupported."; - ASSERT_EQ(0, flags[0]) << "Flag should be unchanged when source is unsupported."; - ASSERT_EQ(0, flags[1]) << "Flag should be unchanged when source is unsupported."; - ASSERT_EQ(0, flags[2]) << "Flag should be unchanged when source is unsupported."; - ASSERT_EQ(1, flags[3]) << "Flag should be unchanged when source is unsupported."; - - ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 4, keyCodes, flags)) - << "Should query mapper when source is supported."; - ASSERT_EQ(1, flags[0]) << "Flag for supported key should be set."; - ASSERT_EQ(1, flags[1]) << "Flag for supported key should be set."; - ASSERT_EQ(0, flags[2]) << "Flag for unsupported key should be unchanged."; - ASSERT_EQ(1, flags[3]) << "Flag for unsupported key should be unchanged."; - - // Event handling. - RawEvent event; - mDevice->process(&event, 1); - - ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled()); -} - - -// --- InputMapperTest --- - -class InputMapperTest : public testing::Test { -protected: - static const char* DEVICE_NAME; - static const int32_t DEVICE_ID; - static const int32_t DEVICE_GENERATION; - static const int32_t DEVICE_CONTROLLER_NUMBER; - static const uint32_t DEVICE_CLASSES; - - sp<FakeEventHub> mFakeEventHub; - sp<FakeInputReaderPolicy> mFakePolicy; - sp<FakeInputListener> mFakeListener; - FakeInputReaderContext* mFakeContext; - InputDevice* mDevice; - - virtual void SetUp() { - mFakeEventHub = new FakeEventHub(); - mFakePolicy = new FakeInputReaderPolicy(); - mFakeListener = new FakeInputListener(); - mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener); - InputDeviceIdentifier identifier; - identifier.name = DEVICE_NAME; - mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, - DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); - - mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); - } - - virtual void TearDown() { - delete mDevice; - delete mFakeContext; - mFakeListener.clear(); - mFakePolicy.clear(); - mFakeEventHub.clear(); - } - - void addConfigurationProperty(const char* key, const char* value) { - mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8(key), String8(value)); - } - - void addMapperAndConfigure(InputMapper* mapper) { - mDevice->addMapper(mapper); - mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0); - mDevice->reset(ARBITRARY_TIME); - } - - void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, - int32_t orientation) { - mFakePolicy->setDisplayInfo(displayId, width, height, orientation); - mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), - InputReaderConfiguration::CHANGE_DISPLAY_INFO); - } - - static void process(InputMapper* mapper, nsecs_t when, int32_t deviceId, int32_t type, - int32_t code, int32_t value) { - RawEvent event; - event.when = when; - event.deviceId = deviceId; - event.type = type; - event.code = code; - event.value = value; - mapper->process(&event); - } - - static void assertMotionRange(const InputDeviceInfo& info, - int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) { - const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source); - ASSERT_TRUE(range != NULL) << "Axis: " << axis << " Source: " << source; - ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source; - ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source; - ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source; - ASSERT_NEAR(max, range->max, EPSILON) << "Axis: " << axis << " Source: " << source; - ASSERT_NEAR(flat, range->flat, EPSILON) << "Axis: " << axis << " Source: " << source; - ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source; - } - - static void assertPointerCoords(const PointerCoords& coords, - float x, float y, float pressure, float size, - float touchMajor, float touchMinor, float toolMajor, float toolMinor, - float orientation, float distance) { - ASSERT_NEAR(x, coords.getAxisValue(AMOTION_EVENT_AXIS_X), 1); - ASSERT_NEAR(y, coords.getAxisValue(AMOTION_EVENT_AXIS_Y), 1); - ASSERT_NEAR(pressure, coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), EPSILON); - ASSERT_NEAR(size, coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE), EPSILON); - ASSERT_NEAR(touchMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), 1); - ASSERT_NEAR(touchMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), 1); - ASSERT_NEAR(toolMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), 1); - ASSERT_NEAR(toolMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), 1); - ASSERT_NEAR(orientation, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), EPSILON); - ASSERT_NEAR(distance, coords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), EPSILON); - } - - static void assertPosition(const sp<FakePointerController>& controller, float x, float y) { - float actualX, actualY; - controller->getPosition(&actualX, &actualY); - ASSERT_NEAR(x, actualX, 1); - ASSERT_NEAR(y, actualY, 1); - } -}; - -const char* InputMapperTest::DEVICE_NAME = "device"; -const int32_t InputMapperTest::DEVICE_ID = 1; -const int32_t InputMapperTest::DEVICE_GENERATION = 2; -const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0; -const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests - - -// --- SwitchInputMapperTest --- - -class SwitchInputMapperTest : public InputMapperTest { -protected: -}; - -TEST_F(SwitchInputMapperTest, GetSources) { - SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); - addMapperAndConfigure(mapper); - - ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mapper->getSources()); -} - -TEST_F(SwitchInputMapperTest, GetSwitchState) { - SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); - addMapperAndConfigure(mapper); - - mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 1); - ASSERT_EQ(1, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); - - mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 0); - ASSERT_EQ(0, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); -} - -TEST_F(SwitchInputMapperTest, Process) { - SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); - addMapperAndConfigure(mapper); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_LID, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_JACK_PHYSICAL_INSERT, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_HEADPHONE_INSERT, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - - NotifySwitchArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySwitchWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ((1 << SW_LID) | (1 << SW_JACK_PHYSICAL_INSERT), args.switchValues); - ASSERT_EQ((1 << SW_LID) | (1 << SW_JACK_PHYSICAL_INSERT) | (1 << SW_HEADPHONE_INSERT), - args.switchMask); - ASSERT_EQ(uint32_t(0), args.policyFlags); -} - - -// --- KeyboardInputMapperTest --- - -class KeyboardInputMapperTest : public InputMapperTest { -protected: - void testDPadKeyRotation(KeyboardInputMapper* mapper, - int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode); -}; - -void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, - int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode) { - NotifyKeyArgs args; - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 1); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(originalScanCode, args.scanCode); - ASSERT_EQ(rotatedKeyCode, args.keyCode); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(originalScanCode, args.scanCode); - ASSERT_EQ(rotatedKeyCode, args.keyCode); -} - - -TEST_F(KeyboardInputMapperTest, GetSources) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper->getSources()); -} - -TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { - const int32_t USAGE_A = 0x070004; - const int32_t USAGE_UNKNOWN = 0x07ffff; - mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); - mFakeEventHub->addKey(DEVICE_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE); - - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - // Key down by scan code. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_HOME, 1); - NotifyKeyArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(AKEYCODE_HOME, args.keyCode); - ASSERT_EQ(KEY_HOME, args.scanCode); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Key up by scan code. - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, - EV_KEY, KEY_HOME, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEYCODE_HOME, args.keyCode); - ASSERT_EQ(KEY_HOME, args.scanCode); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Key down by usage code. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_MSC, MSC_SCAN, USAGE_A); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, 0, 1); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(AKEYCODE_A, args.keyCode); - ASSERT_EQ(0, args.scanCode); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Key up by usage code. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_MSC, MSC_SCAN, USAGE_A); - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, - EV_KEY, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEYCODE_A, args.keyCode); - ASSERT_EQ(0, args.scanCode); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Key down with unknown scan code or usage code. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_MSC, MSC_SCAN, USAGE_UNKNOWN); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_UNKNOWN, 1); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(0, args.keyCode); - ASSERT_EQ(KEY_UNKNOWN, args.scanCode); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(0U, args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Key up with unknown scan code or usage code. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_MSC, MSC_SCAN, USAGE_UNKNOWN); - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, - EV_KEY, KEY_UNKNOWN, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(0, args.keyCode); - ASSERT_EQ(KEY_UNKNOWN, args.scanCode); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(0U, args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); -} - -TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { - mFakeEventHub->addKey(DEVICE_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0); - - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - // Initial metastate. - ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); - - // Metakey down. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_LEFTSHIFT, 1); - NotifyKeyArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); - ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); - - // Key down. - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, - EV_KEY, KEY_A, 1); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); - - // Key up. - process(mapper, ARBITRARY_TIME + 2, DEVICE_ID, - EV_KEY, KEY_A, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); - - // Metakey up. - process(mapper, ARBITRARY_TIME + 3, DEVICE_ID, - EV_KEY, KEY_LEFTSHIFT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); - ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); -} - -TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) { - mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); - - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_90); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); -} - -TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { - mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); - - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addConfigurationProperty("keyboard.orientationAware", "1"); - addMapperAndConfigure(mapper); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_0); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_90); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN)); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_180); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_LEFT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT)); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_270); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_LEFT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_UP)); - - // Special case: if orientation changes while key is down, we still emit the same keycode - // in the key up as we did in the key down. - NotifyKeyArgs args; - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_270); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(KEY_UP, args.scanCode); - ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_180); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(KEY_UP, args.scanCode); - ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); -} - -TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 1); - ASSERT_EQ(1, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); - - mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 0); - ASSERT_EQ(0, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); -} - -TEST_F(KeyboardInputMapperTest, GetScanCodeState) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 1); - ASSERT_EQ(1, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); - - mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 0); - ASSERT_EQ(0, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); -} - -TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0); - - const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; - uint8_t flags[2] = { 0, 0 }; - ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags)); - ASSERT_TRUE(flags[0]); - ASSERT_FALSE(flags[1]); -} - -TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) { - mFakeEventHub->addLed(DEVICE_ID, LED_CAPSL, true /*initially on*/); - mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/); - mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/); - mFakeEventHub->addKey(DEVICE_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); - - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - // Initialization should have turned all of the lights off. - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - - // Toggle caps lock on. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_CAPSLOCK, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_CAPSLOCK, 0); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper->getMetaState()); - - // Toggle num lock on. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_NUMLOCK, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_NUMLOCK, 0); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper->getMetaState()); - - // Toggle caps lock off. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_CAPSLOCK, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_CAPSLOCK, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper->getMetaState()); - - // Toggle scroll lock on. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_SCROLLLOCK, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_SCROLLLOCK, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper->getMetaState()); - - // Toggle num lock off. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_NUMLOCK, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_NUMLOCK, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper->getMetaState()); - - // Toggle scroll lock off. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_SCROLLLOCK, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_SCROLLLOCK, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); -} - - -// --- CursorInputMapperTest --- - -class CursorInputMapperTest : public InputMapperTest { -protected: - static const int32_t TRACKBALL_MOVEMENT_THRESHOLD; - - sp<FakePointerController> mFakePointerController; - - virtual void SetUp() { - InputMapperTest::SetUp(); - - mFakePointerController = new FakePointerController(); - mFakePolicy->setPointerController(DEVICE_ID, mFakePointerController); - } - - void testMotionRotation(CursorInputMapper* mapper, - int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY); -}; - -const int32_t CursorInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6; - -void CursorInputMapperTest::testMotionRotation(CursorInputMapper* mapper, - int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY) { - NotifyMotionArgs args; - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, originalX); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, originalY); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD, - float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); -} - -TEST_F(CursorInputMapperTest, WhenModeIsPointer_GetSources_ReturnsMouse) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "pointer"); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); -} - -TEST_F(CursorInputMapperTest, WhenModeIsNavigation_GetSources_ReturnsTrackball) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources()); -} - -TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeFromPointerController) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "pointer"); - addMapperAndConfigure(mapper); - - InputDeviceInfo info; - mapper->populateDeviceInfo(&info); - - // Initially there may not be a valid motion range. - ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE)); - ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE)); - ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, - AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f)); - - // When the bounds are set, then there should be a valid motion range. - mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1); - - InputDeviceInfo info2; - mapper->populateDeviceInfo(&info2); - - ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, - AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE, - 1, 800 - 1, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, - AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE, - 2, 480 - 1, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, - AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE, - 0.0f, 1.0f, 0.0f, 0.0f)); -} - -TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsScaledRange) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); - - InputDeviceInfo info; - mapper->populateDeviceInfo(&info); - - ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, - AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_TRACKBALL, - -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); - ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, - AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_TRACKBALL, - -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); - ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, - AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TRACKBALL, - 0.0f, 1.0f, 0.0f, 0.0f)); -} - -TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - NotifyMotionArgs args; - - // Button press. - // Mostly testing non x/y behavior here so we don't need to check again elsewhere. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source); - ASSERT_EQ(uint32_t(0), args.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(0, args.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, args.buttonState); - ASSERT_EQ(0, args.edgeFlags); - ASSERT_EQ(uint32_t(1), args.pointerCount); - ASSERT_EQ(0, args.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); - ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Button release. Should have same down time. - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, BTN_MOUSE, 0); - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source); - ASSERT_EQ(uint32_t(0), args.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_EQ(0, args.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(0, args.buttonState); - ASSERT_EQ(0, args.edgeFlags); - ASSERT_EQ(uint32_t(1), args.pointerCount); - ASSERT_EQ(0, args.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); - ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); -} - -TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); - - NotifyMotionArgs args; - - // Motion in X but not Y. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // Motion in Y but not X. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, -2); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); -} - -TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); - - NotifyMotionArgs args; - - // Button press. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // Button release. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); -} - -TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); - - NotifyMotionArgs args; - - // Combined X, Y and Button. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, -2); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // Move X, Y a bit while pressed. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 2); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // Release Button. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); -} - -TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, - DISPLAY_ORIENTATION_90); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); -} - -TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "navigation"); - addConfigurationProperty("cursor.orientationAware", "1"); - addMapperAndConfigure(mapper); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1)); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1)); - - setDisplayInfoAndReconfigure(DISPLAY_ID, - DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1)); -} - -TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "pointer"); - addMapperAndConfigure(mapper); - - mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); - mFakePointerController->setPosition(100, 200); - mFakePointerController->setButtonState(0); - - NotifyMotionArgs motionArgs; - NotifyKeyArgs keyArgs; - - // press BTN_LEFT, release BTN_LEFT - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_LEFT, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_LEFT, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_RIGHT, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MIDDLE, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, - motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, - mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_RIGHT, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MIDDLE, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // press BTN_BACK, release BTN_BACK - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_BACK, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_BACK, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - - // press BTN_SIDE, release BTN_SIDE - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_SIDE, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_SIDE, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - - // press BTN_FORWARD, release BTN_FORWARD - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_FORWARD, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_FORWARD, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - - // press BTN_EXTRA, release BTN_EXTRA - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_EXTRA, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_EXTRA, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); -} - -TEST_F(CursorInputMapperTest, Process_WhenModeIsPointer_ShouldMoveThePointerAround) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "pointer"); - addMapperAndConfigure(mapper); - - mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); - mFakePointerController->setPosition(100, 200); - mFakePointerController->setButtonState(0); - - NotifyMotionArgs args; - - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 10); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 20); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f)); -} - - -// --- TouchInputMapperTest --- - -class TouchInputMapperTest : public InputMapperTest { -protected: - static const int32_t RAW_X_MIN; - static const int32_t RAW_X_MAX; - static const int32_t RAW_Y_MIN; - static const int32_t RAW_Y_MAX; - static const int32_t RAW_TOUCH_MIN; - static const int32_t RAW_TOUCH_MAX; - static const int32_t RAW_TOOL_MIN; - static const int32_t RAW_TOOL_MAX; - static const int32_t RAW_PRESSURE_MIN; - static const int32_t RAW_PRESSURE_MAX; - static const int32_t RAW_ORIENTATION_MIN; - static const int32_t RAW_ORIENTATION_MAX; - static const int32_t RAW_DISTANCE_MIN; - static const int32_t RAW_DISTANCE_MAX; - static const int32_t RAW_TILT_MIN; - static const int32_t RAW_TILT_MAX; - static const int32_t RAW_ID_MIN; - static const int32_t RAW_ID_MAX; - static const int32_t RAW_SLOT_MIN; - static const int32_t RAW_SLOT_MAX; - static const float X_PRECISION; - static const float Y_PRECISION; - - static const float GEOMETRIC_SCALE; - - static const VirtualKeyDefinition VIRTUAL_KEYS[2]; - - enum Axes { - POSITION = 1 << 0, - TOUCH = 1 << 1, - TOOL = 1 << 2, - PRESSURE = 1 << 3, - ORIENTATION = 1 << 4, - MINOR = 1 << 5, - ID = 1 << 6, - DISTANCE = 1 << 7, - TILT = 1 << 8, - SLOT = 1 << 9, - TOOL_TYPE = 1 << 10, - }; - - void prepareDisplay(int32_t orientation); - void prepareVirtualKeys(); - int32_t toRawX(float displayX); - int32_t toRawY(float displayY); - float toDisplayX(int32_t rawX); - float toDisplayY(int32_t rawY); -}; - -const int32_t TouchInputMapperTest::RAW_X_MIN = 25; -const int32_t TouchInputMapperTest::RAW_X_MAX = 1019; -const int32_t TouchInputMapperTest::RAW_Y_MIN = 30; -const int32_t TouchInputMapperTest::RAW_Y_MAX = 1009; -const int32_t TouchInputMapperTest::RAW_TOUCH_MIN = 0; -const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31; -const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0; -const int32_t TouchInputMapperTest::RAW_TOOL_MAX = 15; -const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = RAW_TOUCH_MIN; -const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = RAW_TOUCH_MAX; -const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7; -const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7; -const int32_t TouchInputMapperTest::RAW_DISTANCE_MIN = 0; -const int32_t TouchInputMapperTest::RAW_DISTANCE_MAX = 7; -const int32_t TouchInputMapperTest::RAW_TILT_MIN = 0; -const int32_t TouchInputMapperTest::RAW_TILT_MAX = 150; -const int32_t TouchInputMapperTest::RAW_ID_MIN = 0; -const int32_t TouchInputMapperTest::RAW_ID_MAX = 9; -const int32_t TouchInputMapperTest::RAW_SLOT_MIN = 0; -const int32_t TouchInputMapperTest::RAW_SLOT_MAX = 9; -const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH; -const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT; - -const float TouchInputMapperTest::GEOMETRIC_SCALE = - avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN + 1), - float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN + 1)); - -const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = { - { KEY_HOME, 60, DISPLAY_HEIGHT + 15, 20, 20 }, - { KEY_MENU, DISPLAY_HEIGHT - 60, DISPLAY_WIDTH + 15, 20, 20 }, -}; - -void TouchInputMapperTest::prepareDisplay(int32_t orientation) { - setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation); -} - -void TouchInputMapperTest::prepareVirtualKeys() { - mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]); - mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]); - mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); - mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, 0, AKEYCODE_MENU, POLICY_FLAG_WAKE); -} - -int32_t TouchInputMapperTest::toRawX(float displayX) { - return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH + RAW_X_MIN); -} - -int32_t TouchInputMapperTest::toRawY(float displayY) { - return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN); -} - -float TouchInputMapperTest::toDisplayX(int32_t rawX) { - return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN + 1); -} - -float TouchInputMapperTest::toDisplayY(int32_t rawY) { - return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN + 1); -} - - -// --- SingleTouchInputMapperTest --- - -class SingleTouchInputMapperTest : public TouchInputMapperTest { -protected: - void prepareButtons(); - void prepareAxes(int axes); - - void processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y); - void processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y); - void processUp(SingleTouchInputMapper* mappery); - void processPressure(SingleTouchInputMapper* mapper, int32_t pressure); - void processToolMajor(SingleTouchInputMapper* mapper, int32_t toolMajor); - void processDistance(SingleTouchInputMapper* mapper, int32_t distance); - void processTilt(SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY); - void processKey(SingleTouchInputMapper* mapper, int32_t code, int32_t value); - void processSync(SingleTouchInputMapper* mapper); -}; - -void SingleTouchInputMapperTest::prepareButtons() { - mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); -} - -void SingleTouchInputMapperTest::prepareAxes(int axes) { - if (axes & POSITION) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_X, - RAW_X_MIN, RAW_X_MAX, 0, 0); - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_Y, - RAW_Y_MIN, RAW_Y_MAX, 0, 0); - } - if (axes & PRESSURE) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_PRESSURE, - RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); - } - if (axes & TOOL) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TOOL_WIDTH, - RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); - } - if (axes & DISTANCE) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_DISTANCE, - RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0); - } - if (axes & TILT) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_X, - RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_Y, - RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); - } -} - -void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 1); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, x); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, y); -} - -void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, x); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, y); -} - -void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper* mapper) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 0); -} - -void SingleTouchInputMapperTest::processPressure( - SingleTouchInputMapper* mapper, int32_t pressure) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_PRESSURE, pressure); -} - -void SingleTouchInputMapperTest::processToolMajor( - SingleTouchInputMapper* mapper, int32_t toolMajor) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TOOL_WIDTH, toolMajor); -} - -void SingleTouchInputMapperTest::processDistance( - SingleTouchInputMapper* mapper, int32_t distance) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_DISTANCE, distance); -} - -void SingleTouchInputMapperTest::processTilt( - SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TILT_X, tiltX); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TILT_Y, tiltY); -} - -void SingleTouchInputMapperTest::processKey( - SingleTouchInputMapper* mapper, int32_t code, int32_t value) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, value); -} - -void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); -} - - -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareButtons(); - prepareAxes(POSITION); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); -} - -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X); - mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y); - prepareButtons(); - prepareAxes(POSITION); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); -} - -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareButtons(); - prepareAxes(POSITION); - addConfigurationProperty("touch.deviceType", "touchPad"); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); -} - -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - prepareButtons(); - prepareAxes(POSITION); - addConfigurationProperty("touch.deviceType", "touchScreen"); - addMapperAndConfigure(mapper); - - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources()); -} - -TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - // Unknown key. - ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); - - // Virtual key is down. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); - - // Virtual key is up. - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - ASSERT_EQ(AKEY_STATE_UP, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); -} - -TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - // Unknown key. - ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); - - // Virtual key is down. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); - - // Virtual key is up. - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - ASSERT_EQ(AKEY_STATE_UP, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); -} - -TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A }; - uint8_t flags[2] = { 0, 0 }; - ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags)); - ASSERT_TRUE(flags[0]); - ASSERT_FALSE(flags[1]); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - NotifyKeyArgs args; - - // Press virtual key. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); - ASSERT_EQ(AKEYCODE_HOME, args.keyCode); - ASSERT_EQ(KEY_HOME, args.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Release virtual key. - processUp(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); - ASSERT_EQ(AKEYCODE_HOME, args.keyCode); - ASSERT_EQ(KEY_HOME, args.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); - - // Should not have sent any motions. - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - NotifyKeyArgs keyArgs; - - // Press virtual key. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime); - ASSERT_EQ(DEVICE_ID, keyArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source); - ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, keyArgs.flags); - ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode); - ASSERT_EQ(KEY_HOME, keyArgs.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState); - ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime); - - // Move out of bounds. This should generate a cancel and a pointer down since we moved - // into the display area. - y -= 100; - processMove(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime); - ASSERT_EQ(DEVICE_ID, keyArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source); - ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY - | AKEY_EVENT_FLAG_CANCELED, keyArgs.flags); - ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode); - ASSERT_EQ(KEY_HOME, keyArgs.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState); - ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime); - - NotifyMotionArgs motionArgs; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Keep moving out of bounds. Should generate a pointer move. - y -= 50; - processMove(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Release out of bounds. Should generate a pointer up. - processUp(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - NotifyMotionArgs motionArgs; - - // Initially go down out of bounds. - int32_t x = -10; - int32_t y = -10; - processDown(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); - - // Move into the display area. Should generate a pointer down. - x = 50; - y = 75; - processMove(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Release. Should generate a pointer up. - processUp(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - NotifyMotionArgs motionArgs; - - // Down. - int32_t x = 100; - int32_t y = 125; - processDown(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Move. - x += 50; - y += 75; - processMove(mapper, x, y); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Up. - processUp(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareButtons(); - prepareAxes(POSITION); - addConfigurationProperty("touch.orientationAware", "0"); - addMapperAndConfigure(mapper); - - NotifyMotionArgs args; - - // Rotation 90. - prepareDisplay(DISPLAY_ORIENTATION_90); - processDown(mapper, toRawX(50), toRawY(75)); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); - ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); - - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareButtons(); - prepareAxes(POSITION); - addMapperAndConfigure(mapper); - - NotifyMotionArgs args; - - // Rotation 0. - prepareDisplay(DISPLAY_ORIENTATION_0); - processDown(mapper, toRawX(50), toRawY(75)); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); - ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); - - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); - - // Rotation 90. - prepareDisplay(DISPLAY_ORIENTATION_90); - processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50)); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); - ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); - - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); - - // Rotation 180. - prepareDisplay(DISPLAY_ORIENTATION_180); - processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); - ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); - - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); - - // Rotation 270. - prepareDisplay(DISPLAY_ORIENTATION_270); - processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); - ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); - - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); -} - -TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION | PRESSURE | TOOL | DISTANCE | TILT); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawPressure = 10; - int32_t rawToolMajor = 12; - int32_t rawDistance = 2; - int32_t rawTiltX = 30; - int32_t rawTiltY = 110; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float pressure = float(rawPressure) / RAW_PRESSURE_MAX; - float size = float(rawToolMajor) / RAW_TOOL_MAX; - float tool = float(rawToolMajor) * GEOMETRIC_SCALE; - float distance = float(rawDistance); - - float tiltCenter = (RAW_TILT_MAX + RAW_TILT_MIN) * 0.5f; - float tiltScale = M_PI / 180; - float tiltXAngle = (rawTiltX - tiltCenter) * tiltScale; - float tiltYAngle = (rawTiltY - tiltCenter) * tiltScale; - float orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); - float tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); - - processDown(mapper, rawX, rawY); - processPressure(mapper, rawPressure); - processToolMajor(mapper, rawToolMajor); - processDistance(mapper, rawDistance); - processTilt(mapper, rawTiltX, rawTiltY); - processSync(mapper); - - NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, pressure, size, tool, tool, tool, tool, orientation, distance)); - ASSERT_EQ(tilt, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_TILT)); -} - -TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - addMapperAndConfigure(mapper); - - NotifyMotionArgs motionArgs; - NotifyKeyArgs keyArgs; - - processDown(mapper, 100, 200); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(0, motionArgs.buttonState); - - // press BTN_LEFT, release BTN_LEFT - processKey(mapper, BTN_LEFT, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); - - processKey(mapper, BTN_LEFT, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE - processKey(mapper, BTN_RIGHT, 1); - processKey(mapper, BTN_MIDDLE, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, - motionArgs.buttonState); - - processKey(mapper, BTN_RIGHT, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - processKey(mapper, BTN_MIDDLE, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - // press BTN_BACK, release BTN_BACK - processKey(mapper, BTN_BACK, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - processKey(mapper, BTN_BACK, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - - // press BTN_SIDE, release BTN_SIDE - processKey(mapper, BTN_SIDE, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - processKey(mapper, BTN_SIDE, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - - // press BTN_FORWARD, release BTN_FORWARD - processKey(mapper, BTN_FORWARD, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - processKey(mapper, BTN_FORWARD, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - - // press BTN_EXTRA, release BTN_EXTRA - processKey(mapper, BTN_EXTRA, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - processKey(mapper, BTN_EXTRA, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - - // press BTN_STYLUS, release BTN_STYLUS - processKey(mapper, BTN_STYLUS, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY, motionArgs.buttonState); - - processKey(mapper, BTN_STYLUS, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - // press BTN_STYLUS2, release BTN_STYLUS2 - processKey(mapper, BTN_STYLUS2, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); - - processKey(mapper, BTN_STYLUS2, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - // release touch - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(0, motionArgs.buttonState); -} - -TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - addMapperAndConfigure(mapper); - - NotifyMotionArgs motionArgs; - - // default tool type is finger - processDown(mapper, 100, 200); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // eraser - processKey(mapper, BTN_TOOL_RUBBER, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); - - // stylus - processKey(mapper, BTN_TOOL_RUBBER, 0); - processKey(mapper, BTN_TOOL_PEN, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // brush - processKey(mapper, BTN_TOOL_PEN, 0); - processKey(mapper, BTN_TOOL_BRUSH, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // pencil - processKey(mapper, BTN_TOOL_BRUSH, 0); - processKey(mapper, BTN_TOOL_PENCIL, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // airbrush - processKey(mapper, BTN_TOOL_PENCIL, 0); - processKey(mapper, BTN_TOOL_AIRBRUSH, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // mouse - processKey(mapper, BTN_TOOL_AIRBRUSH, 0); - processKey(mapper, BTN_TOOL_MOUSE, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); - - // lens - processKey(mapper, BTN_TOOL_MOUSE, 0); - processKey(mapper, BTN_TOOL_LENS, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); - - // double-tap - processKey(mapper, BTN_TOOL_LENS, 0); - processKey(mapper, BTN_TOOL_DOUBLETAP, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // triple-tap - processKey(mapper, BTN_TOOL_DOUBLETAP, 0); - processKey(mapper, BTN_TOOL_TRIPLETAP, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // quad-tap - processKey(mapper, BTN_TOOL_TRIPLETAP, 0); - processKey(mapper, BTN_TOOL_QUADTAP, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // finger - processKey(mapper, BTN_TOOL_QUADTAP, 0); - processKey(mapper, BTN_TOOL_FINGER, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // stylus trumps finger - processKey(mapper, BTN_TOOL_PEN, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // eraser trumps stylus - processKey(mapper, BTN_TOOL_RUBBER, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); - - // mouse trumps eraser - processKey(mapper, BTN_TOOL_MOUSE, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); - - // back to default tool type - processKey(mapper, BTN_TOOL_MOUSE, 0); - processKey(mapper, BTN_TOOL_RUBBER, 0); - processKey(mapper, BTN_TOOL_PEN, 0); - processKey(mapper, BTN_TOOL_FINGER, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - mFakeEventHub->addKey(DEVICE_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0); - addMapperAndConfigure(mapper); - - NotifyMotionArgs motionArgs; - - // initially hovering because BTN_TOUCH not sent yet, pressure defaults to 0 - processKey(mapper, BTN_TOOL_FINGER, 1); - processMove(mapper, 100, 200); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); - - // move a little - processMove(mapper, 150, 250); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - // down when BTN_TOUCH is pressed, pressure defaults to 1 - processKey(mapper, BTN_TOUCH, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); - - // up when BTN_TOUCH is released, hover restored - processKey(mapper, BTN_TOUCH, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - // exit hover when pointer goes away - processKey(mapper, BTN_TOOL_FINGER, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); -} - -TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsValueIsZero) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION | PRESSURE); - addMapperAndConfigure(mapper); - - NotifyMotionArgs motionArgs; - - // initially hovering because pressure is 0 - processDown(mapper, 100, 200); - processPressure(mapper, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); - - // move a little - processMove(mapper, 150, 250); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - // down when pressure is non-zero - processPressure(mapper, RAW_PRESSURE_MAX); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); - - // up when pressure becomes 0, hover restored - processPressure(mapper, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - // exit hover when pointer goes away - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); -} - - -// --- MultiTouchInputMapperTest --- - -class MultiTouchInputMapperTest : public TouchInputMapperTest { -protected: - void prepareAxes(int axes); - - void processPosition(MultiTouchInputMapper* mapper, int32_t x, int32_t y); - void processTouchMajor(MultiTouchInputMapper* mapper, int32_t touchMajor); - void processTouchMinor(MultiTouchInputMapper* mapper, int32_t touchMinor); - void processToolMajor(MultiTouchInputMapper* mapper, int32_t toolMajor); - void processToolMinor(MultiTouchInputMapper* mapper, int32_t toolMinor); - void processOrientation(MultiTouchInputMapper* mapper, int32_t orientation); - void processPressure(MultiTouchInputMapper* mapper, int32_t pressure); - void processDistance(MultiTouchInputMapper* mapper, int32_t distance); - void processId(MultiTouchInputMapper* mapper, int32_t id); - void processSlot(MultiTouchInputMapper* mapper, int32_t slot); - void processToolType(MultiTouchInputMapper* mapper, int32_t toolType); - void processKey(MultiTouchInputMapper* mapper, int32_t code, int32_t value); - void processMTSync(MultiTouchInputMapper* mapper); - void processSync(MultiTouchInputMapper* mapper); -}; - -void MultiTouchInputMapperTest::prepareAxes(int axes) { - if (axes & POSITION) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X, - RAW_X_MIN, RAW_X_MAX, 0, 0); - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y, - RAW_Y_MIN, RAW_Y_MAX, 0, 0); - } - if (axes & TOUCH) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, - RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); - if (axes & MINOR) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR, - RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); - } - } - if (axes & TOOL) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR, - RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); - if (axes & MINOR) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR, - RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0); - } - } - if (axes & ORIENTATION) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION, - RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0); - } - if (axes & PRESSURE) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_PRESSURE, - RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); - } - if (axes & DISTANCE) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_DISTANCE, - RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0); - } - if (axes & ID) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TRACKING_ID, - RAW_ID_MIN, RAW_ID_MAX, 0, 0); - } - if (axes & SLOT) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_SLOT, - RAW_SLOT_MIN, RAW_SLOT_MAX, 0, 0); - mFakeEventHub->setAbsoluteAxisValue(DEVICE_ID, ABS_MT_SLOT, 0); - } - if (axes & TOOL_TYPE) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOOL_TYPE, - 0, MT_TOOL_MAX, 0, 0); - } -} - -void MultiTouchInputMapperTest::processPosition( - MultiTouchInputMapper* mapper, int32_t x, int32_t y) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_X, x); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_Y, y); -} - -void MultiTouchInputMapperTest::processTouchMajor( - MultiTouchInputMapper* mapper, int32_t touchMajor) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MAJOR, touchMajor); -} - -void MultiTouchInputMapperTest::processTouchMinor( - MultiTouchInputMapper* mapper, int32_t touchMinor) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MINOR, touchMinor); -} - -void MultiTouchInputMapperTest::processToolMajor( - MultiTouchInputMapper* mapper, int32_t toolMajor) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MAJOR, toolMajor); -} - -void MultiTouchInputMapperTest::processToolMinor( - MultiTouchInputMapper* mapper, int32_t toolMinor) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MINOR, toolMinor); -} - -void MultiTouchInputMapperTest::processOrientation( - MultiTouchInputMapper* mapper, int32_t orientation) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_ORIENTATION, orientation); -} - -void MultiTouchInputMapperTest::processPressure( - MultiTouchInputMapper* mapper, int32_t pressure) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_PRESSURE, pressure); -} - -void MultiTouchInputMapperTest::processDistance( - MultiTouchInputMapper* mapper, int32_t distance) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_DISTANCE, distance); -} - -void MultiTouchInputMapperTest::processId( - MultiTouchInputMapper* mapper, int32_t id) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TRACKING_ID, id); -} - -void MultiTouchInputMapperTest::processSlot( - MultiTouchInputMapper* mapper, int32_t slot) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_SLOT, slot); -} - -void MultiTouchInputMapperTest::processToolType( - MultiTouchInputMapper* mapper, int32_t toolType) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOOL_TYPE, toolType); -} - -void MultiTouchInputMapperTest::processKey( - MultiTouchInputMapper* mapper, int32_t code, int32_t value) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, value); -} - -void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0); -} - -void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) { - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); -} - - -TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - NotifyMotionArgs motionArgs; - - // Two fingers down at once. - int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; - processPosition(mapper, x1, y1); - processMTSync(mapper); - processPosition(mapper, x2, y2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Move. - x1 += 10; y1 += 15; x2 += 5; y2 -= 10; - processPosition(mapper, x1, y1); - processMTSync(mapper); - processPosition(mapper, x2, y2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // First finger up. - x2 += 15; y2 -= 20; - processPosition(mapper, x2, y2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Move. - x2 += 20; y2 -= 25; - processPosition(mapper, x2, y2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // New finger down. - int32_t x3 = 700, y3 = 300; - processPosition(mapper, x2, y2); - processMTSync(mapper); - processPosition(mapper, x3, y3); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Second finger up. - x3 += 30; y3 -= 20; - processPosition(mapper, x3, y3); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Last finger up. - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); - ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); - ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(0, motionArgs.flags); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(0, motionArgs.edgeFlags); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); - ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); - ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); -} - -TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | ID); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - NotifyMotionArgs motionArgs; - - // Two fingers down at once. - int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; - processPosition(mapper, x1, y1); - processId(mapper, 1); - processMTSync(mapper); - processPosition(mapper, x2, y2); - processId(mapper, 2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - // Move. - x1 += 10; y1 += 15; x2 += 5; y2 -= 10; - processPosition(mapper, x1, y1); - processId(mapper, 1); - processMTSync(mapper); - processPosition(mapper, x2, y2); - processId(mapper, 2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - // First finger up. - x2 += 15; y2 -= 20; - processPosition(mapper, x2, y2); - processId(mapper, 2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - // Move. - x2 += 20; y2 -= 25; - processPosition(mapper, x2, y2); - processId(mapper, 2); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - // New finger down. - int32_t x3 = 700, y3 = 300; - processPosition(mapper, x2, y2); - processId(mapper, 2); - processMTSync(mapper); - processPosition(mapper, x3, y3); - processId(mapper, 3); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - // Second finger up. - x3 += 30; y3 -= 20; - processPosition(mapper, x3, y3); - processId(mapper, 3); - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - - // Last finger up. - processMTSync(mapper); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); -} - -TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | ID | SLOT); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - NotifyMotionArgs motionArgs; - - // Two fingers down at once. - int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; - processPosition(mapper, x1, y1); - processId(mapper, 1); - processSlot(mapper, 1); - processPosition(mapper, x2, y2); - processId(mapper, 2); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - // Move. - x1 += 10; y1 += 15; x2 += 5; y2 -= 10; - processSlot(mapper, 0); - processPosition(mapper, x1, y1); - processSlot(mapper, 1); - processPosition(mapper, x2, y2); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - // First finger up. - x2 += 15; y2 -= 20; - processSlot(mapper, 0); - processId(mapper, -1); - processSlot(mapper, 1); - processPosition(mapper, x2, y2); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - // Move. - x2 += 20; y2 -= 25; - processPosition(mapper, x2, y2); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - // New finger down. - int32_t x3 = 700, y3 = 300; - processPosition(mapper, x2, y2); - processSlot(mapper, 0); - processId(mapper, 3); - processPosition(mapper, x3, y3); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - // Second finger up. - x3 += 30; y3 -= 20; - processSlot(mapper, 1); - processId(mapper, -1); - processSlot(mapper, 0); - processPosition(mapper, x3, y3); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - motionArgs.action); - ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], - toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - - // Last finger up. - processId(mapper, -1); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); - - // Should not have sent any more keys or motions. - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); -} - -TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR | DISTANCE); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawTouchMajor = 7; - int32_t rawTouchMinor = 6; - int32_t rawToolMajor = 9; - int32_t rawToolMinor = 8; - int32_t rawPressure = 11; - int32_t rawDistance = 0; - int32_t rawOrientation = 3; - int32_t id = 5; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float pressure = float(rawPressure) / RAW_PRESSURE_MAX; - float size = avg(rawTouchMajor, rawTouchMinor) / RAW_TOUCH_MAX; - float toolMajor = float(rawToolMajor) * GEOMETRIC_SCALE; - float toolMinor = float(rawToolMinor) * GEOMETRIC_SCALE; - float touchMajor = float(rawTouchMajor) * GEOMETRIC_SCALE; - float touchMinor = float(rawTouchMinor) * GEOMETRIC_SCALE; - float orientation = float(rawOrientation) / RAW_ORIENTATION_MAX * M_PI_2; - float distance = float(rawDistance); - - processPosition(mapper, rawX, rawY); - processTouchMajor(mapper, rawTouchMajor); - processTouchMinor(mapper, rawTouchMinor); - processToolMajor(mapper, rawToolMajor); - processToolMinor(mapper, rawToolMinor); - processPressure(mapper, rawPressure); - processOrientation(mapper, rawOrientation); - processDistance(mapper, rawDistance); - processId(mapper, id); - processMTSync(mapper); - processSync(mapper); - - NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(0, args.pointerProperties[0].id); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, pressure, size, touchMajor, touchMinor, toolMajor, toolMinor, - orientation, distance)); -} - -TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | TOUCH | TOOL | MINOR); - addConfigurationProperty("touch.size.calibration", "geometric"); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawTouchMajor = 140; - int32_t rawTouchMinor = 120; - int32_t rawToolMajor = 180; - int32_t rawToolMinor = 160; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float size = avg(rawTouchMajor, rawTouchMinor) / RAW_TOUCH_MAX; - float toolMajor = float(rawToolMajor) * GEOMETRIC_SCALE; - float toolMinor = float(rawToolMinor) * GEOMETRIC_SCALE; - float touchMajor = float(rawTouchMajor) * GEOMETRIC_SCALE; - float touchMinor = float(rawTouchMinor) * GEOMETRIC_SCALE; - - processPosition(mapper, rawX, rawY); - processTouchMajor(mapper, rawTouchMajor); - processTouchMinor(mapper, rawTouchMinor); - processToolMajor(mapper, rawToolMajor); - processToolMinor(mapper, rawToolMinor); - processMTSync(mapper); - processSync(mapper); - - NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, 1.0f, size, touchMajor, touchMinor, toolMajor, toolMinor, 0, 0)); -} - -TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | TOUCH | TOOL); - addConfigurationProperty("touch.size.calibration", "diameter"); - addConfigurationProperty("touch.size.scale", "10"); - addConfigurationProperty("touch.size.bias", "160"); - addConfigurationProperty("touch.size.isSummed", "1"); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - // Note: We only provide a single common touch/tool value because the device is assumed - // not to emit separate values for each pointer (isSummed = 1). - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawX2 = 150; - int32_t rawY2 = 250; - int32_t rawTouchMajor = 5; - int32_t rawToolMajor = 8; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float x2 = toDisplayX(rawX2); - float y2 = toDisplayY(rawY2); - float size = float(rawTouchMajor) / 2 / RAW_TOUCH_MAX; - float touch = float(rawTouchMajor) / 2 * 10.0f + 160.0f; - float tool = float(rawToolMajor) / 2 * 10.0f + 160.0f; - - processPosition(mapper, rawX, rawY); - processTouchMajor(mapper, rawTouchMajor); - processToolMajor(mapper, rawToolMajor); - processMTSync(mapper); - processPosition(mapper, rawX2, rawY2); - processTouchMajor(mapper, rawTouchMajor); - processToolMajor(mapper, rawToolMajor); - processMTSync(mapper); - processSync(mapper); - - NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - args.action); - ASSERT_EQ(size_t(2), args.pointerCount); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, 1.0f, size, touch, touch, tool, tool, 0, 0)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[1], - x2, y2, 1.0f, size, touch, touch, tool, tool, 0, 0)); -} - -TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_AreaCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | TOUCH | TOOL); - addConfigurationProperty("touch.size.calibration", "area"); - addConfigurationProperty("touch.size.scale", "43"); - addConfigurationProperty("touch.size.bias", "3"); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawTouchMajor = 5; - int32_t rawToolMajor = 8; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float size = float(rawTouchMajor) / RAW_TOUCH_MAX; - float touch = sqrtf(rawTouchMajor) * 43.0f + 3.0f; - float tool = sqrtf(rawToolMajor) * 43.0f + 3.0f; - - processPosition(mapper, rawX, rawY); - processTouchMajor(mapper, rawTouchMajor); - processToolMajor(mapper, rawToolMajor); - processMTSync(mapper); - processSync(mapper); - - NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, 1.0f, size, touch, touch, tool, tool, 0, 0)); -} - -TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | PRESSURE); - addConfigurationProperty("touch.pressure.calibration", "amplitude"); - addConfigurationProperty("touch.pressure.scale", "0.01"); - addMapperAndConfigure(mapper); - - // These calculations are based on the input device calibration documentation. - int32_t rawX = 100; - int32_t rawY = 200; - int32_t rawPressure = 60; - - float x = toDisplayX(rawX); - float y = toDisplayY(rawY); - float pressure = float(rawPressure) * 0.01f; - - processPosition(mapper, rawX, rawY); - processPressure(mapper, rawPressure); - processMTSync(mapper); - processSync(mapper); - - NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, pressure, 0, 0, 0, 0, 0, 0, 0)); -} - -TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllButtons) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | ID | SLOT); - addMapperAndConfigure(mapper); - - NotifyMotionArgs motionArgs; - NotifyKeyArgs keyArgs; - - processId(mapper, 1); - processPosition(mapper, 100, 200); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(0, motionArgs.buttonState); - - // press BTN_LEFT, release BTN_LEFT - processKey(mapper, BTN_LEFT, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); - - processKey(mapper, BTN_LEFT, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE - processKey(mapper, BTN_RIGHT, 1); - processKey(mapper, BTN_MIDDLE, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, - motionArgs.buttonState); - - processKey(mapper, BTN_RIGHT, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - processKey(mapper, BTN_MIDDLE, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - // press BTN_BACK, release BTN_BACK - processKey(mapper, BTN_BACK, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - processKey(mapper, BTN_BACK, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - - // press BTN_SIDE, release BTN_SIDE - processKey(mapper, BTN_SIDE, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - processKey(mapper, BTN_SIDE, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); - - // press BTN_FORWARD, release BTN_FORWARD - processKey(mapper, BTN_FORWARD, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - processKey(mapper, BTN_FORWARD, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - - // press BTN_EXTRA, release BTN_EXTRA - processKey(mapper, BTN_EXTRA, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - processKey(mapper, BTN_EXTRA, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); - - // press BTN_STYLUS, release BTN_STYLUS - processKey(mapper, BTN_STYLUS, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY, motionArgs.buttonState); - - processKey(mapper, BTN_STYLUS, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - // press BTN_STYLUS2, release BTN_STYLUS2 - processKey(mapper, BTN_STYLUS2, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); - - processKey(mapper, BTN_STYLUS2, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(0, motionArgs.buttonState); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - - // release touch - processId(mapper, -1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(0, motionArgs.buttonState); -} - -TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); - addMapperAndConfigure(mapper); - - NotifyMotionArgs motionArgs; - - // default tool type is finger - processId(mapper, 1); - processPosition(mapper, 100, 200); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // eraser - processKey(mapper, BTN_TOOL_RUBBER, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); - - // stylus - processKey(mapper, BTN_TOOL_RUBBER, 0); - processKey(mapper, BTN_TOOL_PEN, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // brush - processKey(mapper, BTN_TOOL_PEN, 0); - processKey(mapper, BTN_TOOL_BRUSH, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // pencil - processKey(mapper, BTN_TOOL_BRUSH, 0); - processKey(mapper, BTN_TOOL_PENCIL, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // airbrush - processKey(mapper, BTN_TOOL_PENCIL, 0); - processKey(mapper, BTN_TOOL_AIRBRUSH, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // mouse - processKey(mapper, BTN_TOOL_AIRBRUSH, 0); - processKey(mapper, BTN_TOOL_MOUSE, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); - - // lens - processKey(mapper, BTN_TOOL_MOUSE, 0); - processKey(mapper, BTN_TOOL_LENS, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); - - // double-tap - processKey(mapper, BTN_TOOL_LENS, 0); - processKey(mapper, BTN_TOOL_DOUBLETAP, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // triple-tap - processKey(mapper, BTN_TOOL_DOUBLETAP, 0); - processKey(mapper, BTN_TOOL_TRIPLETAP, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // quad-tap - processKey(mapper, BTN_TOOL_TRIPLETAP, 0); - processKey(mapper, BTN_TOOL_QUADTAP, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // finger - processKey(mapper, BTN_TOOL_QUADTAP, 0); - processKey(mapper, BTN_TOOL_FINGER, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // stylus trumps finger - processKey(mapper, BTN_TOOL_PEN, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // eraser trumps stylus - processKey(mapper, BTN_TOOL_RUBBER, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); - - // mouse trumps eraser - processKey(mapper, BTN_TOOL_MOUSE, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); - - // MT tool type trumps BTN tool types: MT_TOOL_FINGER - processToolType(mapper, MT_TOOL_FINGER); // this is the first time we send MT_TOOL_TYPE - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - - // MT tool type trumps BTN tool types: MT_TOOL_PEN - processToolType(mapper, MT_TOOL_PEN); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - - // back to default tool type - processToolType(mapper, -1); // use a deliberately undefined tool type, for testing - processKey(mapper, BTN_TOOL_MOUSE, 0); - processKey(mapper, BTN_TOOL_RUBBER, 0); - processKey(mapper, BTN_TOOL_PEN, 0); - processKey(mapper, BTN_TOOL_FINGER, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); -} - -TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | ID | SLOT); - mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); - addMapperAndConfigure(mapper); - - NotifyMotionArgs motionArgs; - - // initially hovering because BTN_TOUCH not sent yet, pressure defaults to 0 - processId(mapper, 1); - processPosition(mapper, 100, 200); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); - - // move a little - processPosition(mapper, 150, 250); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - // down when BTN_TOUCH is pressed, pressure defaults to 1 - processKey(mapper, BTN_TOUCH, 1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); - - // up when BTN_TOUCH is released, hover restored - processKey(mapper, BTN_TOUCH, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - // exit hover when pointer goes away - processId(mapper, -1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); -} - -TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfItsValueIsZero) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | ID | SLOT | PRESSURE); - addMapperAndConfigure(mapper); - - NotifyMotionArgs motionArgs; - - // initially hovering because pressure is 0 - processId(mapper, 1); - processPosition(mapper, 100, 200); - processPressure(mapper, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); - - // move a little - processPosition(mapper, 150, 250); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - // down when pressure becomes non-zero - processPressure(mapper, RAW_PRESSURE_MAX); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); - - // up when pressure becomes 0, hover restored - processPressure(mapper, 0); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - - // exit hover when pointer goes away - processId(mapper, -1); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); -} - - -} // namespace android diff --git a/services/java/Android.mk b/services/java/Android.mk deleted file mode 100644 index 8c3d0f0..0000000 --- a/services/java/Android.mk +++ /dev/null @@ -1,18 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -# the library -# ============================================================ -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - $(call all-subdir-java-files) \ - com/android/server/EventLogTags.logtags \ - com/android/server/am/EventLogTags.logtags - -LOCAL_MODULE:= services - -LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common - -include $(BUILD_JAVA_LIBRARY) - -include $(BUILD_DROIDDOC) diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java deleted file mode 100644 index 203cca6..0000000 --- a/services/java/com/android/server/AppWidgetService.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.app.ActivityManager; -import android.appwidget.AppWidgetProviderInfo; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.UserHandle; -import android.util.Slog; -import android.util.SparseArray; -import android.widget.RemoteViews; - -import com.android.internal.appwidget.IAppWidgetHost; -import com.android.internal.appwidget.IAppWidgetService; -import com.android.internal.os.BackgroundThread; -import com.android.internal.util.IndentingPrintWriter; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.List; -import java.util.Locale; - - -/** - * Redirects calls to this service to the instance of the service for the appropriate user. - */ -class AppWidgetService extends IAppWidgetService.Stub -{ - private static final String TAG = "AppWidgetService"; - - Context mContext; - Locale mLocale; - PackageManager mPackageManager; - boolean mSafeMode; - private final Handler mSaveStateHandler; - - private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices; - - AppWidgetService(Context context) { - mContext = context; - - mSaveStateHandler = BackgroundThread.getHandler(); - - mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5); - AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler); - mAppWidgetServices.append(0, primary); - } - - public void systemRunning(boolean safeMode) { - mSafeMode = safeMode; - - mAppWidgetServices.get(0).systemReady(safeMode); - - // Register for the boot completed broadcast, so we can send the - // ENABLE broacasts. If we try to send them now, they time out, - // because the system isn't ready to handle them yet. - mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, - new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); - - // Register for configuration changes so we can update the names - // of the widgets when the locale changes. - mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, - new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null); - - // Register for broadcasts about package install, etc., so we can - // update the provider list. - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_PACKAGE_ADDED); - filter.addAction(Intent.ACTION_PACKAGE_CHANGED); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addDataScheme("package"); - mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, - filter, null, null); - // Register for events related to sdcard installation. - IntentFilter sdFilter = new IntentFilter(); - sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); - sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); - mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, - sdFilter, null, null); - - IntentFilter userFilter = new IntentFilter(); - userFilter.addAction(Intent.ACTION_USER_REMOVED); - userFilter.addAction(Intent.ACTION_USER_STOPPING); - mContext.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { - onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, - UserHandle.USER_NULL)); - } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) { - onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, - UserHandle.USER_NULL)); - } - } - }, userFilter); - } - - @Override - public int allocateAppWidgetId(String packageName, int hostId, int userId) - throws RemoteException { - return getImplForUser(userId).allocateAppWidgetId(packageName, hostId); - } - - @Override - public int[] getAppWidgetIdsForHost(int hostId, int userId) throws RemoteException { - return getImplForUser(userId).getAppWidgetIdsForHost(hostId); - } - - @Override - public void deleteAppWidgetId(int appWidgetId, int userId) throws RemoteException { - getImplForUser(userId).deleteAppWidgetId(appWidgetId); - } - - @Override - public void deleteHost(int hostId, int userId) throws RemoteException { - getImplForUser(userId).deleteHost(hostId); - } - - @Override - public void deleteAllHosts(int userId) throws RemoteException { - getImplForUser(userId).deleteAllHosts(); - } - - @Override - public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options, int userId) - throws RemoteException { - getImplForUser(userId).bindAppWidgetId(appWidgetId, provider, options); - } - - @Override - public boolean bindAppWidgetIdIfAllowed( - String packageName, int appWidgetId, ComponentName provider, Bundle options, int userId) - throws RemoteException { - return getImplForUser(userId).bindAppWidgetIdIfAllowed( - packageName, appWidgetId, provider, options); - } - - @Override - public boolean hasBindAppWidgetPermission(String packageName, int userId) - throws RemoteException { - return getImplForUser(userId).hasBindAppWidgetPermission(packageName); - } - - @Override - public void setBindAppWidgetPermission(String packageName, boolean permission, int userId) - throws RemoteException { - getImplForUser(userId).setBindAppWidgetPermission(packageName, permission); - } - - @Override - public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection, - int userId) throws RemoteException { - getImplForUser(userId).bindRemoteViewsService(appWidgetId, intent, connection); - } - - @Override - public int[] startListening(IAppWidgetHost host, String packageName, int hostId, - List<RemoteViews> updatedViews, int userId) throws RemoteException { - return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews); - } - - public void onUserRemoved(int userId) { - if (userId < 1) return; - synchronized (mAppWidgetServices) { - AppWidgetServiceImpl impl = mAppWidgetServices.get(userId); - mAppWidgetServices.remove(userId); - - if (impl == null) { - AppWidgetServiceImpl.getSettingsFile(userId).delete(); - } else { - impl.onUserRemoved(); - } - } - } - - public void onUserStopping(int userId) { - if (userId < 1) return; - synchronized (mAppWidgetServices) { - AppWidgetServiceImpl impl = mAppWidgetServices.get(userId); - if (impl != null) { - mAppWidgetServices.remove(userId); - impl.onUserStopping(); - } - } - } - - private void checkPermission(int userId) { - int realUserId = ActivityManager.handleIncomingUser( - Binder.getCallingPid(), - Binder.getCallingUid(), - userId, - false, /* allowAll */ - true, /* requireFull */ - this.getClass().getSimpleName(), - this.getClass().getPackage().getName()); - } - - private AppWidgetServiceImpl getImplForUser(int userId) { - checkPermission(userId); - boolean sendInitial = false; - AppWidgetServiceImpl service; - synchronized (mAppWidgetServices) { - service = mAppWidgetServices.get(userId); - if (service == null) { - Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding"); - // TODO: Verify that it's a valid user - service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler); - service.systemReady(mSafeMode); - // Assume that BOOT_COMPLETED was received, as this is a non-primary user. - mAppWidgetServices.append(userId, service); - sendInitial = true; - } - } - if (sendInitial) { - service.sendInitialBroadcasts(); - } - return service; - } - - @Override - public int[] getAppWidgetIds(ComponentName provider, int userId) throws RemoteException { - return getImplForUser(userId).getAppWidgetIds(provider); - } - - @Override - public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId) - throws RemoteException { - return getImplForUser(userId).getAppWidgetInfo(appWidgetId); - } - - @Override - public RemoteViews getAppWidgetViews(int appWidgetId, int userId) throws RemoteException { - return getImplForUser(userId).getAppWidgetViews(appWidgetId); - } - - @Override - public void updateAppWidgetOptions(int appWidgetId, Bundle options, int userId) { - getImplForUser(userId).updateAppWidgetOptions(appWidgetId, options); - } - - @Override - public Bundle getAppWidgetOptions(int appWidgetId, int userId) { - return getImplForUser(userId).getAppWidgetOptions(appWidgetId); - } - - @Override - public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId) - throws RemoteException { - return getImplForUser(userId).getInstalledProviders(categoryFilter); - } - - @Override - public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId, int userId) - throws RemoteException { - getImplForUser(userId).notifyAppWidgetViewDataChanged( - appWidgetIds, viewId); - } - - @Override - public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId) - throws RemoteException { - getImplForUser(userId).partiallyUpdateAppWidgetIds( - appWidgetIds, views); - } - - @Override - public void stopListening(int hostId, int userId) throws RemoteException { - getImplForUser(userId).stopListening(hostId); - } - - @Override - public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId) - throws RemoteException { - getImplForUser(userId).unbindRemoteViewsService( - appWidgetId, intent); - } - - @Override - public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId) - throws RemoteException { - getImplForUser(userId).updateAppWidgetIds(appWidgetIds, views); - } - - @Override - public void updateAppWidgetProvider(ComponentName provider, RemoteViews views, int userId) - throws RemoteException { - getImplForUser(userId).updateAppWidgetProvider(provider, views); - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); - - // Dump the state of all the app widget providers - synchronized (mAppWidgetServices) { - IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); - for (int i = 0; i < mAppWidgetServices.size(); i++) { - pw.println("User: " + mAppWidgetServices.keyAt(i)); - ipw.increaseIndent(); - AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); - service.dump(fd, ipw, args); - ipw.decreaseIndent(); - } - } - } - - BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - // Slog.d(TAG, "received " + action); - if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { - int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); - if (userId >= 0) { - getImplForUser(userId).sendInitialBroadcasts(); - } else { - Slog.w(TAG, "Incorrect user handle supplied in " + intent); - } - } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { - for (int i = 0; i < mAppWidgetServices.size(); i++) { - AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); - service.onConfigurationChanged(); - } - } else { - int sendingUser = getSendingUserId(); - if (sendingUser == UserHandle.USER_ALL) { - for (int i = 0; i < mAppWidgetServices.size(); i++) { - AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); - service.onBroadcastReceived(intent); - } - } else { - AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser); - if (service != null) { - service.onBroadcastReceived(intent); - } - } - } - } - }; -} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index a42cbcf..8968725 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -17,6 +17,9 @@ package com.android.server; import android.app.ActivityManagerNative; +import android.app.ActivityThread; +import android.app.IAlarmManager; +import android.app.INotificationManager; import android.bluetooth.BluetoothAdapter; import android.content.ComponentName; import android.content.ContentResolver; @@ -28,8 +31,10 @@ import android.content.res.Configuration; import android.media.AudioService; import android.net.wifi.p2p.WifiP2pService; import android.os.Environment; +import android.os.FactoryTest; import android.os.Handler; -import android.os.HandlerThread; +import android.os.IBinder; +import android.os.IPowerManager; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; @@ -51,22 +56,30 @@ import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accounts.AccountManagerService; import com.android.server.am.ActivityManagerService; import com.android.server.am.BatteryStatsService; +import com.android.server.clipboard.ClipboardService; import com.android.server.content.ContentService; +import com.android.server.devicepolicy.DevicePolicyManagerService; import com.android.server.display.DisplayManagerService; import com.android.server.dreams.DreamManagerService; import com.android.server.input.InputManagerService; +import com.android.server.lights.LightsManager; +import com.android.server.lights.LightsService; import com.android.server.media.MediaRouterService; import com.android.server.net.NetworkPolicyManagerService; import com.android.server.net.NetworkStatsService; +import com.android.server.notification.NotificationManagerService; import com.android.server.os.SchedulingPolicyService; import com.android.server.pm.Installer; import com.android.server.pm.PackageManagerService; import com.android.server.pm.UserManagerService; import com.android.server.power.PowerManagerService; import com.android.server.power.ShutdownThread; -import com.android.server.print.PrintManagerService; import com.android.server.search.SearchManagerService; +import com.android.server.statusbar.StatusBarManagerService; +import com.android.server.storage.DeviceStorageMonitorService; +import com.android.server.twilight.TwilightService; import com.android.server.usb.UsbService; +import com.android.server.wallpaper.WallpaperManagerService; import com.android.server.wifi.WifiService; import com.android.server.wm.WindowManagerService; @@ -77,62 +90,212 @@ import java.io.File; import java.util.Timer; import java.util.TimerTask; -class ServerThread { +public final class SystemServer { private static final String TAG = "SystemServer"; + private static final String ENCRYPTING_STATE = "trigger_restart_min_framework"; private static final String ENCRYPTED_STATE = "1"; - ContentResolver mContentResolver; + private static final long SNAPSHOT_INTERVAL = 60 * 60 * 1000; // 1hr - void reportWtf(String msg, Throwable e) { - Slog.w(TAG, "***********************************************"); - Log.wtf(TAG, "BOOT FAILURE " + msg, e); + // The earliest supported time. We pick one day into 1970, to + // give any timezone code room without going into negative time. + private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000; + + /* + * Implementation class names. TODO: Move them to a codegen class or load + * them from the build system somehow. + */ + private static final String BACKUP_MANAGER_SERVICE_CLASS = + "com.android.server.backup.BackupManagerService$Lifecycle"; + private static final String APPWIDGET_SERVICE_CLASS = + "com.android.server.appwidget.AppWidgetService"; + private static final String PRINT_MANAGER_SERVICE_CLASS = + "com.android.server.print.PrintManagerService"; + private static final String USB_SERVICE_CLASS = + "com.android.server.usb.UsbService$Lifecycle"; + private static final String HDMI_CEC_SERVICE_CLASS = + "com.android.server.hdmi.HdmiCecService"; + + private final int mFactoryTestMode; + private Timer mProfilerSnapshotTimer; + + private Context mSystemContext; + private SystemServiceManager mSystemServiceManager; + + // TODO: remove all of these references by improving dependency resolution and boot phases + private Installer mInstaller; + private PowerManagerService mPowerManagerService; + private ActivityManagerService mActivityManagerService; + private DisplayManagerService mDisplayManagerService; + private ContentResolver mContentResolver; + + /** + * Called to initialize native system services. + */ + private static native void nativeInit(); + + /** + * The main entry point from zygote. + */ + public static void main(String[] args) { + new SystemServer().run(); } - public void initAndLoop() { - EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, - SystemClock.uptimeMillis()); + public SystemServer() { + mFactoryTestMode = FactoryTest.getMode(); + } - Looper.prepareMainLooper(); + private void run() { + // If a device's clock is before 1970 (before 0), a lot of + // APIs crash dealing with negative numbers, notably + // java.io.File#setLastModified, so instead we fake it and + // hope that time from cell towers or NTP fixes it shortly. + if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) { + Slog.w(TAG, "System clock is before 1970; setting to 1970."); + SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); + } - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_FOREGROUND); + // Here we go! + Slog.i(TAG, "Entered the Android system server!"); + EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis()); + + // In case the runtime switched since last boot (such as when + // the old runtime was removed in an OTA), set the system + // property so that it is in sync. We can't do this in + // libnativehelper's JniInvocation::Init code where we already + // had to fallback to a different runtime because it is + // running as root and we need to be the system user to set + // the property. http://b/11463182 + SystemProperties.set("persist.sys.dalvik.vm.lib", VMRuntime.getRuntime().vmLibrary()); + + // Enable the sampling profiler. + if (SamplingProfilerIntegration.isEnabled()) { + SamplingProfilerIntegration.start(); + mProfilerSnapshotTimer = new Timer(); + mProfilerSnapshotTimer.schedule(new TimerTask() { + @Override + public void run() { + SamplingProfilerIntegration.writeSnapshot("system_server", null); + } + }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL); + } + // Mmmmmm... more memory! + VMRuntime.getRuntime().clearGrowthLimit(); + + // The system server has to run all of the time, so it needs to be + // as efficient as possible with its memory usage. + VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); + + // Within the system server, it is an error to access Environment paths without + // explicitly specifying a user. + Environment.setUserRequired(true); + + // Ensure binder calls into the system always run at foreground priority. BinderInternal.disableBackgroundScheduling(true); + + // Prepare the main looper thread (this thread). + android.os.Process.setThreadPriority( + android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false); + Looper.prepareMainLooper(); + + // Initialize native services. + System.loadLibrary("android_servers"); + nativeInit(); // Check whether we failed to shut down last time we tried. - { - final String shutdownAction = SystemProperties.get( - ShutdownThread.SHUTDOWN_ACTION_PROPERTY, ""); - if (shutdownAction != null && shutdownAction.length() > 0) { - boolean reboot = (shutdownAction.charAt(0) == '1'); - - final String reason; - if (shutdownAction.length() > 1) { - reason = shutdownAction.substring(1, shutdownAction.length()); - } else { - reason = null; - } + // This call may not return. + performPendingShutdown(); - ShutdownThread.rebootOrShutdown(reboot, reason); + // Initialize the system context. + createSystemContext(); + + // Create the system service manager. + mSystemServiceManager = new SystemServiceManager(mSystemContext); + LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); + + // Start services. + try { + startBootstrapServices(); + startCoreServices(); + startOtherServices(); + } catch (RuntimeException ex) { + Slog.e("System", "******************************************"); + Slog.e("System", "************ Failure starting system services", ex); + throw ex; + } + + // For debug builds, log event loop stalls to dropbox for analysis. + if (StrictMode.conditionallyEnableDebugLogging()) { + Slog.i(TAG, "Enabled StrictMode for system server main thread."); + } + + // Loop forever. + Looper.loop(); + throw new RuntimeException("Main thread loop unexpectedly exited"); + } + + private void reportWtf(String msg, Throwable e) { + Slog.w(TAG, "***********************************************"); + Log.wtf(TAG, "BOOT FAILURE " + msg, e); + } + + private void performPendingShutdown() { + final String shutdownAction = SystemProperties.get( + ShutdownThread.SHUTDOWN_ACTION_PROPERTY, ""); + if (shutdownAction != null && shutdownAction.length() > 0) { + boolean reboot = (shutdownAction.charAt(0) == '1'); + + final String reason; + if (shutdownAction.length() > 1) { + reason = shutdownAction.substring(1, shutdownAction.length()); + } else { + reason = null; } + + ShutdownThread.rebootOrShutdown(reboot, reason); } + } - String factoryTestStr = SystemProperties.get("ro.factorytest"); - int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF - : Integer.parseInt(factoryTestStr); - final boolean headless = "1".equals(SystemProperties.get("ro.config.headless", "0")); + private void createSystemContext() { + ActivityThread activityThread = ActivityThread.systemMain(); + mSystemContext = activityThread.getSystemContext(); + mSystemContext.setTheme(android.R.style.Theme_Holo); + } - Installer installer = null; + private void startBootstrapServices() { + // Wait for installd to finish starting up so that it has a chance to + // create critical directories such as /data/user with the appropriate + // permissions. We need this to complete before we initialize other services. + mInstaller = mSystemServiceManager.startService(Installer.class); + + // Power manager needs to be started early because other services need it. + // TODO: The conversion to the new pattern is incomplete. We need to switch + // the power manager's dependencies over then we can use boot phases to arrange + // initialization order and remove the mPowerManagerService field. + mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class); + + // Activity manager runs the show. + mActivityManagerService = mSystemServiceManager.startService( + ActivityManagerService.Lifecycle.class).getService(); + } + + private void startCoreServices() { + // Display manager is needed to provide display metrics before package manager + // starts up. + mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class); + } + + private void startOtherServices() { + final Context context = mSystemContext; AccountManagerService accountManager = null; ContentService contentService = null; - LightsService lights = null; - PowerManagerService power = null; - DisplayManagerService display = null; + LightsManager lights = null; BatteryService battery = null; VibratorService vibrator = null; - AlarmManagerService alarm = null; + IAlarmManager alarm = null; MountService mountService = null; NetworkManagementService networkManagement = null; NetworkStatsService networkStats = null; @@ -142,14 +305,11 @@ class ServerThread { WifiService wifi = null; NsdService serviceDiscovery= null; IPackageManager pm = null; - Context context = null; WindowManagerService wm = null; BluetoothManagerService bluetooth = null; DockObserver dock = null; UsbService usb = null; SerialService serial = null; - TwilightService twilight = null; - UiModeManagerService uiMode = null; RecognitionManagerService recognition = null; NetworkTimeUpdateService networkTimeUpdater = null; CommonTimeManagementService commonTimeMgmtService = null; @@ -157,48 +317,8 @@ class ServerThread { TelephonyRegistry telephonyRegistry = null; ConsumerIrService consumerIr = null; - // Create a handler thread just for the window manager to enjoy. - HandlerThread wmHandlerThread = new HandlerThread("WindowManager"); - wmHandlerThread.start(); - Handler wmHandler = new Handler(wmHandlerThread.getLooper()); - wmHandler.post(new Runnable() { - @Override - public void run() { - //Looper.myLooper().setMessageLogging(new LogPrinter( - // android.util.Log.DEBUG, TAG, android.util.Log.LOG_ID_SYSTEM)); - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_DISPLAY); - android.os.Process.setCanSelfBackground(false); - - // For debug builds, log event loop stalls to dropbox for analysis. - if (StrictMode.conditionallyEnableDebugLogging()) { - Slog.i(TAG, "Enabled StrictMode logging for WM Looper"); - } - } - }); - - // bootstrap services boolean onlyCore = false; boolean firstBoot = false; - try { - // Wait for installd to finished starting up so that it has a chance to - // create critical directories such as /data/user with the appropriate - // permissions. We need this to complete before we initialize other services. - Slog.i(TAG, "Waiting for installd to be ready."); - installer = new Installer(); - installer.ping(); - - Slog.i(TAG, "Power Manager"); - power = new PowerManagerService(); - ServiceManager.addService(Context.POWER_SERVICE, power); - - Slog.i(TAG, "Activity Manager"); - context = ActivityManagerService.main(factoryTest); - } catch (RuntimeException e) { - Slog.e("System", "******************************************"); - Slog.e("System", "************ Failure starting bootstrap service", e); - } - boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false); boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false); boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false); @@ -209,10 +329,6 @@ class ServerThread { boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false); try { - Slog.i(TAG, "Display Manager"); - display = new DisplayManagerService(context, wmHandler); - ServiceManager.addService(Context.DISPLAY_SERVICE, display, true); - Slog.i(TAG, "Telephony Registry"); telephonyRegistry = new TelephonyRegistry(context); ServiceManager.addService("telephony.registry", telephonyRegistry); @@ -222,10 +338,8 @@ class ServerThread { AttributeCache.init(context); - if (!display.waitForDefaultDisplay()) { - reportWtf("Timeout waiting for default display to be initialized.", - new Throwable()); - } + // We need the default display before we can initialize the package manager. + mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); Slog.i(TAG, "Package Manager"); // Only run "core" apps if we're encrypting the device. @@ -238,15 +352,15 @@ class ServerThread { onlyCore = true; } - pm = PackageManagerService.main(context, installer, - factoryTest != SystemServer.FACTORY_TEST_OFF, + pm = PackageManagerService.main(context, mInstaller, + mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, onlyCore); try { firstBoot = pm.isFirstBoot(); } catch (RemoteException e) { } - ActivityManagerService.setSystemProcess(); + mActivityManagerService.setSystemProcess(); Slog.i(TAG, "Entropy Mixer"); ServiceManager.addService("entropy", new EntropyMixer(context)); @@ -269,13 +383,13 @@ class ServerThread { Slog.i(TAG, "Content Manager"); contentService = ContentService.main(context, - factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL); + mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL); Slog.i(TAG, "System Content Providers"); - ActivityManagerService.installSystemProviders(); + mActivityManagerService.installSystemProviders(); - Slog.i(TAG, "Lights Service"); - lights = new LightsService(context); + mSystemServiceManager.startService(LightsService.class); + lights = LocalServices.getService(LightsManager.class); Slog.i(TAG, "Battery Service"); battery = new BatteryService(context, lights); @@ -285,49 +399,49 @@ class ServerThread { vibrator = new VibratorService(context); ServiceManager.addService("vibrator", vibrator); - Slog.i(TAG, "Consumer IR Service"); - consumerIr = new ConsumerIrService(context); - ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr); - + // TODO: use boot phase // only initialize the power service after we have started the // lights service, content providers and the battery service. - power.init(context, lights, ActivityManagerService.self(), battery, + mPowerManagerService.init(lights, battery, BatteryStatsService.getService(), - ActivityManagerService.self().getAppOpsService(), display); + mActivityManagerService.getAppOpsService()); - Slog.i(TAG, "Alarm Manager"); - alarm = new AlarmManagerService(context); - ServiceManager.addService(Context.ALARM_SERVICE, alarm); + Slog.i(TAG, "Consumer IR Service"); + consumerIr = new ConsumerIrService(context); + ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr); + + mSystemServiceManager.startService(AlarmManagerService.class); + alarm = IAlarmManager.Stub.asInterface( + ServiceManager.getService(Context.ALARM_SERVICE)); Slog.i(TAG, "Init Watchdog"); - Watchdog.getInstance().init(context, battery, power, alarm, - ActivityManagerService.self()); - Watchdog.getInstance().addThread(wmHandler, "WindowManager thread"); + final Watchdog watchdog = Watchdog.getInstance(); + watchdog.init(context, mActivityManagerService); Slog.i(TAG, "Input Manager"); - inputManager = new InputManagerService(context, wmHandler); + inputManager = new InputManagerService(context); Slog.i(TAG, "Window Manager"); - wm = WindowManagerService.main(context, power, display, inputManager, - wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL, + wm = WindowManagerService.main(context, inputManager, + mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL, !firstBoot, onlyCore); ServiceManager.addService(Context.WINDOW_SERVICE, wm); ServiceManager.addService(Context.INPUT_SERVICE, inputManager); - ActivityManagerService.self().setWindowManager(wm); + mActivityManagerService.setWindowManager(wm); inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); inputManager.start(); - display.setWindowManager(wm); - display.setInputManager(inputManager); + // TODO: Use service dependencies instead. + mDisplayManagerService.windowManagerAndInputReady(); // Skip Bluetooth if we have an emulator kernel // TODO: Use a more reliable check to see if this product should // support Bluetooth - see bug 988521 if (SystemProperties.get("ro.kernel.qemu").equals("1")) { Slog.i(TAG, "No Bluetooh Service (emulator)"); - } else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) { + } else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) { Slog.i(TAG, "No Bluetooth Service (factory test)"); } else if (!context.getPackageManager().hasSystemFeature (PackageManager.FEATURE_BLUETOOTH)) { @@ -344,23 +458,19 @@ class ServerThread { Slog.e("System", "************ Failure starting core service", e); } - DevicePolicyManagerService devicePolicy = null; StatusBarManagerService statusBar = null; + INotificationManager notification = null; InputMethodManagerService imm = null; - AppWidgetService appWidget = null; - NotificationManagerService notification = null; WallpaperManagerService wallpaper = null; LocationManagerService location = null; CountryDetectorService countryDetector = null; TextServicesManagerService tsms = null; LockSettingsService lockSettings = null; - DreamManagerService dreamy = null; AssetAtlasService atlas = null; - PrintManagerService printManager = null; MediaRouterService mediaRouter = null; // Bring up services needed for UI. - if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { + if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) { //if (!disableNonCoreServices) { // TODO: View depends on these; mock them? if (true) { try { @@ -397,11 +507,11 @@ class ServerThread { ActivityManagerNative.getDefault().showBootMessage( context.getResources().getText( com.android.internal.R.string.android_upgrading_starting_apps), - false); + false); } catch (RemoteException e) { } - if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { + if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) { if (!disableStorage && !"0".equals(SystemProperties.get("system_init.startmountservice"))) { try { @@ -427,9 +537,9 @@ class ServerThread { } try { - Slog.i(TAG, "Device Policy"); - devicePolicy = new DevicePolicyManagerService(context); - ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy); + // Always start the Device Policy Manager, so that the API is compatible with + // API8. + mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class); } catch (Throwable e) { reportWtf("starting DevicePolicyService", e); } @@ -487,7 +597,8 @@ class ServerThread { try { Slog.i(TAG, "NetworkPolicy Service"); networkPolicy = new NetworkPolicyManagerService( - context, ActivityManagerService.self(), power, + context, mActivityManagerService, + (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE), networkStats, networkManagement); ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy); } catch (Throwable e) { @@ -567,22 +678,12 @@ class ServerThread { reportWtf("making Content Service ready", e); } - try { - Slog.i(TAG, "Notification Manager"); - notification = new NotificationManagerService(context, statusBar, lights); - ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification); - networkPolicy.bindNotificationManager(notification); - } catch (Throwable e) { - reportWtf("starting Notification Manager", e); - } + mSystemServiceManager.startService(NotificationManagerService.class); + notification = INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + networkPolicy.bindNotificationManager(notification); - try { - Slog.i(TAG, "Device Storage Monitor"); - ServiceManager.addService(DeviceStorageMonitorService.SERVICE, - new DeviceStorageMonitorService(context)); - } catch (Throwable e) { - reportWtf("starting DeviceStorageMonitor service", e); - } + mSystemServiceManager.startService(DeviceStorageMonitorService.class); if (!disableLocation) { try { @@ -624,10 +725,8 @@ class ServerThread { R.bool.config_enableWallpaperService)) { try { Slog.i(TAG, "Wallpaper Service"); - if (!headless) { - wallpaper = new WallpaperManagerService(context); - ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper); - } + wallpaper = new WallpaperManagerService(context); + ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper); } catch (Throwable e) { reportWtf("starting Wallpaper Service", e); } @@ -665,10 +764,11 @@ class ServerThread { if (!disableNonCoreServices) { try { - Slog.i(TAG, "USB Service"); - // Manage USB host and device support - usb = new UsbService(context); - ServiceManager.addService(Context.USB_SERVICE, usb); + if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST) || + pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)) { + // Manage USB host and device support + mSystemServiceManager.startService(USB_SERVICE_CLASS); + } } catch (Throwable e) { reportWtf("starting UsbService", e); } @@ -683,34 +783,23 @@ class ServerThread { } } - try { - Slog.i(TAG, "Twilight Service"); - twilight = new TwilightService(context); - } catch (Throwable e) { - reportWtf("starting TwilightService", e); - } + mSystemServiceManager.startService(TwilightService.class); - try { - Slog.i(TAG, "UI Mode Manager Service"); - // Listen for UI mode changes - uiMode = new UiModeManagerService(context, twilight); - } catch (Throwable e) { - reportWtf("starting UiModeManagerService", e); - } + mSystemServiceManager.startService(UiModeManagerService.class); if (!disableNonCoreServices) { try { - Slog.i(TAG, "Backup Service"); - ServiceManager.addService(Context.BACKUP_SERVICE, - new BackupManagerService(context)); + if (pm.hasSystemFeature(PackageManager.FEATURE_BACKUP)) { + mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS); + } } catch (Throwable e) { Slog.e(TAG, "Failure starting Backup Service", e); } try { - Slog.i(TAG, "AppWidget Service"); - appWidget = new AppWidgetService(context); - ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget); + if (pm.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) { + mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS); + } } catch (Throwable e) { reportWtf("starting AppWidget Service", e); } @@ -770,16 +859,9 @@ class ServerThread { } } - if (!disableNonCoreServices && - context.getResources().getBoolean(R.bool.config_dreamsSupported)) { - try { - Slog.i(TAG, "Dreams Service"); - // Dreams (interactive idle-time views, a/k/a screen savers) - dreamy = new DreamManagerService(context, wmHandler); - ServiceManager.addService(DreamService.DREAM_SERVICE, dreamy); - } catch (Throwable e) { - reportWtf("starting DreamManagerService", e); - } + if (!disableNonCoreServices) { + // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode) + mSystemServiceManager.startService(DreamManagerService.class); } if (!disableNonCoreServices) { @@ -800,13 +882,19 @@ class ServerThread { } try { - Slog.i(TAG, "Print Service"); - printManager = new PrintManagerService(context); - ServiceManager.addService(Context.PRINT_SERVICE, printManager); + if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) { + mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS); + } } catch (Throwable e) { reportWtf("starting Print Service", e); } + try { + mSystemServiceManager.startService(HDMI_CEC_SERVICE_CLASS); + } catch (Throwable e) { + reportWtf("starting HdmiCec Service", e); + } + if (!disableNonCoreServices) { try { Slog.i(TAG, "Media Router Service"); @@ -822,7 +910,7 @@ class ServerThread { // we are in safe mode. final boolean safeMode = wm.detectSafeMode(); if (safeMode) { - ActivityManagerService.self().enterSafeMode(); + mActivityManagerService.enterSafeMode(); // Post the safe mode state in the Zygote class Zygote.systemInSafeMode = true; // Disable the JIT for the system_server process @@ -848,21 +936,10 @@ class ServerThread { } } - if (devicePolicy != null) { - try { - devicePolicy.systemReady(); - } catch (Throwable e) { - reportWtf("making Device Policy Service ready", e); - } - } + // Needed by DevicePolicyManager for initialization + mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY); - if (notification != null) { - try { - notification.systemReady(); - } catch (Throwable e) { - reportWtf("making Notification Service ready", e); - } - } + mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); try { wm.systemReady(); @@ -871,7 +948,7 @@ class ServerThread { } if (safeMode) { - ActivityManagerService.self().showSafeModeOverlay(); + mActivityManagerService.showSafeModeOverlay(); } // Update the configuration for this context by hand, because we're going @@ -884,7 +961,8 @@ class ServerThread { context.getResources().updateConfiguration(config, metrics); try { - power.systemReady(twilight, dreamy); + // TODO: use boot phase + mPowerManagerService.systemReady(); } catch (Throwable e) { reportWtf("making Power Manager Service ready", e); } @@ -896,13 +974,13 @@ class ServerThread { } try { - display.systemReady(safeMode, onlyCore); + // TODO: use boot phase and communicate these flags some other way + mDisplayManagerService.systemReady(safeMode, onlyCore); } catch (Throwable e) { reportWtf("making Display Manager Service ready", e); } // These are needed to propagate to the runnable below. - final Context contextF = context; final MountService mountServiceF = mountService; final BatteryService batteryF = battery; final NetworkManagementService networkManagementF = networkManagement; @@ -910,10 +988,6 @@ class ServerThread { final NetworkPolicyManagerService networkPolicyF = networkPolicy; final ConnectivityService connectivityF = connectivity; final DockObserver dockF = dock; - final UsbService usbF = usb; - final TwilightService twilightF = twilight; - final UiModeManagerService uiModeF = uiMode; - final AppWidgetService appWidgetF = appWidget; final WallpaperManagerService wallpaperF = wallpaper; final InputMethodManagerService immF = imm; final RecognitionManagerService recognitionF = recognition; @@ -923,11 +997,9 @@ class ServerThread { final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService; final TextServicesManagerService textServiceManagerServiceF = tsms; final StatusBarManagerService statusBarF = statusBar; - final DreamManagerService dreamyF = dreamy; final AssetAtlasService atlasF = atlas; final InputManagerService inputManagerF = inputManager; final TelephonyRegistry telephonyRegistryF = telephonyRegistry; - final PrintManagerService printManagerF = printManager; final MediaRouterService mediaRouterF = mediaRouter; // We now tell the activity manager it is okay to run third party @@ -935,17 +1007,22 @@ class ServerThread { // where third party code can really run (but before it has actually // started launching the initial applications), for us to complete our // initialization. - ActivityManagerService.self().systemReady(new Runnable() { + mActivityManagerService.systemReady(new Runnable() { + @Override public void run() { Slog.i(TAG, "Making services ready"); + mSystemServiceManager.startBootPhase( + SystemService.PHASE_ACTIVITY_MANAGER_READY); try { - ActivityManagerService.self().startObservingNativeCrashes(); + mActivityManagerService.startObservingNativeCrashes(); } catch (Throwable e) { reportWtf("observing native crashes", e); } - if (!headless) { - startSystemUi(contextF); + try { + startSystemUi(context); + } catch (Throwable e) { + reportWtf("starting System UI", e); } try { if (mountServiceF != null) mountServiceF.systemReady(); @@ -983,21 +1060,6 @@ class ServerThread { reportWtf("making Dock Service ready", e); } try { - if (usbF != null) usbF.systemReady(); - } catch (Throwable e) { - reportWtf("making USB Service ready", e); - } - try { - if (twilightF != null) twilightF.systemReady(); - } catch (Throwable e) { - reportWtf("makin Twilight Service ready", e); - } - try { - if (uiModeF != null) uiModeF.systemReady(); - } catch (Throwable e) { - reportWtf("making UI Mode Service ready", e); - } - try { if (recognitionF != null) recognitionF.systemReady(); } catch (Throwable e) { reportWtf("making Recognition Service ready", e); @@ -1006,13 +1068,10 @@ class ServerThread { // It is now okay to let the various system services start their // third party code... + mSystemServiceManager.startBootPhase( + SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); try { - if (appWidgetF != null) appWidgetF.systemRunning(safeMode); - } catch (Throwable e) { - reportWtf("Notifying AppWidgetService running", e); - } - try { if (wallpaperF != null) wallpaperF.systemRunning(); } catch (Throwable e) { reportWtf("Notifying WallpaperService running", e); @@ -1038,7 +1097,9 @@ class ServerThread { reportWtf("Notifying NetworkTimeService running", e); } try { - if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemRunning(); + if (commonTimeMgmtServiceF != null) { + commonTimeMgmtServiceF.systemRunning(); + } } catch (Throwable e) { reportWtf("Notifying CommonTimeManagementService running", e); } @@ -1049,11 +1110,6 @@ class ServerThread { reportWtf("Notifying TextServicesManagerService running", e); } try { - if (dreamyF != null) dreamyF.systemRunning(); - } catch (Throwable e) { - reportWtf("Notifying DreamManagerService running", e); - } - try { if (atlasF != null) atlasF.systemRunning(); } catch (Throwable e) { reportWtf("Notifying AssetAtlasService running", e); @@ -1064,34 +1120,20 @@ class ServerThread { } catch (Throwable e) { reportWtf("Notifying InputManagerService running", e); } - try { if (telephonyRegistryF != null) telephonyRegistryF.systemRunning(); } catch (Throwable e) { reportWtf("Notifying TelephonyRegistry running", e); } - - try { - if (printManagerF != null) printManagerF.systemRuning(); - } catch (Throwable e) { - reportWtf("Notifying PrintManagerService running", e); - } - try { if (mediaRouterF != null) mediaRouterF.systemRunning(); } catch (Throwable e) { reportWtf("Notifying MediaRouterService running", e); } + + mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETE); } }); - - // For debug builds, log event loop stalls to dropbox for analysis. - if (StrictMode.conditionallyEnableDebugLogging()) { - Slog.i(TAG, "Enabled StrictMode for system server main thread."); - } - - Looper.loop(); - Slog.d(TAG, "System ServerThread is exiting!"); } static final void startSystemUi(Context context) { @@ -1102,80 +1144,3 @@ class ServerThread { context.startServiceAsUser(intent, UserHandle.OWNER); } } - -public class SystemServer { - private static final String TAG = "SystemServer"; - - public static final int FACTORY_TEST_OFF = 0; - public static final int FACTORY_TEST_LOW_LEVEL = 1; - public static final int FACTORY_TEST_HIGH_LEVEL = 2; - - static Timer timer; - static final long SNAPSHOT_INTERVAL = 60 * 60 * 1000; // 1hr - - // The earliest supported time. We pick one day into 1970, to - // give any timezone code room without going into negative time. - private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000; - - /** - * Called to initialize native system services. - */ - private static native void nativeInit(); - - public static void main(String[] args) { - - /* - * In case the runtime switched since last boot (such as when - * the old runtime was removed in an OTA), set the system - * property so that it is in sync. We can't do this in - * libnativehelper's JniInvocation::Init code where we already - * had to fallback to a different runtime because it is - * running as root and we need to be the system user to set - * the property. http://b/11463182 - */ - SystemProperties.set("persist.sys.dalvik.vm.lib", - VMRuntime.getRuntime().vmLibrary()); - - if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) { - // If a device's clock is before 1970 (before 0), a lot of - // APIs crash dealing with negative numbers, notably - // java.io.File#setLastModified, so instead we fake it and - // hope that time from cell towers or NTP fixes it - // shortly. - Slog.w(TAG, "System clock is before 1970; setting to 1970."); - SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); - } - - if (SamplingProfilerIntegration.isEnabled()) { - SamplingProfilerIntegration.start(); - timer = new Timer(); - timer.schedule(new TimerTask() { - @Override - public void run() { - SamplingProfilerIntegration.writeSnapshot("system_server", null); - } - }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL); - } - - // Mmmmmm... more memory! - dalvik.system.VMRuntime.getRuntime().clearGrowthLimit(); - - // The system server has to run all of the time, so it needs to be - // as efficient as possible with its memory usage. - VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); - - Environment.setUserRequired(true); - - System.loadLibrary("android_servers"); - - Slog.i(TAG, "Entered the Android system server!"); - - // Initialize native services. - nativeInit(); - - // This used to be its own separate thread, but now it is - // just the loop we run on the main thread. - ServerThread thr = new ServerThread(); - thr.initAndLoop(); - } -} diff --git a/services/java/com/android/server/display/DisplayViewport.java b/services/java/com/android/server/display/DisplayViewport.java deleted file mode 100644 index 5080556..0000000 --- a/services/java/com/android/server/display/DisplayViewport.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package com.android.server.display; - -import android.graphics.Rect; - -/** - * Describes how the pixels of physical display device reflects the content of - * a logical display. - * <p> - * This information is used by the input system to translate touch input from - * physical display coordinates into logical display coordinates. - * </p> - */ -public final class DisplayViewport { - // True if this viewport is valid. - public boolean valid; - - // The logical display id. - public int displayId; - - // The rotation applied to the physical coordinate system. - public int orientation; - - // The portion of the logical display that are presented on this physical display. - public final Rect logicalFrame = new Rect(); - - // The portion of the (rotated) physical display that shows the logical display contents. - // The relation between logical and physical frame defines how the coordinate system - // should be scaled or translated after rotation. - public final Rect physicalFrame = new Rect(); - - // The full width and height of the display device, rotated in the same - // manner as physicalFrame. This expresses the full native size of the display device. - // The physical frame should usually fit within this area. - public int deviceWidth; - public int deviceHeight; - - public void copyFrom(DisplayViewport viewport) { - valid = viewport.valid; - displayId = viewport.displayId; - orientation = viewport.orientation; - logicalFrame.set(viewport.logicalFrame); - physicalFrame.set(viewport.physicalFrame); - deviceWidth = viewport.deviceWidth; - deviceHeight = viewport.deviceHeight; - } - - // For debugging purposes. - @Override - public String toString() { - return "DisplayViewport{valid=" + valid - + ", displayId=" + displayId - + ", orientation=" + orientation - + ", logicalFrame=" + logicalFrame - + ", physicalFrame=" + physicalFrame - + ", deviceWidth=" + deviceWidth - + ", deviceHeight=" + deviceHeight - + "}"; - } -} diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java deleted file mode 100644 index 7a104d7..0000000 --- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package com.android.server.display; - -import android.content.Context; -import android.os.Handler; -import android.util.DisplayMetrics; -import android.view.Display; - -/** - * Provides a fake default display for headless systems. - * <p> - * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock. - * </p> - */ -final class HeadlessDisplayAdapter extends DisplayAdapter { - private static final String TAG = "HeadlessDisplayAdapter"; - - // Called with SyncRoot lock held. - public HeadlessDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, - Context context, Handler handler, Listener listener) { - super(syncRoot, context, handler, listener, TAG); - } - - @Override - public void registerLocked() { - super.registerLocked(); - sendDisplayDeviceEventLocked(new HeadlessDisplayDevice(), DISPLAY_DEVICE_EVENT_ADDED); - } - - private final class HeadlessDisplayDevice extends DisplayDevice { - private DisplayDeviceInfo mInfo; - - public HeadlessDisplayDevice() { - super(HeadlessDisplayAdapter.this, null); - } - - @Override - public DisplayDeviceInfo getDisplayDeviceInfoLocked() { - if (mInfo == null) { - mInfo = new DisplayDeviceInfo(); - mInfo.name = getContext().getResources().getString( - com.android.internal.R.string.display_manager_built_in_display_name); - mInfo.width = 640; - mInfo.height = 480; - mInfo.refreshRate = 60; - mInfo.densityDpi = DisplayMetrics.DENSITY_DEFAULT; - mInfo.xDpi = 160; - mInfo.yDpi = 160; - mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY - | DisplayDeviceInfo.FLAG_SECURE - | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; - mInfo.type = Display.TYPE_BUILT_IN; - mInfo.touch = DisplayDeviceInfo.TOUCH_NONE; - } - return mInfo; - } - } -} diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java deleted file mode 100644 index b6e7781..0000000 --- a/services/java/com/android/server/dreams/DreamManagerService.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package com.android.server.dreams; - -import com.android.internal.util.DumpUtils; - -import android.app.ActivityManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Binder; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.PowerManager; -import android.os.SystemClock; -import android.os.UserHandle; -import android.provider.Settings; -import android.service.dreams.IDreamManager; -import android.util.Slog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; - -import libcore.util.Objects; - -/** - * Service api for managing dreams. - * - * @hide - */ -public final class DreamManagerService extends IDreamManager.Stub { - private static final boolean DEBUG = false; - private static final String TAG = "DreamManagerService"; - - private final Object mLock = new Object(); - - private final Context mContext; - private final DreamHandler mHandler; - private final DreamController mController; - private final PowerManager mPowerManager; - - private Binder mCurrentDreamToken; - private ComponentName mCurrentDreamName; - private int mCurrentDreamUserId; - private boolean mCurrentDreamIsTest; - - public DreamManagerService(Context context, Handler mainHandler) { - mContext = context; - mHandler = new DreamHandler(mainHandler.getLooper()); - mController = new DreamController(context, mHandler, mControllerListener); - - mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - } - - public void systemRunning() { - mContext.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - synchronized (mLock) { - stopDreamLocked(); - } - } - }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission("android.permission.DUMP") - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump DreamManager from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - pw.println("DREAM MANAGER (dumpsys dreams)"); - pw.println(); - - pw.println("mCurrentDreamToken=" + mCurrentDreamToken); - pw.println("mCurrentDreamName=" + mCurrentDreamName); - pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId); - pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest); - pw.println(); - - DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() { - @Override - public void dump(PrintWriter pw) { - mController.dump(pw); - } - }, pw, 200); - } - - @Override // Binder call - public ComponentName[] getDreamComponents() { - checkPermission(android.Manifest.permission.READ_DREAM_STATE); - - final int userId = UserHandle.getCallingUserId(); - final long ident = Binder.clearCallingIdentity(); - try { - return getDreamComponentsForUser(userId); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - @Override // Binder call - public void setDreamComponents(ComponentName[] componentNames) { - checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); - - final int userId = UserHandle.getCallingUserId(); - final long ident = Binder.clearCallingIdentity(); - try { - Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.SCREENSAVER_COMPONENTS, - componentsToString(componentNames), - userId); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - @Override // Binder call - public ComponentName getDefaultDreamComponent() { - checkPermission(android.Manifest.permission.READ_DREAM_STATE); - - final int userId = UserHandle.getCallingUserId(); - final long ident = Binder.clearCallingIdentity(); - try { - String name = Settings.Secure.getStringForUser(mContext.getContentResolver(), - Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT, - userId); - return name == null ? null : ComponentName.unflattenFromString(name); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - @Override // Binder call - public boolean isDreaming() { - checkPermission(android.Manifest.permission.READ_DREAM_STATE); - - synchronized (mLock) { - return mCurrentDreamToken != null && !mCurrentDreamIsTest; - } - } - - @Override // Binder call - public void dream() { - checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); - - final long ident = Binder.clearCallingIdentity(); - try { - // Ask the power manager to nap. It will eventually call back into - // startDream() if/when it is appropriate to start dreaming. - // Because napping could cause the screen to turn off immediately if the dream - // cannot be started, we keep one eye open and gently poke user activity. - long time = SystemClock.uptimeMillis(); - mPowerManager.userActivity(time, true /*noChangeLights*/); - mPowerManager.nap(time); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - @Override // Binder call - public void testDream(ComponentName dream) { - checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); - - if (dream == null) { - throw new IllegalArgumentException("dream must not be null"); - } - - final int callingUserId = UserHandle.getCallingUserId(); - final int currentUserId = ActivityManager.getCurrentUser(); - if (callingUserId != currentUserId) { - // This check is inherently prone to races but at least it's something. - Slog.w(TAG, "Aborted attempt to start a test dream while a different " - + " user is active: callingUserId=" + callingUserId - + ", currentUserId=" + currentUserId); - return; - } - final long ident = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - startDreamLocked(dream, true /*isTest*/, callingUserId); - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - @Override // Binder call - public void awaken() { - checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); - - final long ident = Binder.clearCallingIdentity(); - try { - // Treat an explicit request to awaken as user activity so that the - // device doesn't immediately go to sleep if the timeout expired, - // for example when being undocked. - long time = SystemClock.uptimeMillis(); - mPowerManager.userActivity(time, false /*noChangeLights*/); - stopDream(); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - @Override // Binder call - public void finishSelf(IBinder token) { - // Requires no permission, called by Dream from an arbitrary process. - if (token == null) { - throw new IllegalArgumentException("token must not be null"); - } - - final long ident = Binder.clearCallingIdentity(); - try { - if (DEBUG) { - Slog.d(TAG, "Dream finished: " + token); - } - - // Note that a dream finishing and self-terminating is not - // itself considered user activity. If the dream is ending because - // the user interacted with the device then user activity will already - // have been poked so the device will stay awake a bit longer. - // If the dream is ending on its own for other reasons and no wake - // locks are held and the user activity timeout has expired then the - // device may simply go to sleep. - synchronized (mLock) { - if (mCurrentDreamToken == token) { - stopDreamLocked(); - } - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - /** - * Called by the power manager to start a dream. - */ - public void startDream() { - int userId = ActivityManager.getCurrentUser(); - ComponentName dream = chooseDreamForUser(userId); - if (dream != null) { - synchronized (mLock) { - startDreamLocked(dream, false /*isTest*/, userId); - } - } - } - - /** - * Called by the power manager to stop a dream. - */ - public void stopDream() { - synchronized (mLock) { - stopDreamLocked(); - } - } - - private ComponentName chooseDreamForUser(int userId) { - ComponentName[] dreams = getDreamComponentsForUser(userId); - return dreams != null && dreams.length != 0 ? dreams[0] : null; - } - - private ComponentName[] getDreamComponentsForUser(int userId) { - String names = Settings.Secure.getStringForUser(mContext.getContentResolver(), - Settings.Secure.SCREENSAVER_COMPONENTS, - userId); - ComponentName[] components = componentsFromString(names); - - // first, ensure components point to valid services - List<ComponentName> validComponents = new ArrayList<ComponentName>(); - if (components != null) { - for (ComponentName component : components) { - if (serviceExists(component)) { - validComponents.add(component); - } else { - Slog.w(TAG, "Dream " + component + " does not exist"); - } - } - } - - // fallback to the default dream component if necessary - if (validComponents.isEmpty()) { - ComponentName defaultDream = getDefaultDreamComponent(); - if (defaultDream != null) { - Slog.w(TAG, "Falling back to default dream " + defaultDream); - validComponents.add(defaultDream); - } - } - return validComponents.toArray(new ComponentName[validComponents.size()]); - } - - private boolean serviceExists(ComponentName name) { - try { - return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null; - } catch (NameNotFoundException e) { - return false; - } - } - - private void startDreamLocked(final ComponentName name, - final boolean isTest, final int userId) { - if (Objects.equal(mCurrentDreamName, name) - && mCurrentDreamIsTest == isTest - && mCurrentDreamUserId == userId) { - return; - } - - stopDreamLocked(); - - if (DEBUG) Slog.i(TAG, "Entering dreamland."); - - final Binder newToken = new Binder(); - mCurrentDreamToken = newToken; - mCurrentDreamName = name; - mCurrentDreamIsTest = isTest; - mCurrentDreamUserId = userId; - - mHandler.post(new Runnable() { - @Override - public void run() { - mController.startDream(newToken, name, isTest, userId); - } - }); - } - - private void stopDreamLocked() { - if (mCurrentDreamToken != null) { - if (DEBUG) Slog.i(TAG, "Leaving dreamland."); - - cleanupDreamLocked(); - - mHandler.post(new Runnable() { - @Override - public void run() { - mController.stopDream(); - } - }); - } - } - - private void cleanupDreamLocked() { - mCurrentDreamToken = null; - mCurrentDreamName = null; - mCurrentDreamIsTest = false; - mCurrentDreamUserId = 0; - } - - private void checkPermission(String permission) { - if (mContext.checkCallingOrSelfPermission(permission) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Access denied to process: " + Binder.getCallingPid() - + ", must have permission " + permission); - } - } - - private static String componentsToString(ComponentName[] componentNames) { - StringBuilder names = new StringBuilder(); - if (componentNames != null) { - for (ComponentName componentName : componentNames) { - if (names.length() > 0) { - names.append(','); - } - names.append(componentName.flattenToString()); - } - } - return names.toString(); - } - - private static ComponentName[] componentsFromString(String names) { - if (names == null) { - return null; - } - String[] namesArray = names.split(","); - ComponentName[] componentNames = new ComponentName[namesArray.length]; - for (int i = 0; i < namesArray.length; i++) { - componentNames[i] = ComponentName.unflattenFromString(namesArray[i]); - } - return componentNames; - } - - private final DreamController.Listener mControllerListener = new DreamController.Listener() { - @Override - public void onDreamStopped(Binder token) { - synchronized (mLock) { - if (mCurrentDreamToken == token) { - cleanupDreamLocked(); - } - } - } - }; - - /** - * Handler for asynchronous operations performed by the dream manager. - * Ensures operations to {@link DreamController} are single-threaded. - */ - private final class DreamHandler extends Handler { - public DreamHandler(Looper looper) { - super(looper, null, true /*async*/); - } - } -} diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/java/com/android/server/power/DisplayPowerRequest.java deleted file mode 100644 index 22f17d7..0000000 --- a/services/java/com/android/server/power/DisplayPowerRequest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package com.android.server.power; - -import android.os.PowerManager; - -/** - * Describes the requested power state of the display. - * - * This object is intended to describe the general characteristics of the - * power state, such as whether the screen should be on or off and the current - * brightness controls leaving the {@link DisplayPowerController} to manage the - * details of how the transitions between states should occur. The goal is for - * the {@link PowerManagerService} to focus on the global power state and not - * have to micro-manage screen off animations, auto-brightness and other effects. - */ -final class DisplayPowerRequest { - public static final int SCREEN_STATE_OFF = 0; - public static final int SCREEN_STATE_DIM = 1; - public static final int SCREEN_STATE_BRIGHT = 2; - - // The requested minimum screen power state: off, dim or bright. - public int screenState; - - // If true, the proximity sensor overrides the screen state when an object is - // nearby, turning it off temporarily until the object is moved away. - public boolean useProximitySensor; - - // The desired screen brightness in the range 0 (minimum / off) to 255 (brightest). - // The display power controller may choose to clamp the brightness. - // When auto-brightness is enabled, this field should specify a nominal default - // value to use while waiting for the light sensor to report enough data. - public int screenBrightness; - - // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter). - public float screenAutoBrightnessAdjustment; - - // If true, enables automatic brightness control. - public boolean useAutoBrightness; - - // If true, prevents the screen from completely turning on if it is currently off. - // The display does not enter a "ready" state if this flag is true and screen on is - // blocked. The window manager policy blocks screen on while it prepares the keyguard to - // prevent the user from seeing intermediate updates. - // - // Technically, we may not block the screen itself from turning on (because that introduces - // extra unnecessary latency) but we do prevent content on screen from becoming - // visible to the user. - public boolean blockScreenOn; - - public DisplayPowerRequest() { - screenState = SCREEN_STATE_BRIGHT; - useProximitySensor = false; - screenBrightness = PowerManager.BRIGHTNESS_ON; - screenAutoBrightnessAdjustment = 0.0f; - useAutoBrightness = false; - blockScreenOn = false; - } - - public DisplayPowerRequest(DisplayPowerRequest other) { - copyFrom(other); - } - - public void copyFrom(DisplayPowerRequest other) { - screenState = other.screenState; - useProximitySensor = other.useProximitySensor; - screenBrightness = other.screenBrightness; - screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment; - useAutoBrightness = other.useAutoBrightness; - blockScreenOn = other.blockScreenOn; - } - - @Override - public boolean equals(Object o) { - return o instanceof DisplayPowerRequest - && equals((DisplayPowerRequest)o); - } - - public boolean equals(DisplayPowerRequest other) { - return other != null - && screenState == other.screenState - && useProximitySensor == other.useProximitySensor - && screenBrightness == other.screenBrightness - && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment - && useAutoBrightness == other.useAutoBrightness - && blockScreenOn == other.blockScreenOn; - } - - @Override - public int hashCode() { - return 0; // don't care - } - - @Override - public String toString() { - return "screenState=" + screenState - + ", useProximitySensor=" + useProximitySensor - + ", screenBrightness=" + screenBrightness - + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment - + ", useAutoBrightness=" + useAutoBrightness - + ", blockScreenOn=" + blockScreenOn; - } -} diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java deleted file mode 100644 index 98acc27..0000000 --- a/services/java/com/android/server/print/PrintManagerService.java +++ /dev/null @@ -1,656 +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.server.print; - -import android.Manifest; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.Binder; -import android.os.Bundle; -import android.os.Process; -import android.os.RemoteException; -import android.os.UserHandle; -import android.print.IPrintDocumentAdapter; -import android.print.IPrintJobStateChangeListener; -import android.print.IPrintManager; -import android.print.IPrinterDiscoveryObserver; -import android.print.PrintAttributes; -import android.print.PrintJobId; -import android.print.PrintJobInfo; -import android.print.PrinterId; -import android.printservice.PrintServiceInfo; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.SparseArray; - -import com.android.internal.R; -import com.android.internal.content.PackageMonitor; -import com.android.internal.os.BackgroundThread; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -public final class PrintManagerService extends IPrintManager.Stub { - - private static final char COMPONENT_NAME_SEPARATOR = ':'; - - private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME = - "EXTRA_PRINT_SERVICE_COMPONENT_NAME"; - - private final Object mLock = new Object(); - - private final Context mContext; - - private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); - - private int mCurrentUserId = UserHandle.USER_OWNER; - - public PrintManagerService(Context context) { - mContext = context; - registerContentObservers(); - registerBoradcastReceivers(); - } - - public void systemRuning() { - BackgroundThread.getHandler().post(new Runnable() { - @Override - public void run() { - final UserState userState; - synchronized (mLock) { - userState = getCurrentUserStateLocked(); - userState.updateIfNeededLocked(); - } - // This is the first time we switch to this user after boot, so - // now is the time to remove obsolete print jobs since they - // are from the last boot and no application would query them. - userState.removeObsoletePrintJobs(); - } - }); - } - - @Override - public Bundle print(String printJobName, IPrintDocumentAdapter adapter, - PrintAttributes attributes, String packageName, int appId, int userId) { - final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - return userState.print(printJobName, adapter, attributes, - resolvedPackageName, resolvedAppId); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) { - final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - return userState.getPrintJobInfos(resolvedAppId); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) { - final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - return userState.getPrintJobInfo(printJobId, resolvedAppId); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) { - final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.cancelPrintJob(printJobId, resolvedAppId); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void restartPrintJob(PrintJobId printJobId, int appId, int userId) { - final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.restartPrintJob(printJobId, resolvedAppId); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public List<PrintServiceInfo> getEnabledPrintServices(int userId) { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - return userState.getEnabledPrintServices(); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public List<PrintServiceInfo> getInstalledPrintServices(int userId) { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - return userState.getInstalledPrintServices(); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer, - int userId) { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.createPrinterDiscoverySession(observer); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer, - int userId) { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.destroyPrinterDiscoverySession(observer); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void startPrinterDiscovery(IPrinterDiscoveryObserver observer, - List<PrinterId> priorityList, int userId) { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.startPrinterDiscovery(observer, priorityList); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.stopPrinterDiscovery(observer); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void validatePrinters(List<PrinterId> printerIds, int userId) { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.validatePrinters(printerIds); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void startPrinterStateTracking(PrinterId printerId, int userId) { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.startPrinterStateTracking(printerId); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void stopPrinterStateTracking(PrinterId printerId, int userId) { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.stopPrinterStateTracking(printerId); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener, - int appId, int userId) throws RemoteException { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.addPrintJobStateChangeListener(listener, resolvedAppId); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener, - int userId) { - final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); - final UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(resolvedUserId); - } - final long identity = Binder.clearCallingIdentity(); - try { - userState.removePrintJobStateChangeListener(listener); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump PrintManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - synchronized (mLock) { - final long identity = Binder.clearCallingIdentity(); - try { - pw.println("PRINT MANAGER STATE (dumpsys print)"); - final int userStateCount = mUserStates.size(); - for (int i = 0; i < userStateCount; i++) { - UserState userState = mUserStates.valueAt(i); - userState.dump(fd, pw, ""); - pw.println(); - } - } finally { - Binder.restoreCallingIdentity(identity); - } - } - } - - private void registerContentObservers() { - final Uri enabledPrintServicesUri = Settings.Secure.getUriFor( - Settings.Secure.ENABLED_PRINT_SERVICES); - - ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) { - @Override - public void onChange(boolean selfChange, Uri uri) { - if (enabledPrintServicesUri.equals(uri)) { - synchronized (mLock) { - UserState userState = getCurrentUserStateLocked(); - userState.updateIfNeededLocked(); - } - } - } - }; - - mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri, - false, observer, UserHandle.USER_ALL); - } - - private void registerBoradcastReceivers() { - PackageMonitor monitor = new PackageMonitor() { - @Override - public boolean onPackageChanged(String packageName, int uid, String[] components) { - synchronized (mLock) { - UserState userState = getOrCreateUserStateLocked(getChangingUserId()); - Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); - while (iterator.hasNext()) { - ComponentName componentName = iterator.next(); - if (packageName.equals(componentName.getPackageName())) { - userState.updateIfNeededLocked(); - return true; - } - } - } - return false; - } - - @Override - public void onPackageRemoved(String packageName, int uid) { - synchronized (mLock) { - UserState userState = getOrCreateUserStateLocked(getChangingUserId()); - Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); - while (iterator.hasNext()) { - ComponentName componentName = iterator.next(); - if (packageName.equals(componentName.getPackageName())) { - iterator.remove(); - persistComponentNamesToSettingLocked( - Settings.Secure.ENABLED_PRINT_SERVICES, - userState.getEnabledServices(), getChangingUserId()); - userState.updateIfNeededLocked(); - return; - } - } - } - } - - @Override - public boolean onHandleForceStop(Intent intent, String[] stoppedPackages, - int uid, boolean doit) { - synchronized (mLock) { - UserState userState = getOrCreateUserStateLocked(getChangingUserId()); - boolean stoppedSomePackages = false; - Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); - while (iterator.hasNext()) { - ComponentName componentName = iterator.next(); - String componentPackage = componentName.getPackageName(); - for (String stoppedPackage : stoppedPackages) { - if (componentPackage.equals(stoppedPackage)) { - if (!doit) { - return true; - } - stoppedSomePackages = true; - break; - } - } - } - if (stoppedSomePackages) { - userState.updateIfNeededLocked(); - } - return false; - } - } - - @Override - public void onPackageAdded(String packageName, int uid) { - Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE); - intent.setPackage(packageName); - - List<ResolveInfo> installedServices = mContext.getPackageManager() - .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES, - getChangingUserId()); - - if (installedServices == null) { - return; - } - - final int installedServiceCount = installedServices.size(); - for (int i = 0; i < installedServiceCount; i++) { - ServiceInfo serviceInfo = installedServices.get(i).serviceInfo; - ComponentName component = new ComponentName(serviceInfo.packageName, - serviceInfo.name); - String label = serviceInfo.loadLabel(mContext.getPackageManager()).toString(); - showEnableInstalledPrintServiceNotification(component, label, - getChangingUserId()); - } - } - - private void persistComponentNamesToSettingLocked(String settingName, - Set<ComponentName> componentNames, int userId) { - StringBuilder builder = new StringBuilder(); - for (ComponentName componentName : componentNames) { - if (builder.length() > 0) { - builder.append(COMPONENT_NAME_SEPARATOR); - } - builder.append(componentName.flattenToShortString()); - } - Settings.Secure.putStringForUser(mContext.getContentResolver(), - settingName, builder.toString(), userId); - } - }; - - // package changes - monitor.register(mContext, BackgroundThread.getHandler().getLooper(), - UserHandle.ALL, true); - - // user changes - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_USER_SWITCHED); - intentFilter.addAction(Intent.ACTION_USER_REMOVED); - - mContext.registerReceiverAsUser(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_USER_SWITCHED.equals(action)) { - switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); - } else if (Intent.ACTION_USER_REMOVED.equals(action)) { - removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); - } - } - }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler()); - } - - private UserState getCurrentUserStateLocked() { - return getOrCreateUserStateLocked(mCurrentUserId); - } - - private UserState getOrCreateUserStateLocked(int userId) { - UserState userState = mUserStates.get(userId); - if (userState == null) { - userState = new UserState(mContext, userId, mLock); - mUserStates.put(userId, userState); - } - return userState; - } - - private void switchUser(int newUserId) { - UserState userState; - synchronized (mLock) { - if (newUserId == mCurrentUserId) { - return; - } - mCurrentUserId = newUserId; - userState = mUserStates.get(mCurrentUserId); - if (userState == null) { - userState = getCurrentUserStateLocked(); - userState.updateIfNeededLocked(); - } else { - userState.updateIfNeededLocked(); - } - } - // This is the first time we switch to this user after boot, so - // now is the time to remove obsolete print jobs since they - // are from the last boot and no application would query them. - userState.removeObsoletePrintJobs(); - } - - private void removeUser(int removedUserId) { - synchronized (mLock) { - UserState userState = mUserStates.get(removedUserId); - if (userState != null) { - userState.destroyLocked(); - mUserStates.remove(removedUserId); - } - } - } - - private int resolveCallingAppEnforcingPermissions(int appId) { - final int callingUid = Binder.getCallingUid(); - if (callingUid == 0 || callingUid == Process.SYSTEM_UID - || callingUid == Process.SHELL_UID) { - return appId; - } - final int callingAppId = UserHandle.getAppId(callingUid); - if (appId == callingAppId) { - return appId; - } - if (mContext.checkCallingPermission( - "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS") - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Call from app " + callingAppId + " as app " - + appId + " without com.android.printspooler.permission" - + ".ACCESS_ALL_PRINT_JOBS"); - } - return appId; - } - - private int resolveCallingUserEnforcingPermissions(int userId) { - final int callingUid = Binder.getCallingUid(); - if (callingUid == 0 || callingUid == Process.SYSTEM_UID - || callingUid == Process.SHELL_UID) { - return userId; - } - final int callingUserId = UserHandle.getUserId(callingUid); - if (callingUserId == userId) { - return userId; - } - if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL) - != PackageManager.PERMISSION_GRANTED - || mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS) - != PackageManager.PERMISSION_GRANTED) { - if (userId == UserHandle.USER_CURRENT_OR_SELF) { - return callingUserId; - } - throw new SecurityException("Call from user " + callingUserId + " as user " - + userId + " without permission INTERACT_ACROSS_USERS or " - + "INTERACT_ACROSS_USERS_FULL not allowed."); - } - if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) { - return mCurrentUserId; - } - throw new IllegalArgumentException("Calling user can be changed to only " - + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF."); - } - - private String resolveCallingPackageNameEnforcingSecurity(String packageName) { - if (TextUtils.isEmpty(packageName)) { - return null; - } - String[] packages = mContext.getPackageManager().getPackagesForUid( - Binder.getCallingUid()); - final int packageCount = packages.length; - for (int i = 0; i < packageCount; i++) { - if (packageName.equals(packages[i])) { - return packageName; - } - } - return null; - } - - private void showEnableInstalledPrintServiceNotification(ComponentName component, - String label, int userId) { - UserHandle userHandle = new UserHandle(userId); - - Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); - intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString()); - - PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent, - PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null, userHandle); - - Notification.Builder builder = new Notification.Builder(mContext) - .setSmallIcon(R.drawable.ic_print) - .setContentTitle(mContext.getString(R.string.print_service_installed_title, label)) - .setContentText(mContext.getString(R.string.print_service_installed_message)) - .setContentIntent(pendingIntent) - .setWhen(System.currentTimeMillis()) - .setAutoCancel(true) - .setShowWhen(true); - - NotificationManager notificationManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); - - String notificationTag = getClass().getName() + ":" + component.flattenToString(); - notificationManager.notifyAsUser(notificationTag, 0, builder.build(), - userHandle); - } -} diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java deleted file mode 100644 index d358b4c..0000000 --- a/services/java/com/android/server/wm/DisplayContent.java +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package com.android.server.wm; - -import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; -import static com.android.server.wm.WindowManagerService.DEBUG_STACK; -import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; -import static com.android.server.wm.WindowManagerService.TAG; - -import android.app.ActivityManager.StackBoxInfo; -import android.graphics.Rect; -import android.graphics.Region; -import android.os.Debug; -import android.util.EventLog; -import android.util.Slog; -import android.view.Display; -import android.view.DisplayInfo; -import com.android.server.EventLogTags; - -import java.io.PrintWriter; -import java.util.ArrayList; - -class DisplayContentList extends ArrayList<DisplayContent> { -} - -/** - * Utility class for keeping track of the WindowStates and other pertinent contents of a - * particular Display. - * - * IMPORTANT: No method from this class should ever be used without holding - * WindowManagerService.mWindowMap. - */ -class DisplayContent { - - /** Unique identifier of this stack. */ - private final int mDisplayId; - - /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element - * from mDisplayWindows; */ - private WindowList mWindows = new WindowList(); - - // This protects the following display size properties, so that - // getDisplaySize() doesn't need to acquire the global lock. This is - // needed because the window manager sometimes needs to use ActivityThread - // while it has its global state locked (for example to load animation - // resources), but the ActivityThread also needs get the current display - // size sometimes when it has its package lock held. - // - // These will only be modified with both mWindowMap and mDisplaySizeLock - // held (in that order) so the window manager doesn't need to acquire this - // lock when needing these values in its normal operation. - final Object mDisplaySizeLock = new Object(); - int mInitialDisplayWidth = 0; - int mInitialDisplayHeight = 0; - int mInitialDisplayDensity = 0; - int mBaseDisplayWidth = 0; - int mBaseDisplayHeight = 0; - int mBaseDisplayDensity = 0; - private final DisplayInfo mDisplayInfo = new DisplayInfo(); - private final Display mDisplay; - - Rect mBaseDisplayRect = new Rect(); - - // Accessed directly by all users. - boolean layoutNeeded; - int pendingLayoutChanges; - final boolean isDefaultDisplay; - - /** - * Window tokens that are in the process of exiting, but still - * on screen for animations. - */ - final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>(); - - /** - * Application tokens that are in the process of exiting, but still - * on screen for animations. - */ - final AppTokenList mExitingAppTokens = new AppTokenList(); - - /** Array containing the home StackBox and possibly one more which would contain apps. Array - * is stored in display order with the current bottom stack at 0. */ - private ArrayList<StackBox> mStackBoxes = new ArrayList<StackBox>(); - - /** True when the home StackBox is at the top of mStackBoxes, false otherwise. */ - private TaskStack mHomeStack = null; - - /** Detect user tapping outside of current focused stack bounds .*/ - StackTapPointerEventListener mTapDetector; - - /** Detect user tapping outside of current focused stack bounds .*/ - Region mTouchExcludeRegion = new Region(); - - /** Save allocating when retrieving tasks */ - private ArrayList<Task> mTaskHistory = new ArrayList<Task>(); - - /** Save allocating when calculating rects */ - Rect mTmpRect = new Rect(); - - final WindowManagerService mService; - - /** - * @param display May not be null. - * @param service TODO(cmautner): - */ - DisplayContent(Display display, WindowManagerService service) { - mDisplay = display; - mDisplayId = display.getDisplayId(); - display.getDisplayInfo(mDisplayInfo); - isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY; - mService = service; - - StackBox newBox = new StackBox(service, this, null); - mStackBoxes.add(newBox); - TaskStack newStack = new TaskStack(service, HOME_STACK_ID, this); - newStack.mStackBox = newBox; - newBox.mStack = newStack; - mHomeStack = newStack; - } - - int getDisplayId() { - return mDisplayId; - } - - WindowList getWindowList() { - return mWindows; - } - - Display getDisplay() { - return mDisplay; - } - - DisplayInfo getDisplayInfo() { - return mDisplayInfo; - } - - /** - * Returns true if the specified UID has access to this display. - */ - public boolean hasAccess(int uid) { - return mDisplay.hasAccess(uid); - } - - boolean homeOnTop() { - return mStackBoxes.get(0).mStack != mHomeStack; - } - - public boolean isPrivate() { - return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0; - } - - /** - * Retrieve the tasks on this display in stack order from the bottommost TaskStack up. - * @return All the Tasks, in order, on this display. - */ - ArrayList<Task> getTasks() { - return mTaskHistory; - } - - void addTask(Task task, boolean toTop) { - mTaskHistory.remove(task); - - final int userId = task.mUserId; - int taskNdx; - final int numTasks = mTaskHistory.size(); - if (toTop) { - for (taskNdx = numTasks - 1; taskNdx >= 0; --taskNdx) { - if (mTaskHistory.get(taskNdx).mUserId == userId) { - break; - } - } - ++taskNdx; - } else { - for (taskNdx = 0; taskNdx < numTasks; ++taskNdx) { - if (mTaskHistory.get(taskNdx).mUserId == userId) { - break; - } - } - } - - mTaskHistory.add(taskNdx, task); - EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx); - } - - void removeTask(Task task) { - mTaskHistory.remove(task); - } - - TaskStack getHomeStack() { - return mHomeStack; - } - - void updateDisplayInfo() { - mDisplay.getDisplayInfo(mDisplayInfo); - } - - void getLogicalDisplayRect(Rect out) { - updateDisplayInfo(); - // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked. - int width = mDisplayInfo.logicalWidth; - int left = (mBaseDisplayWidth - width) / 2; - int height = mDisplayInfo.logicalHeight; - int top = (mBaseDisplayHeight - height) / 2; - out.set(left, top, left + width, top + height); - } - - /** @return The number of tokens in all of the Tasks on this display. */ - int numTokens() { - int count = 0; - for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - count += mTaskHistory.get(taskNdx).mAppTokens.size(); - } - return count; - } - - /** Refer to {@link WindowManagerService#createStack(int, int, int, float)} */ - TaskStack createStack(int stackId, int relativeStackBoxId, int position, float weight) { - TaskStack newStack = null; - if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId + " relativeStackBoxId=" - + relativeStackBoxId + " position=" + position + " weight=" + weight); - if (stackId == HOME_STACK_ID) { - if (mStackBoxes.size() != 1) { - throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first."); - } - newStack = mHomeStack; - } else { - int stackBoxNdx; - for (stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - final StackBox box = mStackBoxes.get(stackBoxNdx); - if (position == StackBox.TASK_STACK_GOES_OVER - || position == StackBox.TASK_STACK_GOES_UNDER) { - // Position indicates a new box is added at top level only. - if (box.contains(relativeStackBoxId)) { - StackBox newBox = new StackBox(mService, this, null); - newStack = new TaskStack(mService, stackId, this); - newStack.mStackBox = newBox; - newBox.mStack = newStack; - final int offset = position == StackBox.TASK_STACK_GOES_OVER ? 1 : 0; - if (DEBUG_STACK) Slog.d(TAG, "createStack: inserting stack at " + - (stackBoxNdx + offset)); - mStackBoxes.add(stackBoxNdx + offset, newBox); - break; - } - } else { - // Remaining position values indicate a box must be split. - newStack = box.split(stackId, relativeStackBoxId, position, weight); - if (newStack != null) { - break; - } - } - } - if (stackBoxNdx < 0) { - throw new IllegalArgumentException("createStack: stackBoxId " + relativeStackBoxId - + " not found."); - } - } - if (newStack != null) { - layoutNeeded = true; - } - EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, relativeStackBoxId, position, - (int)(weight * 100 + 0.5)); - return newStack; - } - - /** Refer to {@link WindowManagerService#resizeStackBox(int, float)} */ - boolean resizeStack(int stackBoxId, float weight) { - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - final StackBox box = mStackBoxes.get(stackBoxNdx); - if (box.resize(stackBoxId, weight)) { - layoutNeeded = true; - return true; - } - } - return false; - } - - void addStackBox(StackBox box, boolean toTop) { - if (mStackBoxes.size() >= 2) { - throw new RuntimeException("addStackBox: Too many toplevel StackBoxes!"); - } - mStackBoxes.add(toTop ? mStackBoxes.size() : 0, box); - } - - void removeStackBox(StackBox box) { - if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: box=" + box); - final TaskStack stack = box.mStack; - if (stack != null && stack.mStackId == HOME_STACK_ID) { - // Never delete the home stack, even if it is empty. - if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: Not deleting home stack."); - return; - } - mStackBoxes.remove(box); - } - - StackBoxInfo getStackBoxInfo(StackBox box) { - StackBoxInfo info = new StackBoxInfo(); - info.stackBoxId = box.mStackBoxId; - info.weight = box.mWeight; - info.vertical = box.mVertical; - info.bounds = new Rect(box.mBounds); - if (box.mStack != null) { - info.stackId = box.mStack.mStackId; - // ActivityManagerService will fill in the StackInfo. - } else { - info.stackId = -1; - info.children = new StackBoxInfo[2]; - info.children[0] = getStackBoxInfo(box.mFirst); - info.children[1] = getStackBoxInfo(box.mSecond); - } - return info; - } - - ArrayList<StackBoxInfo> getStackBoxInfos() { - ArrayList<StackBoxInfo> list = new ArrayList<StackBoxInfo>(); - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - list.add(getStackBoxInfo(mStackBoxes.get(stackBoxNdx))); - } - return list; - } - - /** - * Move the home StackBox to the top or bottom of mStackBoxes. That is the only place - * it is allowed to be. This is a nop if the home StackBox is already in the correct position. - * @param toTop Move home to the top of mStackBoxes if true, to the bottom if false. - * @return true if a change was made, false otherwise. - */ - boolean moveHomeStackBox(boolean toTop) { - if (DEBUG_STACK) Slog.d(TAG, "moveHomeStackBox: toTop=" + toTop + " Callers=" + - Debug.getCallers(4)); - EventLog.writeEvent(EventLogTags.WM_HOME_STACK_MOVED, toTop ? 1 : 0); - switch (mStackBoxes.size()) { - case 0: throw new RuntimeException("moveHomeStackBox: No home StackBox!"); - case 1: return false; // Only the home StackBox exists. - case 2: - if (homeOnTop() ^ toTop) { - mStackBoxes.add(mStackBoxes.remove(0)); - return true; - } - return false; - default: throw new RuntimeException("moveHomeStackBox: Too many toplevel StackBoxes!"); - } - } - - /** - * Propagate the new bounds to all child stack boxes, applying weights as we move down. - * @param contentRect The bounds to apply at the top level. - */ - boolean setStackBoxSize(Rect contentRect) { - boolean change = false; - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - change |= mStackBoxes.get(stackBoxNdx).setStackBoxSizes(contentRect, true); - } - return change; - } - - Rect getStackBounds(int stackId) { - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - Rect bounds = mStackBoxes.get(stackBoxNdx).getStackBounds(stackId); - if (bounds != null) { - return bounds; - } - } - return null; - } - - int stackIdFromPoint(int x, int y) { - StackBox topBox = mStackBoxes.get(mStackBoxes.size() - 1); - return topBox.stackIdFromPoint(x, y); - } - - void setTouchExcludeRegion(TaskStack focusedStack) { - mTouchExcludeRegion.set(mBaseDisplayRect); - WindowList windows = getWindowList(); - for (int i = windows.size() - 1; i >= 0; --i) { - final WindowState win = windows.get(i); - final TaskStack stack = win.getStack(); - if (win.isVisibleLw() && stack != null && stack != focusedStack) { - mTmpRect.set(win.mVisibleFrame); - mTmpRect.intersect(win.mVisibleInsets); - mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE); - } - } - } - - void switchUserStacks(int oldUserId, int newUserId) { - final WindowList windows = getWindowList(); - for (int i = 0; i < windows.size(); i++) { - final WindowState win = windows.get(i); - if (win.isHiddenFromUserLocked()) { - if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding " - + win + ", attrs=" + win.mAttrs.type + ", belonging to " - + win.mOwnerUid); - win.hideLw(false); - } - } - - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - mStackBoxes.get(stackBoxNdx).switchUserStacks(newUserId); - } - } - - void resetAnimationBackgroundAnimator() { - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - mStackBoxes.get(stackBoxNdx).resetAnimationBackgroundAnimator(); - } - } - - boolean animateDimLayers() { - boolean result = false; - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - result |= mStackBoxes.get(stackBoxNdx).animateDimLayers(); - } - return result; - } - - void resetDimming() { - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - mStackBoxes.get(stackBoxNdx).resetDimming(); - } - } - - boolean isDimming() { - boolean result = false; - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - result |= mStackBoxes.get(stackBoxNdx).isDimming(); - } - return result; - } - - void stopDimmingIfNeeded() { - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - mStackBoxes.get(stackBoxNdx).stopDimmingIfNeeded(); - } - } - - void close() { - for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) { - mStackBoxes.get(stackBoxNdx).close(); - } - } - - public void dump(String prefix, PrintWriter pw) { - pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId); - final String subPrefix = " " + prefix; - pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x"); - pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity); - pw.print("dpi"); - if (mInitialDisplayWidth != mBaseDisplayWidth - || mInitialDisplayHeight != mBaseDisplayHeight - || mInitialDisplayDensity != mBaseDisplayDensity) { - pw.print(" base="); - pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight); - pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi"); - } - pw.print(" cur="); - pw.print(mDisplayInfo.logicalWidth); - pw.print("x"); pw.print(mDisplayInfo.logicalHeight); - pw.print(" app="); - pw.print(mDisplayInfo.appWidth); - pw.print("x"); pw.print(mDisplayInfo.appHeight); - pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth); - pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight); - pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth); - pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight); - pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded); - for (int boxNdx = 0; boxNdx < mStackBoxes.size(); ++boxNdx) { - pw.print(prefix); pw.print("StackBox #"); pw.println(boxNdx); - mStackBoxes.get(boxNdx).dump(prefix + " ", pw); - } - int ndx = numTokens(); - if (ndx > 0) { - pw.println(); - pw.println(" Application tokens in Z order:"); - getTasks(); - for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens; - for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { - final AppWindowToken wtoken = tokens.get(tokenNdx); - pw.print(" App #"); pw.print(ndx--); - pw.print(' '); pw.print(wtoken); pw.println(":"); - wtoken.dump(pw, " "); - } - } - } - if (mExitingTokens.size() > 0) { - pw.println(); - pw.println(" Exiting tokens:"); - for (int i=mExitingTokens.size()-1; i>=0; i--) { - WindowToken token = mExitingTokens.get(i); - pw.print(" Exiting #"); pw.print(i); - pw.print(' '); pw.print(token); - pw.println(':'); - token.dump(pw, " "); - } - } - if (mExitingAppTokens.size() > 0) { - pw.println(); - pw.println(" Exiting application tokens:"); - for (int i=mExitingAppTokens.size()-1; i>=0; i--) { - WindowToken token = mExitingAppTokens.get(i); - pw.print(" Exiting App #"); pw.print(i); - pw.print(' '); pw.print(token); - pw.println(':'); - token.dump(pw, " "); - } - } - pw.println(); - } -} diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java deleted file mode 100644 index d351925..0000000 --- a/services/java/com/android/server/wm/StackBox.java +++ /dev/null @@ -1,414 +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.server.wm; - -import android.graphics.Rect; -import android.util.Slog; - -import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; -import static com.android.server.wm.WindowManagerService.DEBUG_STACK; -import static com.android.server.wm.WindowManagerService.TAG; - -import java.io.PrintWriter; - -public class StackBox { - /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */ - public static final int TASK_STACK_GOES_BEFORE = 0; - /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */ - public static final int TASK_STACK_GOES_AFTER = 1; - /** Used with {@link WindowManagerService#createStack}. Horizontal to left of. */ - public static final int TASK_STACK_TO_LEFT_OF = 2; - /** Used with {@link WindowManagerService#createStack}. Horizontal to right of. */ - public static final int TASK_STACK_TO_RIGHT_OF = 3; - /** Used with {@link WindowManagerService#createStack}. Vertical: lower t/b Rect values. */ - public static final int TASK_STACK_GOES_ABOVE = 4; - /** Used with {@link WindowManagerService#createStack}. Vertical: higher t/b Rect values. */ - public static final int TASK_STACK_GOES_BELOW = 5; - /** Used with {@link WindowManagerService#createStack}. Put on a higher layer on display. */ - public static final int TASK_STACK_GOES_OVER = 6; - /** Used with {@link WindowManagerService#createStack}. Put on a lower layer on display. */ - public static final int TASK_STACK_GOES_UNDER = 7; - - static int sCurrentBoxId = 0; - - /** Unique id for this box */ - final int mStackBoxId; - - /** The service */ - final WindowManagerService mService; - - /** The display this box sits in. */ - final DisplayContent mDisplayContent; - - /** Non-null indicates this is mFirst or mSecond of a parent StackBox. Null indicates this - * is this entire size of mDisplayContent. */ - StackBox mParent; - - /** First child, this is null exactly when mStack is non-null. */ - StackBox mFirst; - - /** Second child, this is null exactly when mStack is non-null. */ - StackBox mSecond; - - /** Stack of Tasks, this is null exactly when mFirst and mSecond are non-null. */ - TaskStack mStack; - - /** Content limits relative to the DisplayContent this sits in. */ - Rect mBounds = new Rect(); - - /** Relative orientation of mFirst and mSecond. */ - boolean mVertical; - - /** Fraction of mBounds to devote to mFirst, remainder goes to mSecond */ - float mWeight; - - /** Dirty flag. Something inside this or some descendant of this has changed. */ - boolean layoutNeeded; - - /** True if this StackBox sits below the Status Bar. */ - boolean mUnderStatusBar; - - /** Used to keep from reallocating a temporary Rect for propagating bounds to child boxes */ - Rect mTmpRect = new Rect(); - - StackBox(WindowManagerService service, DisplayContent displayContent, StackBox parent) { - synchronized (StackBox.class) { - mStackBoxId = sCurrentBoxId++; - } - - mService = service; - mDisplayContent = displayContent; - mParent = parent; - } - - /** Propagate #layoutNeeded bottom up. */ - void makeDirty() { - layoutNeeded = true; - if (mParent != null) { - mParent.makeDirty(); - } - } - - /** - * Determine if a particular StackBox is this one or a descendant of this one. - * @param stackBoxId The StackBox being searched for. - * @return true if the specified StackBox matches this or one of its descendants. - */ - boolean contains(int stackBoxId) { - return mStackBoxId == stackBoxId || - (mStack == null && (mFirst.contains(stackBoxId) || mSecond.contains(stackBoxId))); - } - - /** - * Return the stackId of the stack that intersects the passed point. - * @param x coordinate of point. - * @param y coordinate of point. - * @return -1 if point is outside of mBounds, otherwise the stackId of the containing stack. - */ - int stackIdFromPoint(int x, int y) { - if (!mBounds.contains(x, y)) { - return -1; - } - if (mStack != null) { - return mStack.mStackId; - } - int stackId = mFirst.stackIdFromPoint(x, y); - if (stackId >= 0) { - return stackId; - } - return mSecond.stackIdFromPoint(x, y); - } - - /** Determine if this StackBox is the first child or second child. - * @return true if this is the first child. - */ - boolean isFirstChild() { - return mParent != null && mParent.mFirst == this; - } - - /** Returns the bounds of the specified TaskStack if it is contained in this StackBox. - * @param stackId the TaskStack to find the bounds of. - * @return a new Rect with the bounds of stackId if it is within this StackBox, null otherwise. - */ - Rect getStackBounds(int stackId) { - if (mStack != null) { - return mStack.mStackId == stackId ? new Rect(mBounds) : null; - } - Rect bounds = mFirst.getStackBounds(stackId); - if (bounds != null) { - return bounds; - } - return mSecond.getStackBounds(stackId); - } - - /** - * Create a new TaskStack relative to a specified one by splitting the StackBox containing - * the specified TaskStack into two children. The size and position each of the new StackBoxes - * is determined by the passed parameters. - * @param stackId The id of the new TaskStack to create. - * @param relativeStackBoxId The id of the StackBox to place the new TaskStack next to. - * @param position One of the static TASK_STACK_GOES_xxx positions defined in this class. - * @param weight The percentage size of the parent StackBox to devote to the new TaskStack. - * @return The new TaskStack. - */ - TaskStack split(int stackId, int relativeStackBoxId, int position, float weight) { - if (mStackBoxId != relativeStackBoxId) { - // This is not the targeted StackBox. - if (mStack != null) { - return null; - } - // Propagate the split to see if the targeted StackBox is in either sub box. - TaskStack stack = mFirst.split(stackId, relativeStackBoxId, position, weight); - if (stack != null) { - return stack; - } - return mSecond.split(stackId, relativeStackBoxId, position, weight); - } - - // Found it! - TaskStack stack = new TaskStack(mService, stackId, mDisplayContent); - TaskStack firstStack; - TaskStack secondStack; - if (position == TASK_STACK_GOES_BEFORE) { - // TODO: Test Configuration here for LTR/RTL. - position = TASK_STACK_TO_LEFT_OF; - } else if (position == TASK_STACK_GOES_AFTER) { - // TODO: Test Configuration here for LTR/RTL. - position = TASK_STACK_TO_RIGHT_OF; - } - switch (position) { - default: - case TASK_STACK_TO_LEFT_OF: - case TASK_STACK_TO_RIGHT_OF: - mVertical = false; - if (position == TASK_STACK_TO_LEFT_OF) { - mWeight = weight; - firstStack = stack; - secondStack = mStack; - } else { - mWeight = 1.0f - weight; - firstStack = mStack; - secondStack = stack; - } - break; - case TASK_STACK_GOES_ABOVE: - case TASK_STACK_GOES_BELOW: - mVertical = true; - if (position == TASK_STACK_GOES_ABOVE) { - mWeight = weight; - firstStack = stack; - secondStack = mStack; - } else { - mWeight = 1.0f - weight; - firstStack = mStack; - secondStack = stack; - } - break; - } - - mFirst = new StackBox(mService, mDisplayContent, this); - firstStack.mStackBox = mFirst; - mFirst.mStack = firstStack; - - mSecond = new StackBox(mService, mDisplayContent, this); - secondStack.mStackBox = mSecond; - mSecond.mStack = secondStack; - - mStack = null; - return stack; - } - - /** Return the stackId of the first mFirst StackBox with a non-null mStack */ - int getStackId() { - if (mStack != null) { - return mStack.mStackId; - } - return mFirst.getStackId(); - } - - /** Remove this box and propagate its sibling's content up to their parent. - * @return The first stackId of the resulting StackBox. */ - int remove() { - mDisplayContent.layoutNeeded = true; - - if (mParent == null) { - // This is the top-plane stack. - if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing top plane."); - mDisplayContent.removeStackBox(this); - return HOME_STACK_ID; - } - - StackBox sibling = isFirstChild() ? mParent.mSecond : mParent.mFirst; - StackBox grandparent = mParent.mParent; - sibling.mParent = grandparent; - if (grandparent == null) { - // mParent is a top-plane stack. Now sibling will be. - if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent null"); - mDisplayContent.removeStackBox(mParent); - mDisplayContent.addStackBox(sibling, true); - } else { - if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent getting sibling"); - if (mParent.isFirstChild()) { - grandparent.mFirst = sibling; - } else { - grandparent.mSecond = sibling; - } - } - return sibling.getStackId(); - } - - boolean resize(int stackBoxId, float weight) { - if (mStackBoxId != stackBoxId) { - return mStack == null && - (mFirst.resize(stackBoxId, weight) || mSecond.resize(stackBoxId, weight)); - } - // Don't change weight on topmost stack. - if (mParent != null) { - mParent.mWeight = isFirstChild() ? weight : 1.0f - weight; - } - return true; - } - - /** If this is a terminal StackBox (contains a TaskStack) set the bounds. - * @param bounds The rectangle to set the bounds to. - * @param underStatusBar True if the StackBox is directly below the Status Bar. - * @return True if the bounds changed, false otherwise. */ - boolean setStackBoxSizes(Rect bounds, boolean underStatusBar) { - boolean change = false; - if (mUnderStatusBar != underStatusBar) { - change = true; - mUnderStatusBar = underStatusBar; - } - if (mStack != null) { - change |= !mBounds.equals(bounds); - if (change) { - mBounds.set(bounds); - mStack.setBounds(bounds, underStatusBar); - } - } else { - mTmpRect.set(bounds); - if (mVertical) { - final int height = bounds.height(); - int firstHeight = (int)(height * mWeight); - mTmpRect.bottom = bounds.top + firstHeight; - change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar); - mTmpRect.top = mTmpRect.bottom; - mTmpRect.bottom = bounds.top + height; - change |= mSecond.setStackBoxSizes(mTmpRect, false); - } else { - final int width = bounds.width(); - int firstWidth = (int)(width * mWeight); - mTmpRect.right = bounds.left + firstWidth; - change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar); - mTmpRect.left = mTmpRect.right; - mTmpRect.right = bounds.left + width; - change |= mSecond.setStackBoxSizes(mTmpRect, underStatusBar); - } - } - return change; - } - - void resetAnimationBackgroundAnimator() { - if (mStack != null) { - mStack.resetAnimationBackgroundAnimator(); - return; - } - mFirst.resetAnimationBackgroundAnimator(); - mSecond.resetAnimationBackgroundAnimator(); - } - - boolean animateDimLayers() { - if (mStack != null) { - return mStack.animateDimLayers(); - } - boolean result = mFirst.animateDimLayers(); - result |= mSecond.animateDimLayers(); - return result; - } - - void resetDimming() { - if (mStack != null) { - mStack.resetDimmingTag(); - return; - } - mFirst.resetDimming(); - mSecond.resetDimming(); - } - - boolean isDimming() { - if (mStack != null) { - return mStack.isDimming(); - } - boolean result = mFirst.isDimming(); - result |= mSecond.isDimming(); - return result; - } - - void stopDimmingIfNeeded() { - if (mStack != null) { - mStack.stopDimmingIfNeeded(); - return; - } - mFirst.stopDimmingIfNeeded(); - mSecond.stopDimmingIfNeeded(); - } - - void switchUserStacks(int userId) { - if (mStack != null) { - mStack.switchUser(userId); - return; - } - mFirst.switchUserStacks(userId); - mSecond.switchUserStacks(userId); - } - - void close() { - if (mStack != null) { - mStack.mDimLayer.mDimSurface.destroy(); - mStack.mAnimationBackgroundSurface.mDimSurface.destroy(); - return; - } - mFirst.close(); - mSecond.close(); - } - - public void dump(String prefix, PrintWriter pw) { - pw.print(prefix); pw.print("mParent="); pw.println(mParent); - pw.print(prefix); pw.print("mBounds="); pw.print(mBounds.toShortString()); - pw.print(" mVertical="); pw.print(mVertical); - pw.print(" layoutNeeded="); pw.println(layoutNeeded); - if (mFirst != null) { - pw.print(prefix); pw.print("mFirst="); pw.println(System.identityHashCode(mFirst)); - mFirst.dump(prefix + " ", pw); - pw.print(prefix); pw.print("mSecond="); pw.println(System.identityHashCode(mSecond)); - mSecond.dump(prefix + " ", pw); - } else { - pw.print(prefix); pw.print("mStack="); pw.println(mStack); - mStack.dump(prefix + " ", pw); - } - } - - @Override - public String toString() { - if (mStack != null) { - return "Box{" + hashCode() + " stack=" + mStack.mStackId + "}"; - } - return "Box{" + hashCode() + " parent=" + System.identityHashCode(mParent) - + " first=" + System.identityHashCode(mFirst) - + " second=" + System.identityHashCode(mSecond) + "}"; - } -} diff --git a/services/jni/Android.mk b/services/jni/Android.mk deleted file mode 100644 index 98e9b30..0000000 --- a/services/jni/Android.mk +++ /dev/null @@ -1,63 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - com_android_server_AlarmManagerService.cpp \ - com_android_server_AssetAtlasService.cpp \ - com_android_server_ConsumerIrService.cpp \ - com_android_server_input_InputApplicationHandle.cpp \ - com_android_server_input_InputManagerService.cpp \ - com_android_server_input_InputWindowHandle.cpp \ - com_android_server_LightsService.cpp \ - com_android_server_power_PowerManagerService.cpp \ - com_android_server_SerialService.cpp \ - com_android_server_SystemServer.cpp \ - com_android_server_UsbDeviceManager.cpp \ - com_android_server_UsbHostManager.cpp \ - com_android_server_VibratorService.cpp \ - com_android_server_location_GpsLocationProvider.cpp \ - com_android_server_location_FlpHardwareProvider.cpp \ - com_android_server_connectivity_Vpn.cpp \ - onload.cpp - -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) \ - frameworks/base/services \ - frameworks/base/core/jni \ - frameworks/native/services \ - external/skia/include/core \ - libcore/include \ - libcore/include/libsuspend \ - $(call include-path-for, libhardware)/hardware \ - $(call include-path-for, libhardware_legacy)/hardware_legacy \ - -LOCAL_SHARED_LIBRARIES := \ - libandroid_runtime \ - libandroidfw \ - libbinder \ - libcutils \ - liblog \ - libhardware \ - libhardware_legacy \ - libnativehelper \ - libutils \ - libui \ - libinput \ - libinputservice \ - libsensorservice \ - libskia \ - libgui \ - libusbhost \ - libsuspend \ - libEGL \ - libGLESv2 - -LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES - -ifeq ($(WITH_MALLOC_LEAK_CHECK),true) - LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK -endif - -LOCAL_MODULE:= libandroid_servers - -include $(BUILD_SHARED_LIBRARY) diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp deleted file mode 100644 index c2f6151..0000000 --- a/services/jni/com_android_server_AlarmManagerService.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* //device/libs/android_runtime/android_server_AlarmManagerService.cpp -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#define LOG_TAG "AlarmManagerService" - -#include "JNIHelp.h" -#include "jni.h" -#include <utils/Log.h> -#include <utils/misc.h> - -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#include <stdlib.h> -#include <errno.h> -#include <unistd.h> -#include <linux/ioctl.h> -#include <linux/android_alarm.h> - -namespace android { - -static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest) -{ - struct timezone tz; - - tz.tz_minuteswest = minswest; - tz.tz_dsttime = 0; - - int result = settimeofday(NULL, &tz); - if (result < 0) { - ALOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno)); - return -1; - } else { - ALOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest); - } - - return 0; -} - -static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj) -{ - return open("/dev/alarm", O_RDWR); -} - -static void android_server_AlarmManagerService_close(JNIEnv* env, jobject obj, jint fd) -{ - close(fd); -} - -static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds) -{ - struct timespec ts; - ts.tv_sec = seconds; - ts.tv_nsec = nanoseconds; - - int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts); - if (result < 0) - { - ALOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno)); - } -} - -static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd) -{ - int result = 0; - - do - { - result = ioctl(fd, ANDROID_ALARM_WAIT); - } while (result < 0 && errno == EINTR); - - if (result < 0) - { - ALOGE("Unable to wait on alarm: %s\n", strerror(errno)); - return 0; - } - - return result; -} - -static JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"init", "()I", (void*)android_server_AlarmManagerService_init}, - {"close", "(I)V", (void*)android_server_AlarmManagerService_close}, - {"set", "(IIJJ)V", (void*)android_server_AlarmManagerService_set}, - {"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm}, - {"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone}, -}; - -int register_android_server_AlarmManagerService(JNIEnv* env) -{ - return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService", - sMethods, NELEM(sMethods)); -} - -} /* namespace android */ diff --git a/services/print/Android.mk b/services/print/Android.mk new file mode 100644 index 0000000..33604b7 --- /dev/null +++ b/services/print/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.print + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java new file mode 100644 index 0000000..c6fdbe5 --- /dev/null +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -0,0 +1,689 @@ +/* + * 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.server.print; + +import android.Manifest; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Binder; +import android.os.Bundle; +import android.os.Process; +import android.os.RemoteException; +import android.os.UserHandle; +import android.print.IPrintDocumentAdapter; +import android.print.IPrintJobStateChangeListener; +import android.print.IPrintManager; +import android.print.IPrinterDiscoveryObserver; +import android.print.PrintAttributes; +import android.print.PrintJobId; +import android.print.PrintJobInfo; +import android.print.PrinterId; +import android.printservice.PrintServiceInfo; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.SparseArray; + +import com.android.internal.R; +import com.android.internal.content.PackageMonitor; +import com.android.internal.os.BackgroundThread; +import com.android.server.SystemService; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * SystemService wrapper for the PrintManager implementation. Publishes + * Context.PRINT_SERVICE. + * PrintManager implementation is contained within. + */ + +public final class PrintManagerService extends SystemService { + private final PrintManagerImpl mPrintManagerImpl; + + public PrintManagerService(Context context) { + super(context); + mPrintManagerImpl = new PrintManagerImpl(context); + } + + @Override + public void onStart() { + publishBinderService(Context.PRINT_SERVICE, mPrintManagerImpl); + } + + @Override + public void onBootPhase(int phase) { + if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + mPrintManagerImpl.systemRunning(); + } + } + + class PrintManagerImpl extends IPrintManager.Stub { + private static final char COMPONENT_NAME_SEPARATOR = ':'; + + private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME = + "EXTRA_PRINT_SERVICE_COMPONENT_NAME"; + + private final Object mLock = new Object(); + + private final Context mContext; + + private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); + + private int mCurrentUserId = UserHandle.USER_OWNER; + + PrintManagerImpl(Context context) { + mContext = context; + registerContentObservers(); + registerBoradcastReceivers(); + } + + public void systemRunning() { + BackgroundThread.getHandler().post(new Runnable() { + @Override + public void run() { + final UserState userState; + synchronized (mLock) { + userState = getCurrentUserStateLocked(); + userState.updateIfNeededLocked(); + } + // This is the first time we switch to this user after boot, so + // now is the time to remove obsolete print jobs since they + // are from the last boot and no application would query them. + userState.removeObsoletePrintJobs(); + } + }); + } + + @Override + public Bundle print(String printJobName, IPrintDocumentAdapter adapter, + PrintAttributes attributes, String packageName, int appId, int userId) { + final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + return userState.print(printJobName, adapter, attributes, + resolvedPackageName, resolvedAppId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) { + final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + return userState.getPrintJobInfos(resolvedAppId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) { + final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + return userState.getPrintJobInfo(printJobId, resolvedAppId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) { + final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.cancelPrintJob(printJobId, resolvedAppId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void restartPrintJob(PrintJobId printJobId, int appId, int userId) { + final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.restartPrintJob(printJobId, resolvedAppId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public List<PrintServiceInfo> getEnabledPrintServices(int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + return userState.getEnabledPrintServices(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public List<PrintServiceInfo> getInstalledPrintServices(int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + return userState.getInstalledPrintServices(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer, + int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.createPrinterDiscoverySession(observer); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer, + int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.destroyPrinterDiscoverySession(observer); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void startPrinterDiscovery(IPrinterDiscoveryObserver observer, + List<PrinterId> priorityList, int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.startPrinterDiscovery(observer, priorityList); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.stopPrinterDiscovery(observer); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void validatePrinters(List<PrinterId> printerIds, int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.validatePrinters(printerIds); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void startPrinterStateTracking(PrinterId printerId, int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.startPrinterStateTracking(printerId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void stopPrinterStateTracking(PrinterId printerId, int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.stopPrinterStateTracking(printerId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener, + int appId, int userId) throws RemoteException { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.addPrintJobStateChangeListener(listener, resolvedAppId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener, + int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.removePrintJobStateChangeListener(listener); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump PrintManager from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + synchronized (mLock) { + final long identity = Binder.clearCallingIdentity(); + try { + pw.println("PRINT MANAGER STATE (dumpsys print)"); + final int userStateCount = mUserStates.size(); + for (int i = 0; i < userStateCount; i++) { + UserState userState = mUserStates.valueAt(i); + userState.dump(fd, pw, ""); + pw.println(); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + private void registerContentObservers() { + final Uri enabledPrintServicesUri = Settings.Secure.getUriFor( + Settings.Secure.ENABLED_PRINT_SERVICES); + + ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) { + @Override + public void onChange(boolean selfChange, Uri uri) { + if (enabledPrintServicesUri.equals(uri)) { + synchronized (mLock) { + UserState userState = getCurrentUserStateLocked(); + userState.updateIfNeededLocked(); + } + } + } + }; + + mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri, + false, observer, UserHandle.USER_ALL); + } + + private void registerBoradcastReceivers() { + PackageMonitor monitor = new PackageMonitor() { + @Override + public boolean onPackageChanged(String packageName, int uid, String[] components) { + synchronized (mLock) { + UserState userState = getOrCreateUserStateLocked(getChangingUserId()); + Iterator<ComponentName> iterator = userState.getEnabledServices() + .iterator(); + while (iterator.hasNext()) { + ComponentName componentName = iterator.next(); + if (packageName.equals(componentName.getPackageName())) { + userState.updateIfNeededLocked(); + return true; + } + } + } + return false; + } + + @Override + public void onPackageRemoved(String packageName, int uid) { + synchronized (mLock) { + UserState userState = getOrCreateUserStateLocked(getChangingUserId()); + Iterator<ComponentName> iterator = userState.getEnabledServices() + .iterator(); + while (iterator.hasNext()) { + ComponentName componentName = iterator.next(); + if (packageName.equals(componentName.getPackageName())) { + iterator.remove(); + persistComponentNamesToSettingLocked( + Settings.Secure.ENABLED_PRINT_SERVICES, + userState.getEnabledServices(), getChangingUserId()); + userState.updateIfNeededLocked(); + return; + } + } + } + } + + @Override + public boolean onHandleForceStop(Intent intent, String[] stoppedPackages, + int uid, boolean doit) { + synchronized (mLock) { + UserState userState = getOrCreateUserStateLocked(getChangingUserId()); + boolean stoppedSomePackages = false; + Iterator<ComponentName> iterator = userState.getEnabledServices() + .iterator(); + while (iterator.hasNext()) { + ComponentName componentName = iterator.next(); + String componentPackage = componentName.getPackageName(); + for (String stoppedPackage : stoppedPackages) { + if (componentPackage.equals(stoppedPackage)) { + if (!doit) { + return true; + } + stoppedSomePackages = true; + break; + } + } + } + if (stoppedSomePackages) { + userState.updateIfNeededLocked(); + } + return false; + } + } + + @Override + public void onPackageAdded(String packageName, int uid) { + Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE); + intent.setPackage(packageName); + + List<ResolveInfo> installedServices = mContext.getPackageManager() + .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES, + getChangingUserId()); + + if (installedServices == null) { + return; + } + + final int installedServiceCount = installedServices.size(); + for (int i = 0; i < installedServiceCount; i++) { + ServiceInfo serviceInfo = installedServices.get(i).serviceInfo; + ComponentName component = new ComponentName(serviceInfo.packageName, + serviceInfo.name); + String label = serviceInfo.loadLabel(mContext.getPackageManager()) + .toString(); + showEnableInstalledPrintServiceNotification(component, label, + getChangingUserId()); + } + } + + private void persistComponentNamesToSettingLocked(String settingName, + Set<ComponentName> componentNames, int userId) { + StringBuilder builder = new StringBuilder(); + for (ComponentName componentName : componentNames) { + if (builder.length() > 0) { + builder.append(COMPONENT_NAME_SEPARATOR); + } + builder.append(componentName.flattenToShortString()); + } + Settings.Secure.putStringForUser(mContext.getContentResolver(), + settingName, builder.toString(), userId); + } + }; + + // package changes + monitor.register(mContext, BackgroundThread.getHandler().getLooper(), + UserHandle.ALL, true); + + // user changes + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_USER_SWITCHED); + intentFilter.addAction(Intent.ACTION_USER_REMOVED); + + mContext.registerReceiverAsUser(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_USER_SWITCHED.equals(action)) { + switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); + } else if (Intent.ACTION_USER_REMOVED.equals(action)) { + removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); + } + } + }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler()); + } + + private UserState getCurrentUserStateLocked() { + return getOrCreateUserStateLocked(mCurrentUserId); + } + + private UserState getOrCreateUserStateLocked(int userId) { + UserState userState = mUserStates.get(userId); + if (userState == null) { + userState = new UserState(mContext, userId, mLock); + mUserStates.put(userId, userState); + } + return userState; + } + + private void switchUser(int newUserId) { + UserState userState; + synchronized (mLock) { + if (newUserId == mCurrentUserId) { + return; + } + mCurrentUserId = newUserId; + userState = mUserStates.get(mCurrentUserId); + if (userState == null) { + userState = getCurrentUserStateLocked(); + userState.updateIfNeededLocked(); + } else { + userState.updateIfNeededLocked(); + } + } + // This is the first time we switch to this user after boot, so + // now is the time to remove obsolete print jobs since they + // are from the last boot and no application would query them. + userState.removeObsoletePrintJobs(); + } + + private void removeUser(int removedUserId) { + synchronized (mLock) { + UserState userState = mUserStates.get(removedUserId); + if (userState != null) { + userState.destroyLocked(); + mUserStates.remove(removedUserId); + } + } + } + + private int resolveCallingAppEnforcingPermissions(int appId) { + final int callingUid = Binder.getCallingUid(); + if (callingUid == 0 || callingUid == Process.SYSTEM_UID + || callingUid == Process.SHELL_UID) { + return appId; + } + final int callingAppId = UserHandle.getAppId(callingUid); + if (appId == callingAppId) { + return appId; + } + if (mContext.checkCallingPermission( + "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS") + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Call from app " + callingAppId + " as app " + + appId + " without com.android.printspooler.permission" + + ".ACCESS_ALL_PRINT_JOBS"); + } + return appId; + } + + private int resolveCallingUserEnforcingPermissions(int userId) { + final int callingUid = Binder.getCallingUid(); + if (callingUid == 0 || callingUid == Process.SYSTEM_UID + || callingUid == Process.SHELL_UID) { + return userId; + } + final int callingUserId = UserHandle.getUserId(callingUid); + if (callingUserId == userId) { + return userId; + } + if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL) + != PackageManager.PERMISSION_GRANTED + || mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS) + != PackageManager.PERMISSION_GRANTED) { + if (userId == UserHandle.USER_CURRENT_OR_SELF) { + return callingUserId; + } + throw new SecurityException("Call from user " + callingUserId + " as user " + + userId + " without permission INTERACT_ACROSS_USERS or " + + "INTERACT_ACROSS_USERS_FULL not allowed."); + } + if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) { + return mCurrentUserId; + } + throw new IllegalArgumentException("Calling user can be changed to only " + + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF."); + } + + private String resolveCallingPackageNameEnforcingSecurity(String packageName) { + if (TextUtils.isEmpty(packageName)) { + return null; + } + String[] packages = mContext.getPackageManager().getPackagesForUid( + Binder.getCallingUid()); + final int packageCount = packages.length; + for (int i = 0; i < packageCount; i++) { + if (packageName.equals(packages[i])) { + return packageName; + } + } + return null; + } + + private void showEnableInstalledPrintServiceNotification(ComponentName component, + String label, int userId) { + UserHandle userHandle = new UserHandle(userId); + + Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); + intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString()); + + PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent, + PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null, + userHandle); + + Notification.Builder builder = new Notification.Builder(mContext) + .setSmallIcon(R.drawable.ic_print) + .setContentTitle(mContext.getString(R.string.print_service_installed_title, + label)) + .setContentText(mContext.getString(R.string.print_service_installed_message)) + .setContentIntent(pendingIntent) + .setWhen(System.currentTimeMillis()) + .setAutoCancel(true) + .setShowWhen(true); + + NotificationManager notificationManager = (NotificationManager) mContext + .getSystemService(Context.NOTIFICATION_SERVICE); + + String notificationTag = getClass().getName() + ":" + component.flattenToString(); + notificationManager.notifyAsUser(notificationTag, 0, builder.build(), + userHandle); + } + } +} diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java index 1bb61d2..1bb61d2 100644 --- a/services/java/com/android/server/print/RemotePrintService.java +++ b/services/print/java/com/android/server/print/RemotePrintService.java diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java index ffe9806..ffe9806 100644 --- a/services/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java diff --git a/services/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java index f23a992..f23a992 100644 --- a/services/java/com/android/server/print/UserState.java +++ b/services/print/java/com/android/server/print/UserState.java diff --git a/services/tests/Android.mk b/services/tests/Android.mk new file mode 100644 index 0000000..40369ee --- /dev/null +++ b/services/tests/Android.mk @@ -0,0 +1,3 @@ +LOCAL_PATH:= $(call my-dir) + +include $(call all-makefiles-under, $(LOCAL_PATH)) diff --git a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java b/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java index 58d6dae..50e7a03 100644 --- a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java +++ b/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java @@ -34,7 +34,7 @@ public class EntropyMixerTest extends AndroidTestCase { assertEquals(0, FileUtils.readTextFile(file, 0, null).length()); // The constructor has the side effect of writing to file - new EntropyMixer(getContext(), "/dev/null", file.getCanonicalPath()); + new EntropyMixer(getContext(), "/dev/null", file.getCanonicalPath(), "/dev/null"); assertTrue(FileUtils.readTextFile(file, 0, null).length() > 0); } diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java index 56dd7c4..7a30d31 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -17,6 +17,7 @@ package com.android.server; import android.content.Context; +import android.net.LinkAddress; import android.net.LocalSocket; import android.net.LocalServerSocket; import android.os.Binder; @@ -157,18 +158,61 @@ public class NetworkManagementServiceTest extends AndroidTestCase { * IP address changes. */ sendMessage("614 Address updated fe80::1/64 wlan0 128 253"); - expectSoon(observer).addressUpdated("fe80::1/64", "wlan0", 128, 253); + expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253)); - // There is no "added". + // There is no "added", so we take this as "removed". sendMessage("614 Address added fe80::1/64 wlan0 128 253"); - expectSoon(observer).addressRemoved("fe80::1/64", "wlan0", 128, 253); + expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253)); sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0"); - expectSoon(observer).addressRemoved("2001:db8::1/64", "wlan0", 1, 0); + expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0)); - sendMessage("666 Address added 2001:db8::1/64 wlan0 1 0"); + sendMessage("614 Address removed 2001:db8::1/64 wlan0 1"); + // Not enough arguments. + + sendMessage("666 Address removed 2001:db8::1/64 wlan0 1 0"); // Invalid code. + + /** + * DNS information broadcasts. + */ + sendMessage("615 DnsInfo servers rmnet_usb0 3600 2001:db8::1"); + expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600, + new String[]{"2001:db8::1"}); + + sendMessage("615 DnsInfo servers wlan0 14400 2001:db8::1,2001:db8::2"); + expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400, + new String[]{"2001:db8::1", "2001:db8::2"}); + + // We don't check for negative lifetimes, only for parse errors. + sendMessage("615 DnsInfo servers wlan0 -3600 ::1"); + expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600, + new String[]{"::1"}); + + sendMessage("615 DnsInfo servers wlan0 SIXHUNDRED ::1"); + // Non-numeric lifetime. + + sendMessage("615 DnsInfo servers wlan0 2001:db8::1"); + // Missing lifetime. + + sendMessage("615 DnsInfo servers wlan0 3600"); + // No servers. + + sendMessage("615 DnsInfo servers 3600 wlan0 2001:db8::1,2001:db8::2"); + // Non-numeric lifetime. + + sendMessage("615 DnsInfo wlan0 7200 2001:db8::1,2001:db8::2"); + // Invalid tokens. + + sendMessage("666 DnsInfo servers wlan0 5400 2001:db8::1"); + // Invalid code. + + // No syntax checking on the addresses. + sendMessage("615 DnsInfo servers wlan0 600 ,::,,foo,::1,"); + expectSoon(observer).interfaceDnsServerInfo("wlan0", 600, + new String[]{"", "::", "", "foo", "::1"}); + // Make sure nothing else was called. verifyNoMoreInteractions(observer); } diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 8b9f718..8392672 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -216,7 +216,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { expectLastCall().atLeastOnce(); // expect to answer screen status during systemReady() - expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce(); + expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce(); expect(mNetworkManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce(); expectCurrentTime(); @@ -331,7 +331,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { verifyAndReset(); // now turn screen off and verify REJECT rule - expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce(); + expect(mPowerManager.isInteractive()).andReturn(false).atLeastOnce(); expectSetUidNetworkRules(UID_A, true); expectSetUidForeground(UID_A, false); future = expectRulesChanged(UID_A, RULE_REJECT_METERED); @@ -341,7 +341,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { verifyAndReset(); // and turn screen back on, verify ALLOW rule restored - expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce(); + expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce(); expectSetUidNetworkRules(UID_A, false); expectSetUidForeground(UID_A, true); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); diff --git a/services/usb/Android.mk b/services/usb/Android.mk new file mode 100644 index 0000000..feabf0a --- /dev/null +++ b/services/usb/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.usb + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) + +LOCAL_JAVA_LIBRARIES := services.core + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java index ce953a4..0946c5a 100644 --- a/services/java/com/android/server/usb/UsbDebuggingManager.java +++ b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java @@ -17,8 +17,12 @@ package com.android.server.usb; import android.content.ActivityNotFoundException; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.Handler; @@ -208,7 +212,7 @@ public class UsbDebuggingManager implements Runnable { case MESSAGE_ADB_CONFIRM: { String key = (String)msg.obj; mFingerprints = getFingerprints(key); - showConfirmationDialog(key, mFingerprints); + startConfirmation(key, mFingerprints); break; } @@ -243,19 +247,60 @@ public class UsbDebuggingManager implements Runnable { return sb.toString(); } - private void showConfirmationDialog(String key, String fingerprints) { - Intent dialogIntent = new Intent(); + private void startConfirmation(String key, String fingerprints) { + String nameString = Resources.getSystem().getString( + com.android.internal.R.string.config_customAdbPublicKeyConfirmationComponent); + ComponentName componentName = ComponentName.unflattenFromString(nameString); + if (startConfirmationActivity(componentName, key, fingerprints) + || startConfirmationService(componentName, key, fingerprints)) { + return; + } + Slog.e(TAG, "unable to start customAdbPublicKeyConfirmationComponent " + + nameString + " as an Activity or a Service"); + } + + /** + * @returns true if the componentName led to an Activity that was started. + */ + private boolean startConfirmationActivity(ComponentName componentName, String key, + String fingerprints) { + PackageManager packageManager = mContext.getPackageManager(); + Intent intent = createConfirmationIntent(componentName, key, fingerprints); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) { + try { + mContext.startActivity(intent); + return true; + } catch (ActivityNotFoundException e) { + Slog.e(TAG, "unable to start adb whitelist activity: " + componentName, e); + } + } + return false; + } - dialogIntent.setClassName("com.android.systemui", - "com.android.systemui.usb.UsbDebuggingActivity"); - dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - dialogIntent.putExtra("key", key); - dialogIntent.putExtra("fingerprints", fingerprints); + /** + * @returns true if the componentName led to a Service that was started. + */ + private boolean startConfirmationService(ComponentName componentName, String key, + String fingerprints) { + Intent intent = createConfirmationIntent(componentName, key, fingerprints); try { - mContext.startActivity(dialogIntent); - } catch (ActivityNotFoundException e) { - Slog.e(TAG, "unable to start UsbDebuggingActivity"); + if (mContext.startService(intent) != null) { + return true; + } + } catch (SecurityException e) { + Slog.e(TAG, "unable to start adb whitelist service: " + componentName, e); } + return false; + } + + private Intent createConfirmationIntent(ComponentName componentName, String key, + String fingerprints) { + Intent intent = new Intent(); + intent.setClassName(componentName.getPackageName(), componentName.getClassName()); + intent.putExtra("key", key); + intent.putExtra("fingerprints", fingerprints); + return intent; } private File getUserKeyFile() { diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index bb61e49..76a8d17 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -831,7 +831,7 @@ public class UsbDeviceManager { if (mOemModeMap == null) { mOemModeMap = new HashMap<String, List<Pair<String, String>>>(); } - List overrideList = mOemModeMap.get(items[0]); + List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]); if (overrideList == null) { overrideList = new LinkedList<Pair<String, String>>(); mOemModeMap.put(items[0], overrideList); diff --git a/services/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index 10272f2..dfaad0b 100644 --- a/services/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -96,6 +96,7 @@ public class UsbHostManager { /* Called from JNI in monitorUsbHostBus() to report new USB devices */ private void usbDeviceAdded(String deviceName, int vendorID, int productID, int deviceClass, int deviceSubclass, int deviceProtocol, + String manufacturerName, String productName, String serialNumber, /* array of quintuples containing id, class, subclass, protocol and number of endpoints for each interface */ int[] interfaceValues, @@ -151,7 +152,8 @@ public class UsbHostManager { } UsbDevice device = new UsbDevice(deviceName, vendorID, productID, - deviceClass, deviceSubclass, deviceProtocol, interfaces); + deviceClass, deviceSubclass, deviceProtocol, + manufacturerName, productName, serialNumber, interfaces); mDevices.put(deviceName, device); getCurrentSettings().deviceAttached(device); } diff --git a/services/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java index 36669b1..b6ae192 100644 --- a/services/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -32,6 +32,7 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.SystemService; import java.io.File; import java.io.FileDescriptor; @@ -43,6 +44,28 @@ import java.io.PrintWriter; * support is delegated to UsbDeviceManager. */ public class UsbService extends IUsbManager.Stub { + + public static class Lifecycle extends SystemService { + private UsbService mUsbService; + + public Lifecycle(Context context) { + super(context); + } + + @Override + public void onStart() { + mUsbService = new UsbService(getContext()); + publishBinderService(Context.USB_SERVICE, mUsbService); + } + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { + mUsbService.systemReady(); + } + } + } + private static final String TAG = "UsbService"; private final Context mContext; diff --git a/services/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java index 9b5b312..ff4857b 100644 --- a/services/java/com/android/server/usb/UsbSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java @@ -108,13 +108,23 @@ class UsbSettingsManager { public final int mSubclass; // USB device protocol (or -1 for unspecified) public final int mProtocol; - - public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol) { + // USB device manufacturer name string (or null for unspecified) + public final String mManufacturerName; + // USB device product name string (or null for unspecified) + public final String mProductName; + // USB device serial number string (or null for unspecified) + public final String mSerialNumber; + + public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol, + String manufacturer, String product, String serialnum) { mVendorId = vid; mProductId = pid; mClass = clasz; mSubclass = subclass; mProtocol = protocol; + mManufacturerName = manufacturer; + mProductName = product; + mSerialNumber = serialnum; } public DeviceFilter(UsbDevice device) { @@ -123,6 +133,9 @@ class UsbSettingsManager { mClass = device.getDeviceClass(); mSubclass = device.getDeviceSubclass(); mProtocol = device.getDeviceProtocol(); + mManufacturerName = device.getManufacturerName(); + mProductName = device.getProductName(); + mSerialNumber = device.getSerialNumber(); } public static DeviceFilter read(XmlPullParser parser) @@ -132,27 +145,52 @@ class UsbSettingsManager { int deviceClass = -1; int deviceSubclass = -1; int deviceProtocol = -1; + String manufacturerName = null; + String productName = null; + String serialNumber = null; int count = parser.getAttributeCount(); for (int i = 0; i < count; i++) { String name = parser.getAttributeName(i); - // All attribute values are ints - int value = Integer.parseInt(parser.getAttributeValue(i)); - - if ("vendor-id".equals(name)) { - vendorId = value; - } else if ("product-id".equals(name)) { - productId = value; - } else if ("class".equals(name)) { - deviceClass = value; - } else if ("subclass".equals(name)) { - deviceSubclass = value; - } else if ("protocol".equals(name)) { - deviceProtocol = value; + String value = parser.getAttributeValue(i); + // Attribute values are ints or strings + if ("manufacturer-name".equals(name)) { + manufacturerName = value; + } else if ("product-name".equals(name)) { + productName = value; + } else if ("serial-number".equals(name)) { + serialNumber = value; + } else { + int intValue = -1; + int radix = 10; + if (value != null && value.length() > 2 && value.charAt(0) == '0' && + (value.charAt(1) == 'x' || value.charAt(1) == 'X')) { + // allow hex values starting with 0x or 0X + radix = 16; + value = value.substring(2); + } + try { + intValue = Integer.parseInt(value, radix); + } catch (NumberFormatException e) { + Slog.e(TAG, "invalid number for field " + name, e); + continue; + } + if ("vendor-id".equals(name)) { + vendorId = intValue; + } else if ("product-id".equals(name)) { + productId = intValue; + } else if ("class".equals(name)) { + deviceClass = intValue; + } else if ("subclass".equals(name)) { + deviceSubclass = intValue; + } else if ("protocol".equals(name)) { + deviceProtocol = intValue; + } } } return new DeviceFilter(vendorId, productId, - deviceClass, deviceSubclass, deviceProtocol); + deviceClass, deviceSubclass, deviceProtocol, + manufacturerName, productName, serialNumber); } public void write(XmlSerializer serializer) throws IOException { @@ -172,6 +210,15 @@ class UsbSettingsManager { if (mProtocol != -1) { serializer.attribute(null, "protocol", Integer.toString(mProtocol)); } + if (mManufacturerName != null) { + serializer.attribute(null, "manufacturer-name", mManufacturerName); + } + if (mProductName != null) { + serializer.attribute(null, "product-name", mProductName); + } + if (mSerialNumber != null) { + serializer.attribute(null, "serial-number", mSerialNumber); + } serializer.endTag(null, "usb-device"); } @@ -184,6 +231,15 @@ class UsbSettingsManager { public boolean matches(UsbDevice device) { if (mVendorId != -1 && device.getVendorId() != mVendorId) return false; if (mProductId != -1 && device.getProductId() != mProductId) return false; + if (mManufacturerName != null && device.getManufacturerName() == null) return false; + if (mProductName != null && device.getProductName() == null) return false; + if (mSerialNumber != null && device.getSerialNumber() == null) return false; + if (mManufacturerName != null && device.getManufacturerName() != null && + !mManufacturerName.equals(device.getManufacturerName())) return false; + if (mProductName != null && device.getProductName() != null && + !mProductName.equals(device.getProductName())) return false; + if (mSerialNumber != null && device.getSerialNumber() != null && + !mSerialNumber.equals(device.getSerialNumber())) return false; // check device class/subclass/protocol if (matches(device.getDeviceClass(), device.getDeviceSubclass(), @@ -203,6 +259,15 @@ class UsbSettingsManager { public boolean matches(DeviceFilter f) { if (mVendorId != -1 && f.mVendorId != mVendorId) return false; if (mProductId != -1 && f.mProductId != mProductId) return false; + if (f.mManufacturerName != null && mManufacturerName == null) return false; + if (f.mProductName != null && mProductName == null) return false; + if (f.mSerialNumber != null && mSerialNumber == null) return false; + if (mManufacturerName != null && f.mManufacturerName != null && + !mManufacturerName.equals(f.mManufacturerName)) return false; + if (mProductName != null && f.mProductName != null && + !mProductName.equals(f.mProductName)) return false; + if (mSerialNumber != null && f.mSerialNumber != null && + !mSerialNumber.equals(f.mSerialNumber)) return false; // check device class/subclass/protocol return matches(f.mClass, f.mSubclass, f.mProtocol); @@ -217,19 +282,67 @@ class UsbSettingsManager { } if (obj instanceof DeviceFilter) { DeviceFilter filter = (DeviceFilter)obj; - return (filter.mVendorId == mVendorId && - filter.mProductId == mProductId && - filter.mClass == mClass && - filter.mSubclass == mSubclass && - filter.mProtocol == mProtocol); + + if (filter.mVendorId != mVendorId || + filter.mProductId != mProductId || + filter.mClass != mClass || + filter.mSubclass != mSubclass || + filter.mProtocol != mProtocol) { + return(false); + } + if ((filter.mManufacturerName != null && + mManufacturerName == null) || + (filter.mManufacturerName == null && + mManufacturerName != null) || + (filter.mProductName != null && + mProductName == null) || + (filter.mProductName == null && + mProductName != null) || + (filter.mSerialNumber != null && + mSerialNumber == null) || + (filter.mSerialNumber == null && + mSerialNumber != null)) { + return(false); + } + if ((filter.mManufacturerName != null && + mManufacturerName != null && + !mManufacturerName.equals(filter.mManufacturerName)) || + (filter.mProductName != null && + mProductName != null && + !mProductName.equals(filter.mProductName)) || + (filter.mSerialNumber != null && + mSerialNumber != null && + !mSerialNumber.equals(filter.mSerialNumber))) { + return(false); + } + return(true); } if (obj instanceof UsbDevice) { UsbDevice device = (UsbDevice)obj; - return (device.getVendorId() == mVendorId && - device.getProductId() == mProductId && - device.getDeviceClass() == mClass && - device.getDeviceSubclass() == mSubclass && - device.getDeviceProtocol() == mProtocol); + if (device.getVendorId() != mVendorId || + device.getProductId() != mProductId || + device.getDeviceClass() != mClass || + device.getDeviceSubclass() != mSubclass || + device.getDeviceProtocol() != mProtocol) { + return(false); + } + if ((mManufacturerName != null && device.getManufacturerName() == null) || + (mManufacturerName == null && device.getManufacturerName() != null) || + (mProductName != null && device.getProductName() == null) || + (mProductName == null && device.getProductName() != null) || + (mSerialNumber != null && device.getSerialNumber() == null) || + (mSerialNumber == null && device.getSerialNumber() != null)) { + return(false); + } + if ((device.getManufacturerName() != null && + !mManufacturerName.equals(device.getManufacturerName())) || + (device.getProductName() != null && + !mProductName.equals(device.getProductName())) || + (device.getSerialNumber() != null && + !mSerialNumber.equals(device.getSerialNumber()))) { + return(false); + } + return true; } return false; } @@ -244,7 +357,9 @@ class UsbSettingsManager { public String toString() { return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId + ",mClass=" + mClass + ",mSubclass=" + mSubclass + - ",mProtocol=" + mProtocol + "]"; + ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName + + ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber + + "]"; } } |