diff options
405 files changed, 12144 insertions, 2203 deletions
diff --git a/Android.bp b/Android.bp index 88b2473169f5..25e738ccb3cf 100644 --- a/Android.bp +++ b/Android.bp @@ -731,8 +731,10 @@ java_defaults { "netd_aidl_interface-java", ], - // Loaded with System.loadLibrary by android.view.textclassifier required: [ + // TODO: remove gps_debug when the build system propagates "required" properly. + "gps_debug.conf", + // Loaded with System.loadLibrary by android.view.textclassifier "libmedia2_jni", ], diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 5936ee4bc5cb..e731138ff40d 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -5,7 +5,9 @@ api_lint_hook = ${REPO_ROOT}/frameworks/base/tools/apilint/apilint_sha.sh ${PREU strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT} -hidden_api_txt_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT} +hidden_api_txt_checksorted_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT} + +hidden_api_txt_exclude_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/exclude.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT} ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES} diff --git a/api/current.txt b/api/current.txt index 10d78299d90f..38a721f35ee9 100644 --- a/api/current.txt +++ b/api/current.txt @@ -480,6 +480,10 @@ package android { field public static final int dashGap = 16843175; // 0x10101a7 field public static final int dashWidth = 16843174; // 0x10101a6 field public static final int data = 16842798; // 0x101002e + field public static final int dataRetentionTime = 16844189; // 0x101059d + field public static final int dataSentOffDevice = 16844186; // 0x101059a + field public static final int dataSharedWithThirdParty = 16844187; // 0x101059b + field public static final int dataUsedForMonetization = 16844188; // 0x101059c field public static final int datePickerDialogTheme = 16843948; // 0x10104ac field public static final int datePickerMode = 16843955; // 0x10104b3 field public static final int datePickerStyle = 16843612; // 0x101035c @@ -1312,7 +1316,6 @@ package android { field public static final int summaryColumn = 16843426; // 0x10102a2 field public static final int summaryOff = 16843248; // 0x10101f0 field public static final int summaryOn = 16843247; // 0x10101ef - field public static final int supportsAmbientMode = 16844173; // 0x101058d field public static final int supportsAssist = 16844016; // 0x10104f0 field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1 field public static final int supportsLocalInteraction = 16844047; // 0x101050f @@ -1496,6 +1499,7 @@ package android { field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344 field public static final int unselectedAlpha = 16843278; // 0x101020e field public static final int updatePeriodMillis = 16843344; // 0x1010250 + field public static final int usageInfoRequired = 16844185; // 0x1010599 field public static final int use32bitAbi = 16844053; // 0x1010515 field public static final int useAppZygote = 16844184; // 0x1010598 field public static final int useDefaultMargins = 16843641; // 0x1010379 @@ -3803,6 +3807,7 @@ package android.app { method public void overridePendingTransition(int, int); method public void postponeEnterTransition(); method public void recreate(); + method public void registerActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks); method public void registerForContextMenu(android.view.View); method public boolean releaseInstance(); method public final deprecated void removeDialog(int); @@ -3880,6 +3885,7 @@ package android.app { method public deprecated void stopManagingCursor(android.database.Cursor); method public void takeKeyEvents(boolean); method public void triggerSearch(java.lang.String, android.os.Bundle); + method public void unregisterActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks); method public void unregisterForContextMenu(android.view.View); field public static final int DEFAULT_KEYS_DIALER = 1; // 0x1 field public static final int DEFAULT_KEYS_DISABLE = 0; // 0x0 @@ -6352,7 +6358,6 @@ package android.app { method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager); - method public boolean supportsAmbientMode(); method public boolean supportsMultipleDisplays(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.WallpaperInfo> CREATOR; @@ -11171,8 +11176,8 @@ package android.content.pm { field public android.content.pm.ProviderInfo[] providers; field public android.content.pm.ActivityInfo[] receivers; field public android.content.pm.FeatureInfo[] reqFeatures; - field public java.lang.String[] requestedPermissions; - field public int[] requestedPermissionsFlags; + field public deprecated java.lang.String[] requestedPermissions; + field public deprecated int[] requestedPermissionsFlags; field public android.content.pm.ServiceInfo[] services; field public java.lang.String sharedUserId; field public int sharedUserLabel; @@ -11180,6 +11185,7 @@ package android.content.pm { field public android.content.pm.SigningInfo signingInfo; field public java.lang.String[] splitNames; field public int[] splitRevisionCodes; + field public android.content.pm.UsesPermissionInfo[] usesPermissions; field public deprecated int versionCode; field public java.lang.String versionName; } @@ -11655,6 +11661,7 @@ package android.content.pm { field public java.lang.String group; field public java.lang.CharSequence nonLocalizedDescription; field public deprecated int protectionLevel; + field public boolean usageInfoRequired; } public final class ProviderInfo extends android.content.pm.ComponentInfo implements android.os.Parcelable { @@ -11834,6 +11841,28 @@ package android.content.pm { field public static final android.os.Parcelable.Creator<android.content.pm.SigningInfo> CREATOR; } + public final class UsesPermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { + method public int describeContents(); + method public int getDataRetention(); + method public int getDataRetentionWeeks(); + method public int getDataSentOffDevice(); + method public int getDataSharedWithThirdParty(); + method public int getDataUsedForMonetization(); + method public int getFlags(); + method public java.lang.String getPermission(); + field public static final android.os.Parcelable.Creator<android.content.pm.UsesPermissionInfo> CREATOR; + field public static final int FLAG_REQUESTED_PERMISSION_GRANTED = 2; // 0x2 + field public static final int RETENTION_NOT_RETAINED = 1; // 0x1 + field public static final int RETENTION_SPECIFIED = 4; // 0x4 + field public static final int RETENTION_UNDEFINED = 0; // 0x0 + field public static final int RETENTION_UNLIMITED = 3; // 0x3 + field public static final int RETENTION_USER_SELECTED = 2; // 0x2 + field public static final int USAGE_NO = 3; // 0x3 + field public static final int USAGE_UNDEFINED = 0; // 0x0 + field public static final int USAGE_USER_TRIGGERED = 2; // 0x2 + field public static final int USAGE_YES = 1; // 0x1 + } + public final class VersionedPackage implements android.os.Parcelable { ctor public VersionedPackage(java.lang.String, int); ctor public VersionedPackage(java.lang.String, long); @@ -13943,6 +13972,7 @@ package android.graphics { } public final class Insets { + method public static android.graphics.Insets add(android.graphics.Insets, android.graphics.Insets); method public static android.graphics.Insets of(int, int, int, int); method public static android.graphics.Insets of(android.graphics.Rect); field public static final android.graphics.Insets NONE; @@ -14695,6 +14725,7 @@ package android.graphics { method public float getTranslationX(); method public float getTranslationY(); method public float getTranslationZ(); + method public long getUniqueId(); method public int getWidth(); method public boolean hasDisplayList(); method public boolean hasIdentityMatrix(); @@ -15048,6 +15079,7 @@ package android.graphics.drawable { method public void invalidateSelf(); method public boolean isAutoMirrored(); method public boolean isFilterBitmap(); + method public boolean isProjected(); method public boolean isStateful(); method public final boolean isVisible(); method public void jumpToCurrentState(); @@ -29411,11 +29443,24 @@ package android.net.wifi.p2p { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pConfig> CREATOR; + field public static final int GROUP_OWNER_BAND_2GHZ = 1; // 0x1 + field public static final int GROUP_OWNER_BAND_5GHZ = 2; // 0x2 + field public static final int GROUP_OWNER_BAND_AUTO = 0; // 0x0 field public java.lang.String deviceAddress; field public int groupOwnerIntent; field public android.net.wifi.WpsInfo wps; } + public static final class WifiP2pConfig.Builder { + ctor public WifiP2pConfig.Builder(); + method public android.net.wifi.p2p.WifiP2pConfig build(); + method public android.net.wifi.p2p.WifiP2pConfig.Builder enablePersistentMode(boolean); + method public android.net.wifi.p2p.WifiP2pConfig.Builder setDeviceAddress(android.net.MacAddress); + method public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOwnerBand(int); + method public android.net.wifi.p2p.WifiP2pConfig.Builder setNetworkName(java.lang.String); + method public android.net.wifi.p2p.WifiP2pConfig.Builder setPassphrase(java.lang.String); + } + public class WifiP2pDevice implements android.os.Parcelable { ctor public WifiP2pDevice(); ctor public WifiP2pDevice(android.net.wifi.p2p.WifiP2pDevice); @@ -29489,7 +29534,10 @@ package android.net.wifi.p2p { method public void removeLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener); method public void removeServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener); method public void requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener); + method public void requestDiscoveryState(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.DiscoveryStateListener); method public void requestGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.GroupInfoListener); + method public void requestNetworkInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.NetworkInfoListener); + method public void requestP2pState(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.P2pStateListener); method public void requestPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PeerListListener); method public void setDnsSdResponseListeners(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener, android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener); method public void setServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ServiceResponseListener); @@ -29534,6 +29582,10 @@ package android.net.wifi.p2p { method public abstract void onConnectionInfoAvailable(android.net.wifi.p2p.WifiP2pInfo); } + public static abstract interface WifiP2pManager.DiscoveryStateListener { + method public abstract void onDiscoveryStateAvailable(int); + } + public static abstract interface WifiP2pManager.DnsSdServiceResponseListener { method public abstract void onDnsSdServiceAvailable(java.lang.String, java.lang.String, android.net.wifi.p2p.WifiP2pDevice); } @@ -29546,6 +29598,14 @@ package android.net.wifi.p2p { method public abstract void onGroupInfoAvailable(android.net.wifi.p2p.WifiP2pGroup); } + public static abstract interface WifiP2pManager.NetworkInfoListener { + method public abstract void onNetworkInfoAvailable(android.net.NetworkInfo); + } + + public static abstract interface WifiP2pManager.P2pStateListener { + method public abstract void onP2pStateAvailable(int); + } + public static abstract interface WifiP2pManager.PeerListListener { method public abstract void onPeersAvailable(android.net.wifi.p2p.WifiP2pDeviceList); } @@ -40881,11 +40941,9 @@ package android.service.wallpaper { method public int getDesiredMinimumHeight(); method public int getDesiredMinimumWidth(); method public android.view.SurfaceHolder getSurfaceHolder(); - method public boolean isInAmbientMode(); method public boolean isPreview(); method public boolean isVisible(); method public void notifyColorsChanged(); - method public void onAmbientModeChanged(boolean, boolean); method public void onApplyWindowInsets(android.view.WindowInsets); method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean); method public android.app.WallpaperColors onComputeColors(); @@ -49265,6 +49323,7 @@ package android.view { method public void setLayoutDirection(int); method public void setLayoutParams(android.view.ViewGroup.LayoutParams); method public final void setLeft(int); + method public void setLeftTopRightBottom(int, int, int, int); method public void setLongClickable(boolean); method protected final void setMeasuredDimension(int, int); method public void setMinimumHeight(int); diff --git a/api/system-current.txt b/api/system-current.txt index 3f6f7e6056d5..6cfcad3c4b9f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -17,6 +17,7 @@ package android { field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING"; field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE"; field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"; + field public static final java.lang.String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER"; field public static final java.lang.String BACKUP = "android.permission.BACKUP"; field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS"; field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET"; @@ -158,6 +159,7 @@ package android { field public static final java.lang.String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS"; field public static final java.lang.String REBOOT = "android.permission.REBOOT"; field public static final java.lang.String RECEIVE_DATA_ACTIVITY_CHANGE = "android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"; + field public static final java.lang.String RECEIVE_DEVICE_CUSTOMIZATION_READY = "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY"; field public static final java.lang.String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST"; field public static final java.lang.String RECEIVE_WIFI_CREDENTIAL_CHANGE = "android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"; field public static final java.lang.String RECOVERY = "android.permission.RECOVERY"; @@ -171,6 +173,7 @@ package android { field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT"; field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS"; field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS"; + field public static final java.lang.String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY"; field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; field public static final java.lang.String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS"; field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION"; @@ -222,6 +225,7 @@ package android { field public static final int isVrOnly = 16844152; // 0x1010578 field public static final int requiredSystemPropertyName = 16844133; // 0x1010565 field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566 + field public static final int supportsAmbientMode = 16844173; // 0x101058d field public static final int userRestriction = 16844164; // 0x1010584 } @@ -553,6 +557,10 @@ package android.app { method public void onVrStateChanged(boolean); } + public final class WallpaperInfo implements android.os.Parcelable { + method public boolean supportsAmbientMode(); + } + public class WallpaperManager { method public void clearWallpaper(int, int); method public void setDisplayOffset(android.os.IBinder, int, int); @@ -1055,6 +1063,7 @@ package android.content { field public static final java.lang.String ACTION_BATTERY_LEVEL_CHANGED = "android.intent.action.BATTERY_LEVEL_CHANGED"; field public static final java.lang.String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY"; field public static final java.lang.String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED"; + field public static final java.lang.String ACTION_DEVICE_CUSTOMIZATION_READY = "android.intent.action.DEVICE_CUSTOMIZATION_READY"; field public static final java.lang.String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET"; field public static final java.lang.String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON"; field public static final java.lang.String ACTION_INSTALL_INSTANT_APP_PACKAGE = "android.intent.action.INSTALL_INSTANT_APP_PACKAGE"; @@ -1234,6 +1243,7 @@ package android.content.pm { method public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); method public void replacePreferredActivity(android.content.IntentFilter, int, java.util.List<android.content.ComponentName>, android.content.ComponentName); method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); + method public void sendDeviceCustomizationReadyBroadcast(); method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int); method public void setHarmfulAppWarning(java.lang.String, java.lang.CharSequence); method public deprecated java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, java.lang.String); @@ -3676,6 +3686,10 @@ package android.net.wifi { public class WifiManager { method public void connect(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener); + method public void connect(int, android.net.wifi.WifiManager.ActionListener); + method public void disable(int, android.net.wifi.WifiManager.ActionListener); + method public void disableEphemeralNetwork(java.lang.String); + method public void forget(int, android.net.wifi.WifiManager.ActionListener); method public java.util.List<android.net.wifi.WifiConfiguration> getAllMatchingWifiConfigs(java.util.List<android.net.wifi.ScanResult>); method public java.util.List<android.net.wifi.hotspot2.OsuProvider> getMatchingOsuProviders(java.util.List<android.net.wifi.ScanResult>); method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks(); @@ -3687,6 +3701,7 @@ package android.net.wifi { method public boolean isWifiApEnabled(); method public boolean isWifiScannerSupported(); method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler); + method public void save(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener); method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration); method public boolean startScan(android.os.WorkSource); method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback); @@ -5097,6 +5112,7 @@ package android.service.notification { ctor public NotificationAssistantService(); method public final void adjustNotification(android.service.notification.Adjustment); method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); + method public void onActionClicked(java.lang.String, android.app.Notification.Action, int); method public final android.os.IBinder onBind(android.content.Intent); method public void onNotificationDirectReply(java.lang.String); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification); @@ -5330,6 +5346,15 @@ package android.service.trust { } +package android.service.wallpaper { + + public class WallpaperService.Engine { + method public boolean isInAmbientMode(); + method public void onAmbientModeChanged(boolean, long); + } + +} + package android.telecom { public deprecated class AudioState implements android.os.Parcelable { diff --git a/api/test-current.txt b/api/test-current.txt index 738caeca1b64..c0f7ab63003b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -61,6 +61,7 @@ package android.app { } public class ActivityTaskManager { + method public void clearLaunchParamsForPackages(java.util.List<java.lang.String>); method public java.lang.String listAllStacks(); method public void moveTaskToStack(int, int, boolean); method public boolean moveTopActivityToPinnedStack(int, android.graphics.Rect); @@ -81,6 +82,10 @@ package android.app { field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0 } + public class AppDetailsActivity extends android.app.Activity { + ctor public AppDetailsActivity(); + } + public class AppOpsManager { method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long); method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long); @@ -1155,6 +1160,7 @@ package android.service.notification { ctor public NotificationAssistantService(); method public final void adjustNotification(android.service.notification.Adjustment); method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); + method public void onActionClicked(java.lang.String, android.app.Notification.Action, int); method public final android.os.IBinder onBind(android.content.Intent); method public void onNotificationDirectReply(java.lang.String); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 2fc7e03ca91f..c8405a279f7d 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -1338,8 +1338,9 @@ message PhysicalDropDetected { * Log bucketed battery charge cycles. * * Each bucket represents cycles of the battery past - * a given charge point. For example, bucket 1 is the - * lowest 1/8th of the battery, and bucket 8 is 100%. + * a given charge point. For example, if 10 cycle buckets are + * initialized, bucket 1 is the lowest 1/10th of the battery, + * and bucket 10 is 100%. * * Logged from: * /sys/class/power_supply/bms/cycle_count, via Vendor. @@ -1353,6 +1354,8 @@ message ChargeCyclesReported { optional int32 cycle_bucket_6 = 6; optional int32 cycle_bucket_7 = 7; optional int32 cycle_bucket_8 = 8; + optional int32 cycle_bucket_9 = 9; + optional int32 cycle_bucket_10 = 10; } /** diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index b9732a596b2d..8d61aba432d4 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -679,7 +679,7 @@ float LogEvent::GetFloat(size_t key, status_t* err) const { string LogEvent::ToString() const { string result; - result += StringPrintf("{ %lld %lld (%d)", (long long)mLogdTimestampNs, + result += StringPrintf("{ uid(%d) %lld %lld (%d)", mLogUid, (long long)mLogdTimestampNs, (long long)mElapsedTimestampNs, mTagId); for (const auto& value : mValues) { result += diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp index 504c5864f2ec..f1310db03d45 100644 --- a/cmds/statsd/src/stats_log_util.cpp +++ b/cmds/statsd/src/stats_log_util.cpp @@ -343,9 +343,11 @@ void writeFieldValueTreeToStreamHelper(int tagId, const std::vector<FieldValue>& } } if (isBytesField) { - protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum, - (const char*)dim.mValue.str_value.c_str(), - dim.mValue.str_value.length()); + if (dim.mValue.str_value.length() > 0) { + protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum, + (const char*)dim.mValue.str_value.c_str(), + dim.mValue.str_value.length()); + } } else { protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value); } diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp index 90dfa87abeaa..3a5be43ed695 100644 --- a/cmds/statsd/tests/LogEvent_test.cpp +++ b/cmds/statsd/tests/LogEvent_test.cpp @@ -605,7 +605,44 @@ TEST(LogEventTest, TestBinaryFieldAtom) { EXPECT_EQ(orig_str, result_str); } +TEST(LogEventTest, TestBinaryFieldAtom_empty) { + Atom launcherAtom; + auto launcher_event = launcherAtom.mutable_launcher_event(); + launcher_event->set_action(stats::launcher::LauncherAction::LONGPRESS); + launcher_event->set_src_state(stats::launcher::LauncherState::OVERVIEW); + launcher_event->set_dst_state(stats::launcher::LauncherState::ALLAPPS); + + // empty string. + string extension_str; + + LogEvent event1(Atom::kLauncherEventFieldNumber, 1000); + + event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS); + event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW); + event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS); + event1.write(extension_str); + event1.init(); + + ProtoOutputStream proto; + event1.ToProto(proto); + std::vector<uint8_t> outData; + outData.resize(proto.size()); + size_t pos = 0; + auto iter = proto.data(); + while (iter.readBuffer() != NULL) { + size_t toRead = iter.currentToRead(); + std::memcpy(&(outData[pos]), iter.readBuffer(), toRead); + pos += toRead; + iter.rp()->move(toRead); + } + + std::string result_str(outData.begin(), outData.end()); + std::string orig_str; + launcherAtom.SerializeToString(&orig_str); + + EXPECT_EQ(orig_str, result_str); +} } // namespace statsd } // namespace os diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index c193e894be0b..25bd0330ad5c 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -1461,7 +1461,6 @@ Landroid/view/IWindowManager;->setShelfHeight(ZI)V Landroid/view/IWindowManager;->setStrictModeVisualIndicatorPreference(Ljava/lang/String;)V Landroid/view/IWindowManager;->showStrictModeViolation(Z)V Landroid/view/IWindowManager;->thawRotation()V -Landroid/view/IWindowSession$Stub$Proxy;->relayout(Landroid/view/IWindow;ILandroid/view/WindowManager$LayoutParams;IIIIJLandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/view/DisplayCutout$ParcelableWrapper;Landroid/util/MergedConfiguration;Landroid/view/Surface;)I Landroid/view/IWindowSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IWindowSession; Landroid/view/IWindowSession;->finishDrawing(Landroid/view/IWindow;)V Landroid/view/IWindowSession;->getInTouchMode()Z @@ -4367,7 +4366,6 @@ Lcom/google/android/util/AbstractMessageParser$Token$Type;->PHOTO:Lcom/google/an Lcom/google/android/util/AbstractMessageParser$Token$Type;->SMILEY:Lcom/google/android/util/AbstractMessageParser$Token$Type; Lcom/google/android/util/AbstractMessageParser$Token$Type;->values()[Lcom/google/android/util/AbstractMessageParser$Token$Type; Lcom/google/android/util/AbstractMessageParser$Token$Type;->YOUTUBE_VIDEO:Lcom/google/android/util/AbstractMessageParser$Token$Type; -Lcom/sun/nio/file/ExtendedWatchEventModifier;->FILE_TREE:Lcom/sun/nio/file/ExtendedWatchEventModifier; Lgov/nist/core/Debug;->printStackTrace(Ljava/lang/Exception;)V Lgov/nist/core/GenericObject;-><init>()V Lgov/nist/core/GenericObject;->dbgPrint()V @@ -4507,177 +4505,9 @@ Lgov/nist/javax/sip/address/SipUri;->setParameter(Ljava/lang/String;Ljava/lang/S Lgov/nist/javax/sip/address/SipUri;->setUserParam(Ljava/lang/String;)V Lgov/nist/javax/sip/parser/URLParser;-><init>(Ljava/lang/String;)V Lgov/nist/javax/sip/parser/URLParser;->sipURL(Z)Lgov/nist/javax/sip/address/SipUri; -Ljava/lang/DexCache;->dexFile:J -Ljava/lang/invoke/SerializedLambda;-><init>(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V -Ljava/lang/invoke/SerializedLambda;->getCapturedArg(I)Ljava/lang/Object; -Ljava/lang/invoke/SerializedLambda;->getCapturedArgCount()I -Ljava/lang/invoke/SerializedLambda;->getCapturingClass()Ljava/lang/String; -Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceClass()Ljava/lang/String; -Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceMethodName()Ljava/lang/String; -Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceMethodSignature()Ljava/lang/String; -Ljava/lang/invoke/SerializedLambda;->getImplClass()Ljava/lang/String; -Ljava/lang/invoke/SerializedLambda;->getImplMethodKind()I -Ljava/lang/invoke/SerializedLambda;->getImplMethodName()Ljava/lang/String; -Ljava/lang/invoke/SerializedLambda;->getImplMethodSignature()Ljava/lang/String; -Ljava/lang/invoke/SerializedLambda;->getInstantiatedMethodType()Ljava/lang/String; -Ljava/lang/UNIXProcess;->pid:I -Ljava/net/AddressCache$AddressCacheEntry;-><init>(Ljava/lang/Object;)V -Ljava/net/AddressCache$AddressCacheEntry;->expiryNanos:J -Ljava/net/AddressCache$AddressCacheEntry;->value:Ljava/lang/Object; -Ljava/net/AddressCache$AddressCacheKey;->mHostname:Ljava/lang/String; -Ljava/net/AddressCache;->cache:Llibcore/util/BasicLruCache; -Ljava/net/Inet6AddressImpl;->addressCache:Ljava/net/AddressCache; -Ljava/net/PlainSocketImpl;-><init>()V -Ljava/nio/DirectByteBuffer;->cleaner()Lsun/misc/Cleaner; -Ljava/nio/file/FileTreeWalker;->followLinks:Z -Ljava/nio/file/FileTreeWalker;->linkOptions:[Ljava/nio/file/LinkOption; -Ljava/nio/file/FileTreeWalker;->maxDepth:I -Ljava/util/zip/ZipFile$ZipEntryIterator;->nextElement()Ljava/util/zip/ZipEntry; Ljunit/framework/TestCase;->fName:Ljava/lang/String; Ljunit/framework/TestSuite;->isPublicTestMethod(Ljava/lang/reflect/Method;)Z Ljunit/framework/TestSuite;->isTestMethod(Ljava/lang/reflect/Method;)Z -Llibcore/icu/DateIntervalFormat;->formatDateRange(JJILjava/lang/String;)Ljava/lang/String; -Llibcore/icu/ICU;->CACHED_PATTERNS:Llibcore/util/BasicLruCache; -Llibcore/icu/ICU;->getBestDateTimePattern(Ljava/lang/String;Ljava/util/Locale;)Ljava/lang/String; -Llibcore/icu/ICU;->getBestDateTimePatternNative(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; -Llibcore/icu/ICU;->getDateFormatOrder(Ljava/lang/String;)[C -Llibcore/icu/LocaleData;->firstDayOfWeek:Ljava/lang/Integer; -Llibcore/icu/LocaleData;->get(Ljava/util/Locale;)Llibcore/icu/LocaleData; -Llibcore/icu/LocaleData;->longStandAloneWeekdayNames:[Ljava/lang/String; -Llibcore/icu/LocaleData;->mapInvalidAndNullLocales(Ljava/util/Locale;)Ljava/util/Locale; -Llibcore/icu/LocaleData;->minimalDaysInFirstWeek:Ljava/lang/Integer; -Llibcore/icu/LocaleData;->shortMonthNames:[Ljava/lang/String; -Llibcore/icu/LocaleData;->shortStandAloneMonthNames:[Ljava/lang/String; -Llibcore/icu/LocaleData;->shortStandAloneWeekdayNames:[Ljava/lang/String; -Llibcore/icu/LocaleData;->timeFormat_Hm:Ljava/lang/String; -Llibcore/icu/LocaleData;->timeFormat_hm:Ljava/lang/String; -Llibcore/icu/LocaleData;->today:Ljava/lang/String; -Llibcore/icu/LocaleData;->tomorrow:Ljava/lang/String; -Llibcore/icu/LocaleData;->zeroDigit:C -Llibcore/icu/TimeZoneNames;->forLocale(Ljava/util/Locale;)[Ljava/lang/String; -Llibcore/io/AsynchronousCloseMonitor;->signalBlockedThreads(Ljava/io/FileDescriptor;)V -Llibcore/io/BlockGuardOs;-><init>(Llibcore/io/Os;)V -Llibcore/io/BlockGuardOs;->chmod(Ljava/lang/String;I)V -Llibcore/io/BlockGuardOs;->chown(Ljava/lang/String;II)V -Llibcore/io/BlockGuardOs;->close(Ljava/io/FileDescriptor;)V -Llibcore/io/BlockGuardOs;->fchmod(Ljava/io/FileDescriptor;I)V -Llibcore/io/BlockGuardOs;->fchown(Ljava/io/FileDescriptor;II)V -Llibcore/io/BlockGuardOs;->fdatasync(Ljava/io/FileDescriptor;)V -Llibcore/io/BlockGuardOs;->fstat(Ljava/io/FileDescriptor;)Landroid/system/StructStat; -Llibcore/io/BlockGuardOs;->fstatvfs(Ljava/io/FileDescriptor;)Landroid/system/StructStatVfs; -Llibcore/io/BlockGuardOs;->lchown(Ljava/lang/String;II)V -Llibcore/io/BlockGuardOs;->link(Ljava/lang/String;Ljava/lang/String;)V -Llibcore/io/BlockGuardOs;->lseek(Ljava/io/FileDescriptor;JI)J -Llibcore/io/BlockGuardOs;->lstat(Ljava/lang/String;)Landroid/system/StructStat; -Llibcore/io/BlockGuardOs;->mkdir(Ljava/lang/String;I)V -Llibcore/io/BlockGuardOs;->mkfifo(Ljava/lang/String;I)V -Llibcore/io/BlockGuardOs;->open(Ljava/lang/String;II)Ljava/io/FileDescriptor; -Llibcore/io/BlockGuardOs;->posix_fallocate(Ljava/io/FileDescriptor;JJ)V -Llibcore/io/BlockGuardOs;->pread(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;J)I -Llibcore/io/BlockGuardOs;->pread(Ljava/io/FileDescriptor;[BIIJ)I -Llibcore/io/BlockGuardOs;->pwrite(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;J)I -Llibcore/io/BlockGuardOs;->pwrite(Ljava/io/FileDescriptor;[BIIJ)I -Llibcore/io/BlockGuardOs;->read(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;)I -Llibcore/io/BlockGuardOs;->read(Ljava/io/FileDescriptor;[BII)I -Llibcore/io/BlockGuardOs;->readlink(Ljava/lang/String;)Ljava/lang/String; -Llibcore/io/BlockGuardOs;->readv(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I -Llibcore/io/BlockGuardOs;->realpath(Ljava/lang/String;)Ljava/lang/String; -Llibcore/io/BlockGuardOs;->remove(Ljava/lang/String;)V -Llibcore/io/BlockGuardOs;->rename(Ljava/lang/String;Ljava/lang/String;)V -Llibcore/io/BlockGuardOs;->stat(Ljava/lang/String;)Landroid/system/StructStat; -Llibcore/io/BlockGuardOs;->statvfs(Ljava/lang/String;)Landroid/system/StructStatVfs; -Llibcore/io/BlockGuardOs;->symlink(Ljava/lang/String;Ljava/lang/String;)V -Llibcore/io/BlockGuardOs;->write(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;)I -Llibcore/io/BlockGuardOs;->write(Ljava/io/FileDescriptor;[BII)I -Llibcore/io/BlockGuardOs;->writev(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I -Llibcore/io/BufferIterator;->readByte()B -Llibcore/io/BufferIterator;->readByteArray([BII)V -Llibcore/io/BufferIterator;->readInt()I -Llibcore/io/BufferIterator;->readIntArray([III)V -Llibcore/io/BufferIterator;->seek(I)V -Llibcore/io/BufferIterator;->skip(I)V -Llibcore/io/DropBox;->addText(Ljava/lang/String;Ljava/lang/String;)V -Llibcore/io/ForwardingOs;-><init>(Llibcore/io/Os;)V -Llibcore/io/ForwardingOs;->access(Ljava/lang/String;I)Z -Llibcore/io/ForwardingOs;->chmod(Ljava/lang/String;I)V -Llibcore/io/ForwardingOs;->chown(Ljava/lang/String;II)V -Llibcore/io/ForwardingOs;->getenv(Ljava/lang/String;)Ljava/lang/String; -Llibcore/io/ForwardingOs;->lchown(Ljava/lang/String;II)V -Llibcore/io/ForwardingOs;->link(Ljava/lang/String;Ljava/lang/String;)V -Llibcore/io/ForwardingOs;->lstat(Ljava/lang/String;)Landroid/system/StructStat; -Llibcore/io/ForwardingOs;->mkdir(Ljava/lang/String;I)V -Llibcore/io/ForwardingOs;->mkfifo(Ljava/lang/String;I)V -Llibcore/io/ForwardingOs;->open(Ljava/lang/String;II)Ljava/io/FileDescriptor; -Llibcore/io/ForwardingOs;->os:Llibcore/io/Os; -Llibcore/io/ForwardingOs;->readlink(Ljava/lang/String;)Ljava/lang/String; -Llibcore/io/ForwardingOs;->remove(Ljava/lang/String;)V -Llibcore/io/ForwardingOs;->removexattr(Ljava/lang/String;Ljava/lang/String;)V -Llibcore/io/ForwardingOs;->rename(Ljava/lang/String;Ljava/lang/String;)V -Llibcore/io/ForwardingOs;->setenv(Ljava/lang/String;Ljava/lang/String;Z)V -Llibcore/io/ForwardingOs;->setsockoptTimeval(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V -Llibcore/io/ForwardingOs;->setxattr(Ljava/lang/String;Ljava/lang/String;[BI)V -Llibcore/io/ForwardingOs;->stat(Ljava/lang/String;)Landroid/system/StructStat; -Llibcore/io/ForwardingOs;->statvfs(Ljava/lang/String;)Landroid/system/StructStatVfs; -Llibcore/io/ForwardingOs;->symlink(Ljava/lang/String;Ljava/lang/String;)V -Llibcore/io/ForwardingOs;->sysconf(I)J -Llibcore/io/ForwardingOs;->unlink(Ljava/lang/String;)V -Llibcore/io/IoBridge;->isConnected(Ljava/io/FileDescriptor;Ljava/net/InetAddress;III)Z -Llibcore/io/IoUtils;->closeQuietly(Ljava/io/FileDescriptor;)V -Llibcore/io/IoUtils;->closeQuietly(Ljava/lang/AutoCloseable;)V -Llibcore/io/IoUtils;->closeQuietly(Ljava/net/Socket;)V -Llibcore/io/IoUtils;->readFileAsByteArray(Ljava/lang/String;)[B -Llibcore/io/IoUtils;->readFileAsString(Ljava/lang/String;)Ljava/lang/String; -Llibcore/io/IoUtils;->setBlocking(Ljava/io/FileDescriptor;Z)V -Llibcore/io/MemoryMappedFile;->bigEndianIterator()Llibcore/io/BufferIterator; -Llibcore/io/MemoryMappedFile;->mmapRO(Ljava/lang/String;)Llibcore/io/MemoryMappedFile; -Llibcore/io/Os;->chmod(Ljava/lang/String;I)V -Llibcore/io/Os;->close(Ljava/io/FileDescriptor;)V -Llibcore/io/Os;->connect(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V -Llibcore/io/Os;->gai_strerror(I)Ljava/lang/String; -Llibcore/io/Os;->remove(Ljava/lang/String;)V -Llibcore/io/Os;->setenv(Ljava/lang/String;Ljava/lang/String;Z)V -Llibcore/io/Os;->setsockoptTimeval(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V -Llibcore/io/Os;->stat(Ljava/lang/String;)Landroid/system/StructStat; -Llibcore/io/Os;->strerror(I)Ljava/lang/String; -Llibcore/io/Os;->sysconf(I)J -Llibcore/io/Streams;->readAsciiLine(Ljava/io/InputStream;)Ljava/lang/String; -Llibcore/io/Streams;->readFully(Ljava/io/InputStream;)[B -Llibcore/io/Streams;->readFully(Ljava/io/InputStream;[B)V -Llibcore/io/Streams;->readSingleByte(Ljava/io/InputStream;)I -Llibcore/io/Streams;->skipAll(Ljava/io/InputStream;)V -Llibcore/io/Streams;->writeSingleByte(Ljava/io/OutputStream;I)V -Llibcore/net/event/NetworkEventDispatcher;->addListener(Llibcore/net/event/NetworkEventListener;)V -Llibcore/net/event/NetworkEventDispatcher;->getInstance()Llibcore/net/event/NetworkEventDispatcher; -Llibcore/net/event/NetworkEventListener;-><init>()V -Llibcore/net/http/HttpDate;->format(Ljava/util/Date;)Ljava/lang/String; -Llibcore/net/http/HttpDate;->parse(Ljava/lang/String;)Ljava/util/Date; -Llibcore/net/MimeUtils;->guessExtensionFromMimeType(Ljava/lang/String;)Ljava/lang/String; -Llibcore/net/MimeUtils;->guessMimeTypeFromExtension(Ljava/lang/String;)Ljava/lang/String; -Llibcore/net/NetworkSecurityPolicy;->isCleartextTrafficPermitted()Z -Llibcore/util/BasicLruCache;-><init>(I)V -Llibcore/util/BasicLruCache;->evictAll()V -Llibcore/util/BasicLruCache;->get(Ljava/lang/Object;)Ljava/lang/Object; -Llibcore/util/BasicLruCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; -Llibcore/util/EmptyArray;->BYTE:[B -Llibcore/util/EmptyArray;->INT:[I -Llibcore/util/EmptyArray;->OBJECT:[Ljava/lang/Object; -Lorg/apache/harmony/dalvik/ddmc/Chunk;-><init>(ILjava/nio/ByteBuffer;)V -Lorg/apache/harmony/dalvik/ddmc/ChunkHandler;->CHUNK_ORDER:Ljava/nio/ByteOrder; -Lorg/apache/harmony/dalvik/ddmc/DdmServer;->broadcast(I)V -Lorg/apache/harmony/dalvik/ddmc/DdmServer;->sendChunk(Lorg/apache/harmony/dalvik/ddmc/Chunk;)V -Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;->getThreadStats()[B -Lorg/apache/harmony/xml/dom/ElementImpl;->localName:Ljava/lang/String; -Lorg/apache/harmony/xml/ExpatAttributes;-><init>()V -Lorg/apache/harmony/xml/ExpatParser$EntityParser;->depth:I -Lorg/apache/harmony/xml/ExpatParser;-><init>(Ljava/lang/String;Lorg/apache/harmony/xml/ExpatReader;ZLjava/lang/String;Ljava/lang/String;)V -Lorg/apache/harmony/xml/ExpatParser;->append([BII)V -Lorg/apache/harmony/xml/ExpatParser;->append([CII)V -Lorg/apache/harmony/xml/ExpatParser;->attributes:Lorg/apache/harmony/xml/ExpatAttributes; -Lorg/apache/harmony/xml/ExpatParser;->cloneAttributes()Lorg/xml/sax/Attributes; -Lorg/apache/harmony/xml/ExpatParser;->finish()V -Lorg/apache/harmony/xml/ExpatParser;->xmlReader:Lorg/apache/harmony/xml/ExpatReader; -Lorg/apache/harmony/xml/ExpatReader;-><init>()V -Lorg/apache/harmony/xml/ExpatReader;->contentHandler:Lorg/xml/sax/ContentHandler; Lorg/apache/xalan/extensions/ExpressionContext;->getContextNode()Lorg/w3c/dom/Node; Lorg/apache/xalan/extensions/ExpressionContext;->getErrorListener()Ljavax/xml/transform/ErrorListener; Lorg/apache/xalan/extensions/ExpressionContext;->getVariableOrParam(Lorg/apache/xml/utils/QName;)Lorg/apache/xpath/objects/XObject; @@ -5356,431 +5186,3 @@ Lorg/ccil/cowan/tagsoup/XMLWriter;->htmlMode:Z Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutput(Ljava/io/Writer;)V Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutputProperty(Ljava/lang/String;Ljava/lang/String;)V Lorg/ccil/cowan/tagsoup/XMLWriter;->setPrefix(Ljava/lang/String;Ljava/lang/String;)V -Lorg/xml/sax/helpers/NamespaceSupport$Context;-><init>(Lorg/xml/sax/helpers/NamespaceSupport;)V -Lorg/xml/sax/helpers/ParserAdapter$AttributeListAdapter;-><init>(Lorg/xml/sax/helpers/ParserAdapter;)V -Lsun/misc/ASCIICaseInsensitiveComparator;->CASE_INSENSITIVE_ORDER:Ljava/util/Comparator; -Lsun/misc/ASCIICaseInsensitiveComparator;->lowerCaseHashCode(Ljava/lang/String;)I -Lsun/misc/BASE64Decoder;-><init>()V -Lsun/misc/BASE64Decoder;->pem_convert_array:[B -Lsun/misc/BASE64Encoder;-><init>()V -Lsun/misc/BASE64Encoder;->pem_array:[C -Lsun/misc/CEFormatException;-><init>(Ljava/lang/String;)V -Lsun/misc/CEStreamExhausted;-><init>()V -Lsun/misc/CharacterDecoder;-><init>()V -Lsun/misc/CharacterEncoder;-><init>()V -Lsun/misc/CharacterEncoder;->encodeBuffer([B)Ljava/lang/String; -Lsun/misc/CharacterEncoder;->encodeBufferPrefix(Ljava/io/OutputStream;)V -Lsun/misc/CharacterEncoder;->pStream:Ljava/io/PrintStream; -Lsun/misc/Cleaner;->create(Ljava/lang/Object;Ljava/lang/Runnable;)Lsun/misc/Cleaner; -Lsun/misc/FloatingDecimal;->$assertionsDisabled:Z -Lsun/misc/FloatingDecimal;->getHexDigit(Ljava/lang/String;I)I -Lsun/misc/FloatingDecimal;->stripLeadingZeros(Ljava/lang/String;)Ljava/lang/String; -Lsun/misc/FormattedFloatingDecimal$Form;->COMPATIBLE:Lsun/misc/FormattedFloatingDecimal$Form; -Lsun/misc/FormattedFloatingDecimal$Form;->DECIMAL_FLOAT:Lsun/misc/FormattedFloatingDecimal$Form; -Lsun/misc/FormattedFloatingDecimal$Form;->SCIENTIFIC:Lsun/misc/FormattedFloatingDecimal$Form; -Lsun/misc/FormattedFloatingDecimal;->$assertionsDisabled:Z -Lsun/misc/FpUtils;->$assertionsDisabled:Z -Lsun/misc/FpUtils;->rawCopySign(DD)D -Lsun/misc/HexDumpEncoder;-><init>()V -Lsun/misc/HexDumpEncoder;->currentByte:I -Lsun/misc/HexDumpEncoder;->offset:I -Lsun/misc/HexDumpEncoder;->thisLine:[B -Lsun/misc/HexDumpEncoder;->thisLineLength:I -Lsun/misc/IOUtils;->readFully(Ljava/io/InputStream;IZ)[B -Lsun/misc/JarIndex;-><init>([Ljava/lang/String;)V -Lsun/misc/JarIndex;->write(Ljava/io/OutputStream;)V -Lsun/misc/MessageUtils;-><init>()V -Lsun/misc/MetaIndex;->forJar(Ljava/io/File;)Lsun/misc/MetaIndex; -Lsun/misc/MetaIndex;->registerDirectory(Ljava/io/File;)V -Lsun/misc/VM;->maxDirectMemory()J -Lsun/net/ftp/FtpClient;-><init>()V -Lsun/net/util/IPAddressUtil;->isIPv4LiteralAddress(Ljava/lang/String;)Z -Lsun/net/util/IPAddressUtil;->isIPv6LiteralAddress(Ljava/lang/String;)Z -Lsun/net/www/MessageHeader;-><init>()V -Lsun/net/www/MessageHeader;-><init>(Ljava/io/InputStream;)V -Lsun/net/www/MessageHeader;->add(Ljava/lang/String;Ljava/lang/String;)V -Lsun/net/www/MessageHeader;->findValue(Ljava/lang/String;)Ljava/lang/String; -Lsun/net/www/MessageHeader;->prepend(Ljava/lang/String;Ljava/lang/String;)V -Lsun/net/www/MessageHeader;->print(Ljava/io/PrintStream;)V -Lsun/net/www/MessageHeader;->set(Ljava/lang/String;Ljava/lang/String;)V -Lsun/net/www/ParseUtil;->decode(Ljava/lang/String;)Ljava/lang/String; -Lsun/net/www/ParseUtil;->encodePath(Ljava/lang/String;Z)Ljava/lang/String; -Lsun/net/www/ParseUtil;->fileToEncodedURL(Ljava/io/File;)Ljava/net/URL; -Lsun/net/www/URLConnection;-><init>(Ljava/net/URL;)V -Lsun/net/www/URLConnection;->setProperties(Lsun/net/www/MessageHeader;)V -Lsun/nio/ch/DirectBuffer;->address()J -Lsun/nio/ch/FileChannelImpl;->unmap0(JJ)I -Lsun/nio/ch/SelectorImpl;->publicSelectedKeys:Ljava/util/Set; -Lsun/nio/ch/SelectorImpl;->selectedKeys:Ljava/util/Set; -Lsun/nio/cs/HistoricallyNamedCharset;->historicalName()Ljava/lang/String; -Lsun/nio/cs/ThreadLocalCoders;->decoderFor(Ljava/lang/Object;)Ljava/nio/charset/CharsetDecoder; -Lsun/nio/fs/BasicFileAttributesHolder;->get()Ljava/nio/file/attribute/BasicFileAttributes; -Lsun/reflect/misc/ReflectUtil;->checkPackageAccess(Ljava/lang/Class;)V -Lsun/reflect/misc/ReflectUtil;->checkPackageAccess(Ljava/lang/String;)V -Lsun/reflect/misc/ReflectUtil;->isPackageAccessible(Ljava/lang/Class;)Z -Lsun/reflect/misc/ReflectUtil;->isSubclassOf(Ljava/lang/Class;Ljava/lang/Class;)Z -Lsun/reflect/Reflection;->ensureMemberAccess(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;I)V -Lsun/reflect/Reflection;->isSubclassOf(Ljava/lang/Class;Ljava/lang/Class;)Z -Lsun/security/action/GetBooleanAction;-><init>(Ljava/lang/String;)V -Lsun/security/action/GetIntegerAction;-><init>(Ljava/lang/String;I)V -Lsun/security/action/GetPropertyAction;-><init>(Ljava/lang/String;)V -Lsun/security/action/GetPropertyAction;-><init>(Ljava/lang/String;Ljava/lang/String;)V -Lsun/security/jca/GetInstance$Instance;->impl:Ljava/lang/Object; -Lsun/security/jca/GetInstance$Instance;->provider:Ljava/security/Provider; -Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Lsun/security/jca/GetInstance$Instance; -Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)Lsun/security/jca/GetInstance$Instance; -Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;Ljava/security/Provider;)Lsun/security/jca/GetInstance$Instance; -Lsun/security/jca/JCAUtil;->getSecureRandom()Ljava/security/SecureRandom; -Lsun/security/jca/ProviderConfig;->argument:Ljava/lang/String; -Lsun/security/jca/ProviderConfig;->CL_STRING:[Ljava/lang/Class; -Lsun/security/jca/ProviderConfig;->disableLoad()V -Lsun/security/jca/ProviderConfig;->hasArgument()Z -Lsun/security/jca/ProviderList;->getService(Ljava/lang/String;Ljava/lang/String;)Ljava/security/Provider$Service; -Lsun/security/jca/Providers;->getProviderList()Lsun/security/jca/ProviderList; -Lsun/security/jca/Providers;->startJarVerification()Ljava/lang/Object; -Lsun/security/jca/Providers;->stopJarVerification(Ljava/lang/Object;)V -Lsun/security/pkcs/ContentInfo;-><init>(Lsun/security/util/ObjectIdentifier;Lsun/security/util/DerValue;)V -Lsun/security/pkcs/ContentInfo;-><init>([B)V -Lsun/security/pkcs/ContentInfo;->DATA_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/pkcs/ContentInfo;->encode(Lsun/security/util/DerOutputStream;)V -Lsun/security/pkcs/ContentInfo;->getData()[B -Lsun/security/pkcs/ParsingException;-><init>(Ljava/lang/String;)V -Lsun/security/pkcs/PKCS7;-><init>([B)V -Lsun/security/pkcs/PKCS7;-><init>([Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/ContentInfo;[Ljava/security/cert/X509Certificate;[Ljava/security/cert/X509CRL;[Lsun/security/pkcs/SignerInfo;)V -Lsun/security/pkcs/PKCS7;-><init>([Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/ContentInfo;[Ljava/security/cert/X509Certificate;[Lsun/security/pkcs/SignerInfo;)V -Lsun/security/pkcs/PKCS7;->encodeSignedData(Ljava/io/OutputStream;)V -Lsun/security/pkcs/PKCS7;->getCertificates()[Ljava/security/cert/X509Certificate; -Lsun/security/pkcs/PKCS7;->getContentInfo()Lsun/security/pkcs/ContentInfo; -Lsun/security/pkcs/PKCS7;->getSignerInfos()[Lsun/security/pkcs/SignerInfo; -Lsun/security/pkcs/PKCS7;->verify(Lsun/security/pkcs/SignerInfo;[B)Lsun/security/pkcs/SignerInfo; -Lsun/security/pkcs/PKCS7;->verify([B)[Lsun/security/pkcs/SignerInfo; -Lsun/security/pkcs/PKCS8Key;-><init>()V -Lsun/security/pkcs/PKCS8Key;->algid:Lsun/security/x509/AlgorithmId; -Lsun/security/pkcs/PKCS8Key;->encodedKey:[B -Lsun/security/pkcs/PKCS8Key;->key:[B -Lsun/security/pkcs/PKCS9Attribute;-><init>(Ljava/lang/String;Ljava/lang/Object;)V -Lsun/security/pkcs/PKCS9Attribute;-><init>(Lsun/security/util/DerValue;)V -Lsun/security/pkcs/PKCS9Attribute;-><init>(Lsun/security/util/ObjectIdentifier;Ljava/lang/Object;)V -Lsun/security/pkcs/PKCS9Attribute;->CONTENT_TYPE_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/pkcs/PKCS9Attribute;->derEncode(Ljava/io/OutputStream;)V -Lsun/security/pkcs/PKCS9Attribute;->EMAIL_ADDRESS_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/pkcs/PKCS9Attribute;->getOID()Lsun/security/util/ObjectIdentifier; -Lsun/security/pkcs/PKCS9Attribute;->getValue()Ljava/lang/Object; -Lsun/security/pkcs/PKCS9Attribute;->MESSAGE_DIGEST_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/pkcs/PKCS9Attribute;->SIGNING_TIME_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/pkcs/PKCS9Attributes;-><init>(Lsun/security/util/DerInputStream;)V -Lsun/security/pkcs/PKCS9Attributes;-><init>(Lsun/security/util/DerInputStream;Z)V -Lsun/security/pkcs/PKCS9Attributes;-><init>([Lsun/security/pkcs/PKCS9Attribute;)V -Lsun/security/pkcs/PKCS9Attributes;->encode(BLjava/io/OutputStream;)V -Lsun/security/pkcs/PKCS9Attributes;->getAttribute(Ljava/lang/String;)Lsun/security/pkcs/PKCS9Attribute; -Lsun/security/pkcs/PKCS9Attributes;->getAttributeValue(Lsun/security/util/ObjectIdentifier;)Ljava/lang/Object; -Lsun/security/pkcs/PKCS9Attributes;->getDerEncoding()[B -Lsun/security/pkcs/SignerInfo;-><init>(Lsun/security/x509/X500Name;Ljava/math/BigInteger;Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/PKCS9Attributes;Lsun/security/x509/AlgorithmId;[BLsun/security/pkcs/PKCS9Attributes;)V -Lsun/security/pkcs/SignerInfo;-><init>(Lsun/security/x509/X500Name;Ljava/math/BigInteger;Lsun/security/x509/AlgorithmId;Lsun/security/x509/AlgorithmId;[B)V -Lsun/security/pkcs/SignerInfo;->getCertificate(Lsun/security/pkcs/PKCS7;)Ljava/security/cert/X509Certificate; -Lsun/security/pkcs/SignerInfo;->getCertificateChain(Lsun/security/pkcs/PKCS7;)Ljava/util/ArrayList; -Lsun/security/pkcs/SignerInfo;->getDigestAlgorithmId()Lsun/security/x509/AlgorithmId; -Lsun/security/pkcs/SignerInfo;->getDigestEncryptionAlgorithmId()Lsun/security/x509/AlgorithmId; -Lsun/security/pkcs/SignerInfo;->getEncryptedDigest()[B -Lsun/security/provider/certpath/X509CertificatePair;->clearCache()V -Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/io/InputStream;)V -Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/io/InputStream;Ljava/lang/String;)V -Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/util/List;)V -Lsun/security/provider/certpath/X509CertPath;->certs:Ljava/util/List; -Lsun/security/provider/certpath/X509CertPath;->getEncodingsStatic()Ljava/util/Iterator; -Lsun/security/provider/X509Factory;->addToCache(Lsun/security/util/Cache;[BLjava/lang/Object;)V -Lsun/security/provider/X509Factory;->certCache:Lsun/security/util/Cache; -Lsun/security/provider/X509Factory;->crlCache:Lsun/security/util/Cache; -Lsun/security/provider/X509Factory;->getFromCache(Lsun/security/util/Cache;[B)Ljava/lang/Object; -Lsun/security/provider/X509Factory;->intern(Ljava/security/cert/X509Certificate;)Lsun/security/x509/X509CertImpl; -Lsun/security/provider/X509Factory;->intern(Ljava/security/cert/X509CRL;)Lsun/security/x509/X509CRLImpl; -Lsun/security/timestamp/TimestampToken;-><init>([B)V -Lsun/security/timestamp/TimestampToken;->getDate()Ljava/util/Date; -Lsun/security/timestamp/TimestampToken;->getHashAlgorithm()Lsun/security/x509/AlgorithmId; -Lsun/security/timestamp/TimestampToken;->getHashedMessage()[B -Lsun/security/timestamp/TimestampToken;->getNonce()Ljava/math/BigInteger; -Lsun/security/util/BitArray;-><init>(I[B)V -Lsun/security/util/BitArray;->toByteArray()[B -Lsun/security/util/Cache;-><init>()V -Lsun/security/util/Cache;->clear()V -Lsun/security/util/Cache;->get(Ljava/lang/Object;)Ljava/lang/Object; -Lsun/security/util/Cache;->newHardMemoryCache(I)Lsun/security/util/Cache; -Lsun/security/util/Cache;->put(Ljava/lang/Object;Ljava/lang/Object;)V -Lsun/security/util/Debug;->getInstance(Ljava/lang/String;)Lsun/security/util/Debug; -Lsun/security/util/Debug;->println()V -Lsun/security/util/Debug;->println(Ljava/lang/String;)V -Lsun/security/util/Debug;->toHexString(Ljava/math/BigInteger;)Ljava/lang/String; -Lsun/security/util/DerIndefLenConverter;-><init>()V -Lsun/security/util/DerIndefLenConverter;->convert([B)[B -Lsun/security/util/DerIndefLenConverter;->data:[B -Lsun/security/util/DerIndefLenConverter;->dataPos:I -Lsun/security/util/DerIndefLenConverter;->dataSize:I -Lsun/security/util/DerIndefLenConverter;->isIndefinite(I)Z -Lsun/security/util/DerIndefLenConverter;->newData:[B -Lsun/security/util/DerIndefLenConverter;->numOfTotalLenBytes:I -Lsun/security/util/DerIndefLenConverter;->parseLength()I -Lsun/security/util/DerIndefLenConverter;->parseTag()V -Lsun/security/util/DerIndefLenConverter;->parseValue(I)V -Lsun/security/util/DerIndefLenConverter;->writeLengthAndValue()V -Lsun/security/util/DerIndefLenConverter;->writeTag()V -Lsun/security/util/DerInputStream;-><init>([B)V -Lsun/security/util/DerInputStream;->available()I -Lsun/security/util/DerInputStream;->getBigInteger()Ljava/math/BigInteger; -Lsun/security/util/DerInputStream;->getBitString()[B -Lsun/security/util/DerInputStream;->getDerValue()Lsun/security/util/DerValue; -Lsun/security/util/DerInputStream;->getInteger()I -Lsun/security/util/DerInputStream;->getOctetString()[B -Lsun/security/util/DerInputStream;->getOID()Lsun/security/util/ObjectIdentifier; -Lsun/security/util/DerInputStream;->getSequence(I)[Lsun/security/util/DerValue; -Lsun/security/util/DerInputStream;->getSet(I)[Lsun/security/util/DerValue; -Lsun/security/util/DerInputStream;->getSet(IZ)[Lsun/security/util/DerValue; -Lsun/security/util/DerInputStream;->getUTCTime()Ljava/util/Date; -Lsun/security/util/DerInputStream;->getUTF8String()Ljava/lang/String; -Lsun/security/util/DerInputStream;->mark(I)V -Lsun/security/util/DerInputStream;->peekByte()I -Lsun/security/util/DerInputStream;->reset()V -Lsun/security/util/DerInputStream;->subStream(IZ)Lsun/security/util/DerInputStream; -Lsun/security/util/DerInputStream;->tag:B -Lsun/security/util/DerOutputStream;-><init>()V -Lsun/security/util/DerOutputStream;-><init>(I)V -Lsun/security/util/DerOutputStream;->putBitString([B)V -Lsun/security/util/DerOutputStream;->putBoolean(Z)V -Lsun/security/util/DerOutputStream;->putDerValue(Lsun/security/util/DerValue;)V -Lsun/security/util/DerOutputStream;->putIA5String(Ljava/lang/String;)V -Lsun/security/util/DerOutputStream;->putInteger(I)V -Lsun/security/util/DerOutputStream;->putInteger(Ljava/math/BigInteger;)V -Lsun/security/util/DerOutputStream;->putNull()V -Lsun/security/util/DerOutputStream;->putOctetString([B)V -Lsun/security/util/DerOutputStream;->putOID(Lsun/security/util/ObjectIdentifier;)V -Lsun/security/util/DerOutputStream;->putOrderedSetOf(B[Lsun/security/util/DerEncoder;)V -Lsun/security/util/DerOutputStream;->putPrintableString(Ljava/lang/String;)V -Lsun/security/util/DerOutputStream;->putSequence([Lsun/security/util/DerValue;)V -Lsun/security/util/DerOutputStream;->putUTCTime(Ljava/util/Date;)V -Lsun/security/util/DerOutputStream;->putUTF8String(Ljava/lang/String;)V -Lsun/security/util/DerOutputStream;->write(BLsun/security/util/DerOutputStream;)V -Lsun/security/util/DerOutputStream;->write(B[B)V -Lsun/security/util/DerValue;-><init>(B[B)V -Lsun/security/util/DerValue;-><init>(Ljava/io/InputStream;)V -Lsun/security/util/DerValue;-><init>(Ljava/lang/String;)V -Lsun/security/util/DerValue;-><init>([B)V -Lsun/security/util/DerValue;-><init>([BII)V -Lsun/security/util/DerValue;->buffer:Lsun/security/util/DerInputBuffer; -Lsun/security/util/DerValue;->createTag(BZB)B -Lsun/security/util/DerValue;->data:Lsun/security/util/DerInputStream; -Lsun/security/util/DerValue;->encode(Lsun/security/util/DerOutputStream;)V -Lsun/security/util/DerValue;->getAsString()Ljava/lang/String; -Lsun/security/util/DerValue;->getBigInteger()Ljava/math/BigInteger; -Lsun/security/util/DerValue;->getBitString()[B -Lsun/security/util/DerValue;->getData()Lsun/security/util/DerInputStream; -Lsun/security/util/DerValue;->getDataBytes()[B -Lsun/security/util/DerValue;->getOctetString()[B -Lsun/security/util/DerValue;->getOID()Lsun/security/util/ObjectIdentifier; -Lsun/security/util/DerValue;->getPositiveBigInteger()Ljava/math/BigInteger; -Lsun/security/util/DerValue;->getUnalignedBitString()Lsun/security/util/BitArray; -Lsun/security/util/DerValue;->isConstructed()Z -Lsun/security/util/DerValue;->isContextSpecific()Z -Lsun/security/util/DerValue;->isContextSpecific(B)Z -Lsun/security/util/DerValue;->isPrintableStringChar(C)Z -Lsun/security/util/DerValue;->resetTag(B)V -Lsun/security/util/DerValue;->tag:B -Lsun/security/util/DerValue;->toByteArray()[B -Lsun/security/util/DerValue;->toDerInputStream()Lsun/security/util/DerInputStream; -Lsun/security/util/ManifestDigester$Entry;->digest(Ljava/security/MessageDigest;)[B -Lsun/security/util/ManifestDigester$Entry;->digestWorkaround(Ljava/security/MessageDigest;)[B -Lsun/security/util/ManifestDigester;-><init>([B)V -Lsun/security/util/ManifestDigester;->get(Ljava/lang/String;Z)Lsun/security/util/ManifestDigester$Entry; -Lsun/security/util/ManifestDigester;->manifestDigest(Ljava/security/MessageDigest;)[B -Lsun/security/util/MemoryCache$HardCacheEntry;-><init>(Ljava/lang/Object;Ljava/lang/Object;J)V -Lsun/security/util/MemoryCache$SoftCacheEntry;-><init>(Ljava/lang/Object;Ljava/lang/Object;JLjava/lang/ref/ReferenceQueue;)V -Lsun/security/util/ObjectIdentifier;-><init>(Ljava/lang/String;)V -Lsun/security/util/ObjectIdentifier;-><init>([I)V -Lsun/security/util/ObjectIdentifier;->equals(Lsun/security/util/ObjectIdentifier;)Z -Lsun/security/util/ObjectIdentifier;->newInternal([I)Lsun/security/util/ObjectIdentifier; -Lsun/security/util/PropertyExpander;->expand(Ljava/lang/String;)Ljava/lang/String; -Lsun/security/util/ResourcesMgr;->getString(Ljava/lang/String;)Ljava/lang/String; -Lsun/security/util/SecurityConstants;->CREATE_CLASSLOADER_PERMISSION:Ljava/lang/RuntimePermission; -Lsun/security/util/SecurityConstants;->GET_CLASSLOADER_PERMISSION:Ljava/lang/RuntimePermission; -Lsun/security/util/SecurityConstants;->MODIFY_THREADGROUP_PERMISSION:Ljava/lang/RuntimePermission; -Lsun/security/util/SecurityConstants;->MODIFY_THREAD_PERMISSION:Ljava/lang/RuntimePermission; -Lsun/security/util/SignatureFileVerifier;->isBlockOrSF(Ljava/lang/String;)Z -Lsun/security/x509/AccessDescription;-><init>(Lsun/security/util/DerValue;)V -Lsun/security/x509/AccessDescription;->getAccessLocation()Lsun/security/x509/GeneralName; -Lsun/security/x509/AccessDescription;->getAccessMethod()Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;-><init>()V -Lsun/security/x509/AlgorithmId;-><init>(Lsun/security/util/ObjectIdentifier;)V -Lsun/security/x509/AlgorithmId;-><init>(Lsun/security/util/ObjectIdentifier;Ljava/security/AlgorithmParameters;)V -Lsun/security/x509/AlgorithmId;->derEncode(Ljava/io/OutputStream;)V -Lsun/security/x509/AlgorithmId;->DSA_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;->EC_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;->encode()[B -Lsun/security/x509/AlgorithmId;->encode(Lsun/security/util/DerOutputStream;)V -Lsun/security/x509/AlgorithmId;->equals(Lsun/security/x509/AlgorithmId;)Z -Lsun/security/x509/AlgorithmId;->getAlgorithmId(Ljava/lang/String;)Lsun/security/x509/AlgorithmId; -Lsun/security/x509/AlgorithmId;->getDigAlgFromSigAlg(Ljava/lang/String;)Ljava/lang/String; -Lsun/security/x509/AlgorithmId;->getEncAlgFromSigAlg(Ljava/lang/String;)Ljava/lang/String; -Lsun/security/x509/AlgorithmId;->getEncodedParams()[B -Lsun/security/x509/AlgorithmId;->getOID()Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;->getParameters()Ljava/security/AlgorithmParameters; -Lsun/security/x509/AlgorithmId;->MD2_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;->MD5_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;->params:Lsun/security/util/DerValue; -Lsun/security/x509/AlgorithmId;->parse(Lsun/security/util/DerValue;)Lsun/security/x509/AlgorithmId; -Lsun/security/x509/AlgorithmId;->RSAEncryption_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;->sha1WithRSAEncryption_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;->SHA256_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;->SHA384_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;->SHA512_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AlgorithmId;->SHA_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AttributeNameEnumeration;-><init>()V -Lsun/security/x509/AVA;-><init>(Lsun/security/util/ObjectIdentifier;Lsun/security/util/DerValue;)V -Lsun/security/x509/AVA;->getDerValue()Lsun/security/util/DerValue; -Lsun/security/x509/AVA;->getObjectIdentifier()Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AVA;->getValueString()Ljava/lang/String; -Lsun/security/x509/AVA;->toRFC2253CanonicalString()Ljava/lang/String; -Lsun/security/x509/AVAComparator;->INSTANCE:Ljava/util/Comparator; -Lsun/security/x509/AVAKeyword;->getOID(Ljava/lang/String;ILjava/util/Map;)Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AVAKeyword;->isCompliant(I)Z -Lsun/security/x509/AVAKeyword;->keyword:Ljava/lang/String; -Lsun/security/x509/AVAKeyword;->keywordMap:Ljava/util/Map; -Lsun/security/x509/AVAKeyword;->oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/AVAKeyword;->oidMap:Ljava/util/Map; -Lsun/security/x509/CertificateAlgorithmId;-><init>(Lsun/security/x509/AlgorithmId;)V -Lsun/security/x509/CertificateExtensions;-><init>()V -Lsun/security/x509/CertificateExtensions;-><init>(Lsun/security/util/DerInputStream;)V -Lsun/security/x509/CertificateExtensions;->encode(Ljava/io/OutputStream;Z)V -Lsun/security/x509/CertificateExtensions;->get(Ljava/lang/String;)Ljava/lang/Object; -Lsun/security/x509/CertificateExtensions;->set(Ljava/lang/String;Ljava/lang/Object;)V -Lsun/security/x509/CertificateIssuerName;-><init>(Lsun/security/x509/X500Name;)V -Lsun/security/x509/CertificateSerialNumber;-><init>(I)V -Lsun/security/x509/CertificateSerialNumber;-><init>(Ljava/math/BigInteger;)V -Lsun/security/x509/CertificateSubjectName;-><init>(Lsun/security/x509/X500Name;)V -Lsun/security/x509/CertificateSubjectName;->get(Ljava/lang/String;)Ljava/lang/Object; -Lsun/security/x509/CertificateValidity;-><init>(Ljava/util/Date;Ljava/util/Date;)V -Lsun/security/x509/CertificateVersion;-><init>(I)V -Lsun/security/x509/CertificateX509Key;-><init>(Ljava/security/PublicKey;)V -Lsun/security/x509/CRLDistributionPointsExtension;->encodeThis()V -Lsun/security/x509/CRLNumberExtension;-><init>(Ljava/lang/Boolean;Ljava/lang/Object;)V -Lsun/security/x509/CRLNumberExtension;->encodeThis()V -Lsun/security/x509/CRLNumberExtension;->get(Ljava/lang/String;)Ljava/lang/Object; -Lsun/security/x509/Extension;-><init>(Lsun/security/x509/Extension;)V -Lsun/security/x509/Extension;->encode(Lsun/security/util/DerOutputStream;)V -Lsun/security/x509/Extension;->getExtensionId()Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/GeneralName;-><init>(Lsun/security/x509/GeneralNameInterface;)V -Lsun/security/x509/GeneralName;->getName()Lsun/security/x509/GeneralNameInterface; -Lsun/security/x509/GeneralName;->getType()I -Lsun/security/x509/GeneralNames;-><init>()V -Lsun/security/x509/GeneralNames;-><init>(Lsun/security/util/DerValue;)V -Lsun/security/x509/GeneralNames;->add(Lsun/security/x509/GeneralName;)Lsun/security/x509/GeneralNames; -Lsun/security/x509/GeneralNames;->encode(Lsun/security/util/DerOutputStream;)V -Lsun/security/x509/GeneralNames;->isEmpty()Z -Lsun/security/x509/KeyIdentifier;-><init>(Ljava/security/PublicKey;)V -Lsun/security/x509/KeyIdentifier;->getIdentifier()[B -Lsun/security/x509/KeyIdentifier;->octetString:[B -Lsun/security/x509/KeyUsageExtension;-><init>([Z)V -Lsun/security/x509/KeyUsageExtension;->get(Ljava/lang/String;)Ljava/lang/Object; -Lsun/security/x509/NetscapeCertTypeExtension;-><init>([B)V -Lsun/security/x509/NetscapeCertTypeExtension;->get(Ljava/lang/String;)Ljava/lang/Object; -Lsun/security/x509/OIDMap$OIDInfo;->clazz:Ljava/lang/Class; -Lsun/security/x509/OIDMap;->getClass(Lsun/security/util/ObjectIdentifier;)Ljava/lang/Class; -Lsun/security/x509/OIDMap;->nameMap:Ljava/util/Map; -Lsun/security/x509/OIDMap;->oidMap:Ljava/util/Map; -Lsun/security/x509/PKIXExtensions;->CertificateIssuer_Id:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/SerialNumber;-><init>(Lsun/security/util/DerValue;)V -Lsun/security/x509/SubjectAlternativeNameExtension;->get(Ljava/lang/String;)Ljava/lang/Object; -Lsun/security/x509/SubjectKeyIdentifierExtension;-><init>([B)V -Lsun/security/x509/UniqueIdentity;-><init>(Lsun/security/util/DerInputStream;)V -Lsun/security/x509/UniqueIdentity;-><init>(Lsun/security/util/DerValue;)V -Lsun/security/x509/UniqueIdentity;->encode(Lsun/security/util/DerOutputStream;B)V -Lsun/security/x509/URIName;->getName()Ljava/lang/String; -Lsun/security/x509/URIName;->getScheme()Ljava/lang/String; -Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;)V -Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;)V -Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V -Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V -Lsun/security/x509/X500Name;-><init>(Lsun/security/util/DerInputStream;)V -Lsun/security/x509/X500Name;-><init>(Lsun/security/util/DerValue;)V -Lsun/security/x509/X500Name;-><init>([B)V -Lsun/security/x509/X500Name;->allAvas()Ljava/util/List; -Lsun/security/x509/X500Name;->asX500Name(Ljavax/security/auth/x500/X500Principal;)Lsun/security/x509/X500Name; -Lsun/security/x509/X500Name;->asX500Principal()Ljavax/security/auth/x500/X500Principal; -Lsun/security/x509/X500Name;->commonName_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->countryName_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->DNQUALIFIER_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->DOMAIN_COMPONENT_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->encode(Lsun/security/util/DerOutputStream;)V -Lsun/security/x509/X500Name;->GENERATIONQUALIFIER_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->getCommonName()Ljava/lang/String; -Lsun/security/x509/X500Name;->GIVENNAME_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->INITIALS_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->ipAddress_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->isEmpty()Z -Lsun/security/x509/X500Name;->localityName_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->orgName_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->orgUnitName_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->SERIALNUMBER_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->stateName_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->streetAddress_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->SURNAME_OID:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->title_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X500Name;->userid_oid:Lsun/security/util/ObjectIdentifier; -Lsun/security/x509/X509CertImpl;-><init>(Lsun/security/util/DerValue;)V -Lsun/security/x509/X509CertImpl;-><init>(Lsun/security/x509/X509CertInfo;)V -Lsun/security/x509/X509CertImpl;-><init>([B)V -Lsun/security/x509/X509CertImpl;->algId:Lsun/security/x509/AlgorithmId; -Lsun/security/x509/X509CertImpl;->get(Ljava/lang/String;)Ljava/lang/Object; -Lsun/security/x509/X509CertImpl;->getEncodedInternal()[B -Lsun/security/x509/X509CertImpl;->parse(Lsun/security/util/DerValue;)V -Lsun/security/x509/X509CertImpl;->readOnly:Z -Lsun/security/x509/X509CertImpl;->sign(Ljava/security/PrivateKey;Ljava/lang/String;)V -Lsun/security/x509/X509CertImpl;->signature:[B -Lsun/security/x509/X509CertImpl;->signedCert:[B -Lsun/security/x509/X509CertInfo;-><init>()V -Lsun/security/x509/X509CertInfo;-><init>([B)V -Lsun/security/x509/X509CertInfo;->get(Ljava/lang/String;)Ljava/lang/Object; -Lsun/security/x509/X509CertInfo;->set(Ljava/lang/String;Ljava/lang/Object;)V -Lsun/security/x509/X509CRLEntryImpl;->getExtension(Lsun/security/util/ObjectIdentifier;)Lsun/security/x509/Extension; -Lsun/security/x509/X509CRLImpl;-><init>(Ljava/io/InputStream;)V -Lsun/security/x509/X509CRLImpl;-><init>(Lsun/security/util/DerValue;)V -Lsun/security/x509/X509CRLImpl;-><init>([B)V -Lsun/security/x509/X509CRLImpl;->getEncodedInternal()[B -Lsun/security/x509/X509Key;-><init>()V -Lsun/security/x509/X509Key;->algid:Lsun/security/x509/AlgorithmId; -Lsun/security/x509/X509Key;->encodedKey:[B -Lsun/security/x509/X509Key;->key:[B -Lsun/security/x509/X509Key;->parse(Lsun/security/util/DerValue;)Ljava/security/PublicKey; -Lsun/security/x509/X509Key;->unusedBits:I -Lsun/util/calendar/AbstractCalendar;->getDayOfWeekDateOnOrBefore(JI)J -Lsun/util/calendar/AbstractCalendar;->getTimeOfDayValue(Lsun/util/calendar/CalendarDate;)J -Lsun/util/calendar/BaseCalendar$Date;->getNormalizedYear()I -Lsun/util/calendar/BaseCalendar$Date;->setNormalizedYear(I)V -Lsun/util/calendar/CalendarDate;->getDayOfMonth()I -Lsun/util/calendar/CalendarDate;->getMonth()I -Lsun/util/calendar/CalendarDate;->getTimeOfDay()J -Lsun/util/calendar/CalendarDate;->getYear()I -Lsun/util/calendar/CalendarDate;->setDate(III)Lsun/util/calendar/CalendarDate; -Lsun/util/calendar/CalendarDate;->setDayOfMonth(I)Lsun/util/calendar/CalendarDate; -Lsun/util/calendar/CalendarDate;->setHours(I)Lsun/util/calendar/CalendarDate; -Lsun/util/calendar/CalendarDate;->setMillis(I)Lsun/util/calendar/CalendarDate; -Lsun/util/calendar/CalendarDate;->setMinutes(I)Lsun/util/calendar/CalendarDate; -Lsun/util/calendar/CalendarDate;->setSeconds(I)Lsun/util/calendar/CalendarDate; -Lsun/util/calendar/CalendarSystem;->forName(Ljava/lang/String;)Lsun/util/calendar/CalendarSystem; -Lsun/util/calendar/CalendarSystem;->getGregorianCalendar()Lsun/util/calendar/Gregorian; -Lsun/util/calendar/CalendarSystem;->getTime(Lsun/util/calendar/CalendarDate;)J -Lsun/util/calendar/CalendarSystem;->newCalendarDate(Ljava/util/TimeZone;)Lsun/util/calendar/CalendarDate; -Lsun/util/calendar/CalendarSystem;->validate(Lsun/util/calendar/CalendarDate;)Z -Lsun/util/calendar/CalendarUtils;->floorDivide(II)I -Lsun/util/calendar/CalendarUtils;->floorDivide(JJ)J -Lsun/util/calendar/CalendarUtils;->mod(II)I -Lsun/util/calendar/CalendarUtils;->mod(JJ)J -Lsun/util/calendar/Era;-><init>(Ljava/lang/String;Ljava/lang/String;JZ)V -Lsun/util/calendar/Era;->getAbbreviation()Ljava/lang/String; -Lsun/util/calendar/Era;->getName()Ljava/lang/String; -Lsun/util/calendar/Era;->getSinceDate()Lsun/util/calendar/CalendarDate; -Lsun/util/calendar/ImmutableGregorianDate;->unsupported()V -Lsun/util/calendar/LocalGregorianCalendar$Date;->getNormalizedYear()I -Lsun/util/calendar/LocalGregorianCalendar$Date;->setEra(Lsun/util/calendar/Era;)Lsun/util/calendar/LocalGregorianCalendar$Date; -Lsun/util/calendar/LocalGregorianCalendar$Date;->setNormalizedYear(I)V -Lsun/util/calendar/LocalGregorianCalendar$Date;->setYear(I)Lsun/util/calendar/LocalGregorianCalendar$Date; -Lsun/util/calendar/LocalGregorianCalendar;->newCalendarDate(Ljava/util/TimeZone;)Lsun/util/calendar/LocalGregorianCalendar$Date; -Lsun/util/calendar/LocalGregorianCalendar;->normalize(Lsun/util/calendar/CalendarDate;)Z -Lsun/util/calendar/LocalGregorianCalendar;->validate(Lsun/util/calendar/CalendarDate;)Z diff --git a/config/preloaded-classes b/config/preloaded-classes index 5940c45466fb..30959256c922 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -4117,6 +4117,10 @@ com.android.internal.util.StateMachine$SmHandler$StateInfo com.android.internal.util.VirtualRefBasePtr com.android.internal.util.XmlUtils com.android.internal.util.XmlUtils$WriteMapCallback +com.android.internal.util.function.NonaConsumer +com.android.internal.util.function.NonaFunction +com.android.internal.util.function.OctConsumer +com.android.internal.util.function.OctFunction com.android.internal.util.function.HeptConsumer com.android.internal.util.function.HeptFunction com.android.internal.util.function.HexConsumer diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 83fab7e5a45d..05bb9a1c2139 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -827,6 +827,8 @@ public class Activity extends ContextThemeWrapper /** The screen observation manager. Always access via {@link #getIntelligenceManager()}. */ @Nullable private IntelligenceManager mIntelligenceManager; + private final ArrayList<Application.ActivityLifecycleCallbacks> mActivityLifecycleCallbacks = + new ArrayList<Application.ActivityLifecycleCallbacks>(); static final class NonConfigurationInstances { Object activity; @@ -1065,6 +1067,288 @@ public class Activity extends ContextThemeWrapper } /** + * Register an {@link Application.ActivityLifecycleCallbacks} instance that receives + * lifecycle callbacks for only this Activity. + * <p> + * In relation to any + * {@link Application#registerActivityLifecycleCallbacks Application registered callbacks}, + * the callbacks registered here will always occur nested within those callbacks. This means: + * <ul> + * <li>Pre events will first be sent to Application registered callbacks, then to callbacks + * registered here.</li> + * <li>{@link Application.ActivityLifecycleCallbacks#onActivityCreated(Activity, Bundle)}, + * {@link Application.ActivityLifecycleCallbacks#onActivityStarted(Activity)}, and + * {@link Application.ActivityLifecycleCallbacks#onActivityResumed(Activity)} will + * be sent first to Application registered callbacks, then to callbacks registered here. + * For all other events, callbacks registered here will be sent first.</li> + * <li>Post events will first be sent to callbacks registered here, then to + * Application registered callbacks.</li> + * </ul> + * <p> + * If multiple callbacks are registered here, they receive events in a first in (up through + * {@link Application.ActivityLifecycleCallbacks#onActivityPostResumed}, last out + * ordering. + * <p> + * It is strongly recommended to register this in the constructor of your Activity to ensure + * you get all available callbacks. As this callback is associated with only this Activity, + * it is not usually necessary to {@link #unregisterActivityLifecycleCallbacks unregister} it + * unless you specifically do not want to receive further lifecycle callbacks. + * + * @param callback The callback instance to register + */ + public void registerActivityLifecycleCallbacks( + @NonNull Application.ActivityLifecycleCallbacks callback) { + synchronized (mActivityLifecycleCallbacks) { + mActivityLifecycleCallbacks.add(callback); + } + } + + /** + * Unregister an {@link Application.ActivityLifecycleCallbacks} previously registered + * with {@link #registerActivityLifecycleCallbacks}. It will not receive any further + * callbacks. + * + * @param callback The callback instance to unregister + * @see #registerActivityLifecycleCallbacks + */ + public void unregisterActivityLifecycleCallbacks( + @NonNull Application.ActivityLifecycleCallbacks callback) { + synchronized (mActivityLifecycleCallbacks) { + mActivityLifecycleCallbacks.remove(callback); + } + } + + private void dispatchActivityPreCreated(@Nullable Bundle savedInstanceState) { + getApplication().dispatchActivityPreCreated(this, savedInstanceState); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPreCreated(this, + savedInstanceState); + } + } + } + + private void dispatchActivityCreated(@Nullable Bundle savedInstanceState) { + getApplication().dispatchActivityCreated(this, savedInstanceState); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityCreated(this, + savedInstanceState); + } + } + } + + private void dispatchActivityPostCreated(@Nullable Bundle savedInstanceState) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPostCreated(this, + savedInstanceState); + } + } + getApplication().dispatchActivityPostCreated(this, savedInstanceState); + } + + private void dispatchActivityPreStarted() { + getApplication().dispatchActivityPreStarted(this); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPreStarted(this); + } + } + } + + private void dispatchActivityStarted() { + getApplication().dispatchActivityStarted(this); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityStarted(this); + } + } + } + + private void dispatchActivityPostStarted() { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]) + .onActivityPostStarted(this); + } + } + getApplication().dispatchActivityPostStarted(this); + } + + private void dispatchActivityPreResumed() { + getApplication().dispatchActivityPreResumed(this); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPreResumed(this); + } + } + } + + private void dispatchActivityResumed() { + getApplication().dispatchActivityResumed(this); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityResumed(this); + } + } + } + + private void dispatchActivityPostResumed() { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPostResumed(this); + } + } + getApplication().dispatchActivityPostResumed(this); + } + + private void dispatchActivityPrePaused() { + getApplication().dispatchActivityPrePaused(this); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPrePaused(this); + } + } + } + + private void dispatchActivityPaused() { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPaused(this); + } + } + getApplication().dispatchActivityPaused(this); + } + + private void dispatchActivityPostPaused() { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPostPaused(this); + } + } + getApplication().dispatchActivityPostPaused(this); + } + + private void dispatchActivityPreStopped() { + getApplication().dispatchActivityPreStopped(this); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPreStopped(this); + } + } + } + + private void dispatchActivityStopped() { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityStopped(this); + } + } + getApplication().dispatchActivityStopped(this); + } + + private void dispatchActivityPostStopped() { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]) + .onActivityPostStopped(this); + } + } + getApplication().dispatchActivityPostStopped(this); + } + + private void dispatchActivityPreSaveInstanceState(@NonNull Bundle outState) { + getApplication().dispatchActivityPreSaveInstanceState(this, outState); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]) + .onActivityPreSaveInstanceState(this, outState); + } + } + } + + private void dispatchActivitySaveInstanceState(@NonNull Bundle outState) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]) + .onActivitySaveInstanceState(this, outState); + } + } + getApplication().dispatchActivitySaveInstanceState(this, outState); + } + + private void dispatchActivityPostSaveInstanceState(@NonNull Bundle outState) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]) + .onActivityPostSaveInstanceState(this, outState); + } + } + getApplication().dispatchActivityPostSaveInstanceState(this, outState); + } + + private void dispatchActivityPreDestroyed() { + getApplication().dispatchActivityPreDestroyed(this); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]) + .onActivityPreDestroyed(this); + } + } + } + + private void dispatchActivityDestroyed() { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityDestroyed(this); + } + } + getApplication().dispatchActivityDestroyed(this); + } + + private void dispatchActivityPostDestroyed() { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = callbacks.length - 1; i >= 0; i--) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]) + .onActivityPostDestroyed(this); + } + } + getApplication().dispatchActivityPostDestroyed(this); + } + + private Object[] collectActivityLifecycleCallbacks() { + Object[] callbacks = null; + synchronized (mActivityLifecycleCallbacks) { + if (mActivityLifecycleCallbacks.size() > 0) { + callbacks = mActivityLifecycleCallbacks.toArray(); + } + } + return callbacks; + } + + /** * Called when the activity is starting. This is where most initialization * should go: calling {@link #setContentView(int)} to inflate the * activity's UI, using {@link #findViewById} to programmatically interact @@ -1119,7 +1403,7 @@ public class Activity extends ContextThemeWrapper ? mLastNonConfigurationInstances.fragments : null); } mFragments.dispatchCreate(); - getApplication().dispatchActivityCreated(this, savedInstanceState); + dispatchActivityCreated(savedInstanceState); if (mVoiceInteractor != null) { mVoiceInteractor.attachActivity(this); } @@ -1355,7 +1639,7 @@ public class Activity extends ContextThemeWrapper mFragments.doLoaderStart(); - getApplication().dispatchActivityStarted(this); + dispatchActivityStarted(); if (mAutoFillResetNeeded) { getAutofillManager().onVisibleForAutofill(); @@ -1426,7 +1710,7 @@ public class Activity extends ContextThemeWrapper @CallSuper protected void onResume() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this); - getApplication().dispatchActivityResumed(this); + dispatchActivityResumed(); mActivityTransitionState.onResume(this, isTopOfTask()); enableAutofillCompatibilityIfNeeded(); if (mAutoFillResetNeeded) { @@ -1642,13 +1926,13 @@ public class Activity extends ContextThemeWrapper * @param outState The bundle to save the state to. */ final void performSaveInstanceState(@NonNull Bundle outState) { - getApplication().dispatchActivityPreSaveInstanceState(this, outState); + dispatchActivityPreSaveInstanceState(outState); onSaveInstanceState(outState); saveManagedDialogs(outState); mActivityTransitionState.saveState(outState); storeHasCurrentPermissionRequest(outState); if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState); - getApplication().dispatchActivityPostSaveInstanceState(this, outState); + dispatchActivityPostSaveInstanceState(outState); } /** @@ -1662,13 +1946,13 @@ public class Activity extends ContextThemeWrapper */ final void performSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) { - getApplication().dispatchActivityPreSaveInstanceState(this, outState); + dispatchActivityPreSaveInstanceState(outState); onSaveInstanceState(outState, outPersistentState); saveManagedDialogs(outState); storeHasCurrentPermissionRequest(outState); if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState + ", " + outPersistentState); - getApplication().dispatchActivityPostSaveInstanceState(this, outState); + dispatchActivityPostSaveInstanceState(outState); } /** @@ -1731,7 +2015,7 @@ public class Activity extends ContextThemeWrapper outState.putBoolean(AUTOFILL_RESET_NEEDED, true); getAutofillManager().onSaveInstanceState(outState); } - getApplication().dispatchActivitySaveInstanceState(this, outState); + dispatchActivitySaveInstanceState(outState); } /** @@ -1831,7 +2115,7 @@ public class Activity extends ContextThemeWrapper @CallSuper protected void onPause() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this); - getApplication().dispatchActivityPaused(this); + dispatchActivityPaused(); if (mAutoFillResetNeeded) { if (!mAutoFillIgnoreFirstResumePause) { if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill notifyViewExited " + this); @@ -2015,7 +2299,7 @@ public class Activity extends ContextThemeWrapper if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this); if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false); mActivityTransitionState.onStop(); - getApplication().dispatchActivityStopped(this); + dispatchActivityStopped(); mTranslucentCallback = null; mCalled = true; @@ -2104,7 +2388,7 @@ public class Activity extends ContextThemeWrapper mActionBar.onDestroy(); } - getApplication().dispatchActivityDestroyed(this); + dispatchActivityDestroyed(); notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_DESTROYED); @@ -7284,7 +7568,7 @@ public class Activity extends ContextThemeWrapper @UnsupportedAppUsage final void performCreate(Bundle icicle, PersistableBundle persistentState) { - getApplication().dispatchActivityPreCreated(this, icicle); + dispatchActivityPreCreated(icicle); mCanEnterPictureInPicture = true; restoreHasCurrentPermissionRequest(icicle); if (persistentState != null) { @@ -7299,7 +7583,7 @@ public class Activity extends ContextThemeWrapper com.android.internal.R.styleable.Window_windowNoDisplay, false); mFragments.dispatchActivityCreated(); mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions()); - getApplication().dispatchActivityPostCreated(this, icicle); + dispatchActivityPostCreated(icicle); } final void performNewIntent(@NonNull Intent intent) { @@ -7308,7 +7592,7 @@ public class Activity extends ContextThemeWrapper } final void performStart(String reason) { - getApplication().dispatchActivityPreStarted(this); + dispatchActivityPreStarted(); mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions()); mFragments.noteStateNotSaved(); mCalled = false; @@ -7351,7 +7635,7 @@ public class Activity extends ContextThemeWrapper } mActivityTransitionState.enterReady(this); - getApplication().dispatchActivityPostStarted(this); + dispatchActivityPostStarted(); } /** @@ -7406,7 +7690,7 @@ public class Activity extends ContextThemeWrapper } final void performResume(boolean followedByPause, String reason) { - getApplication().dispatchActivityPreResumed(this); + dispatchActivityPreResumed(); performRestart(true /* start */, reason); mFragments.execPendingActions(); @@ -7456,11 +7740,11 @@ public class Activity extends ContextThemeWrapper "Activity " + mComponent.toShortString() + " did not call through to super.onPostResume()"); } - getApplication().dispatchActivityPostResumed(this); + dispatchActivityPostResumed(); } final void performPause() { - getApplication().dispatchActivityPrePaused(this); + dispatchActivityPrePaused(); mDoReportFullyDrawn = false; mFragments.dispatchPause(); mCalled = false; @@ -7473,7 +7757,7 @@ public class Activity extends ContextThemeWrapper "Activity " + mComponent.toShortString() + " did not call through to super.onPause()"); } - getApplication().dispatchActivityPostPaused(this); + dispatchActivityPostPaused(); } final void performUserLeaving() { @@ -7489,7 +7773,7 @@ public class Activity extends ContextThemeWrapper mCanEnterPictureInPicture = false; if (!mStopped) { - getApplication().dispatchActivityPreStopped(this); + dispatchActivityPreStopped(); if (mWindow != null) { mWindow.closeAllPanels(); } @@ -7524,13 +7808,13 @@ public class Activity extends ContextThemeWrapper } mStopped = true; - getApplication().dispatchActivityPostStopped(this); + dispatchActivityPostStopped(); } mResumed = false; } final void performDestroy() { - getApplication().dispatchActivityPreDestroyed(this); + dispatchActivityPreDestroyed(); mDestroyed = true; mWindow.destroy(); mFragments.dispatchDestroy(); @@ -7540,7 +7824,7 @@ public class Activity extends ContextThemeWrapper if (mVoiceInteractor != null) { mVoiceInteractor.detachActivity(); } - getApplication().dispatchActivityPostDestroyed(this); + dispatchActivityPostDestroyed(); } final void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode, diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index 56ccf6f4a76f..6fdf7c8b4fac 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -433,4 +433,18 @@ public class ActivityTaskManager { } return sb.toString(); } + + /** + * Clears launch params for the given package. + * @param packageNames the names of the packages of which the launch params are to be cleared + */ + @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public void clearLaunchParamsForPackages(List<String> packageNames) { + try { + getService().clearLaunchParamsForPackages(packageNames); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/AppDetailsActivity.java b/core/java/android/app/AppDetailsActivity.java index cd36e634f54b..b71af88e99a3 100644 --- a/core/java/android/app/AppDetailsActivity.java +++ b/core/java/android/app/AppDetailsActivity.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.TestApi; import android.content.Intent; import android.os.Bundle; @@ -24,7 +25,9 @@ import android.os.Bundle; * * @hide */ +@TestApi public class AppDetailsActivity extends Activity { + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 8a797dcaf449..7312b2c8163e 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -2981,4 +2981,13 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowAsRuntimeException(); } } + + @Override + public void sendDeviceCustomizationReadyBroadcast() { + try { + mPM.sendDeviceCustomizationReadyBroadcast(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } } diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index 09b77d5b8d0a..777a4949a132 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -445,4 +445,9 @@ interface IActivityTaskManager { void setPackageScreenCompatMode(in String packageName, int mode); boolean getPackageAskScreenCompat(in String packageName); void setPackageAskScreenCompat(in String packageName, boolean ask); + + /** + * Clears launch params for given packages. + */ + void clearLaunchParamsForPackages(in List<String> packageNames); } diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 00547b4a5ce4..3a2038d40952 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -159,5 +159,5 @@ interface IWallpaperManager { /** * Called from SystemUI when it shows the AoD UI. */ - oneway void setInAmbientMode(boolean inAmbientMode, boolean animated); + oneway void setInAmbientMode(boolean inAmbientMode, long animationDuration); } diff --git a/core/java/android/app/Notification.aidl b/core/java/android/app/Notification.aidl index 9d8129ca601a..8a7156e971b4 100644 --- a/core/java/android/app/Notification.aidl +++ b/core/java/android/app/Notification.aidl @@ -17,3 +17,4 @@ package android.app; parcelable Notification; +parcelable Notification.Action;
\ No newline at end of file diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index c221616219e0..5002a8125d44 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5448,6 +5448,8 @@ public class Notification implements Parcelable p.ambient ? resolveAmbientColor(p) : resolveContrastColor(p)); } } + button.setIntTag(R.id.action0, R.id.notification_action_index_tag, + mActions.indexOf(action)); return button; } diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java index 3ea3da25e2fc..f0f7d899ff07 100644 --- a/core/java/android/app/WallpaperInfo.java +++ b/core/java/android/app/WallpaperInfo.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.SystemApi; import android.app.slice.Slice; import android.content.ComponentName; import android.content.Context; @@ -330,7 +331,9 @@ public final class WallpaperInfo implements Parcelable { * @see WallpaperService.Engine#onAmbientModeChanged(boolean, boolean) * @see WallpaperService.Engine#isInAmbientMode() * @return {@code true} if wallpaper can draw when in ambient mode. + * @hide */ + @SystemApi public boolean supportsAmbientMode() { return mSupportsAmbientMode; } diff --git a/core/java/android/app/backup/OWNERS b/core/java/android/app/backup/OWNERS index 1c9a43acfa65..673d85fe79c5 100644 --- a/core/java/android/app/backup/OWNERS +++ b/core/java/android/app/backup/OWNERS @@ -1,7 +1,6 @@ -artikz@google.com +anniemeng@google.com brufino@google.com bryanmawhinney@google.com ctate@google.com jorlow@google.com -mkarpinski@google.com diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java index 7988008f03c0..2174255a3619 100644 --- a/core/java/android/bluetooth/le/ScanRecord.java +++ b/core/java/android/bluetooth/le/ScanRecord.java @@ -116,6 +116,9 @@ public final class ScanRecord { */ @Nullable public byte[] getManufacturerSpecificData(int manufacturerId) { + if (mManufacturerSpecificData == null) { + return null; + } return mManufacturerSpecificData.get(manufacturerId); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index e7f0053721d1..6fd5061eee63 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4116,6 +4116,18 @@ public class Intent implements Parcelable, Cloneable { */ public static final String ACTION_DOCK_ACTIVE = "android.intent.action.DOCK_ACTIVE"; + /** + * Broadcast Action: Indicates that a new device customization has been + * downloaded and applied (packages installed, runtime resource overlays + * enabled, xml files copied, ...), and that it is time for components that + * need to for example clear their caches to do so now. + * + * @hide + */ + @SystemApi + public static final String ACTION_DEVICE_CUSTOMIZATION_READY = + "android.intent.action.DEVICE_CUSTOMIZATION_READY"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index d0eff2e0fda9..dbea821fab2b 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -676,4 +676,6 @@ interface IPackageManager { String getSystemTextClassifierPackageName(); boolean isPackageStateProtected(String packageName, int userId); + + void sendDeviceCustomizationReadyBroadcast(); } diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index ecdd810653ec..099d15ad61c2 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -22,6 +22,9 @@ import android.apex.ApexInfo; import android.os.Parcel; import android.os.Parcelable; +import java.util.ArrayList; +import java.util.List; + /** * Overall information about the contents of a package. This corresponds * to all of the information collected from AndroidManifest.xml. @@ -204,7 +207,10 @@ public class PackageInfo implements Parcelable { * {@link PackageManager#GET_PERMISSIONS} was set. This list includes * all permissions requested, even those that were not granted or known * by the system at install time. + * + * @deprecated Use {@link #usesPermissions} */ + @Deprecated public String[] requestedPermissions; /** @@ -214,10 +220,23 @@ public class PackageInfo implements Parcelable { * {@link PackageManager#GET_PERMISSIONS} was set. Each value matches * the corresponding entry in {@link #requestedPermissions}, and will have * the flag {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate. + * + * @deprecated Use {@link #usesPermissions} */ + @Deprecated public int[] requestedPermissionsFlags; /** + * Array of all {@link android.R.styleable#AndroidManifestUsesPermission + * <uses-permission>} tags included under <manifest>, + * or null if there were none. This is only filled in if the flag + * {@link PackageManager#GET_PERMISSIONS} was set. This list includes + * all permissions requested, even those that were not granted or known + * by the system at install time. + */ + public UsesPermissionInfo[] usesPermissions; + + /** * Flag for {@link #requestedPermissionsFlags}: the requested permission * is required for the application to run; the user can not optionally * disable it. Currently all permissions are required. @@ -456,6 +475,7 @@ public class PackageInfo implements Parcelable { dest.writeTypedArray(permissions, parcelableFlags); dest.writeStringArray(requestedPermissions); dest.writeIntArray(requestedPermissionsFlags); + dest.writeTypedArray(usesPermissions, parcelableFlags); dest.writeTypedArray(signatures, parcelableFlags); dest.writeTypedArray(configPreferences, parcelableFlags); dest.writeTypedArray(reqFeatures, parcelableFlags); @@ -520,6 +540,7 @@ public class PackageInfo implements Parcelable { permissions = source.createTypedArray(PermissionInfo.CREATOR); requestedPermissions = source.createStringArray(); requestedPermissionsFlags = source.createIntArray(); + usesPermissions = source.createTypedArray(UsesPermissionInfo.CREATOR); signatures = source.createTypedArray(Signature.CREATOR); configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR); reqFeatures = source.createTypedArray(FeatureInfo.CREATOR); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index a4b724ba48e7..6421dc5a3f68 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -6409,4 +6409,18 @@ public abstract class PackageManager { "isPackageStateProtected not implemented in subclass"); } + /** + * Notify to the rest of the system that a new device configuration has + * been prepared and that it is time to refresh caches. + * + * @see android.content.Intent#ACTION_DEVICE_CUSTOMIZATION_READY + * + * @hide + */ + @SystemApi + public void sendDeviceCustomizationReadyBroadcast() { + throw new UnsupportedOperationException( + "sendDeviceCustomizationReadyBroadcast not implemented in subclass"); + } + } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index d00c9a036a53..49189e53f385 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -785,18 +785,23 @@ public class PackageParser { pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags); } } - N = p.requestedPermissions.size(); + N = p.usesPermissionInfos.size(); if (N > 0) { pi.requestedPermissions = new String[N]; pi.requestedPermissionsFlags = new int[N]; + pi.usesPermissions = new UsesPermissionInfo[N]; for (int i=0; i<N; i++) { - final String perm = p.requestedPermissions.get(i); + UsesPermissionInfo info = p.usesPermissionInfos.get(i); + final String perm = info.getPermission(); pi.requestedPermissions[i] = perm; + int permissionFlags = 0; // The notion of required permissions is deprecated but for compatibility. - pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED; + permissionFlags |= PackageInfo.REQUESTED_PERMISSION_REQUIRED; if (grantedPermissions != null && grantedPermissions.contains(perm)) { - pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED; + permissionFlags |= PackageInfo.REQUESTED_PERMISSION_GRANTED; } + pi.requestedPermissionsFlags[i] = permissionFlags; + pi.usesPermissions[i] = new UsesPermissionInfo(info, permissionFlags); } } } @@ -2114,12 +2119,12 @@ public class PackageParser { return null; } } else if (tagName.equals(TAG_USES_PERMISSION)) { - if (!parseUsesPermission(pkg, res, parser)) { + if (!parseUsesPermission(pkg, res, parser, outError)) { return null; } } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M) || tagName.equals(TAG_USES_PERMISSION_SDK_23)) { - if (!parseUsesPermission(pkg, res, parser)) { + if (!parseUsesPermission(pkg, res, parser, outError)) { return null; } } else if (tagName.equals(TAG_USES_CONFIGURATION)) { @@ -2442,7 +2447,7 @@ public class PackageParser { newPermsMsg.append(' '); } newPermsMsg.append(npi.name); - pkg.requestedPermissions.add(npi.name); + addRequestedPermission(pkg, npi.name); pkg.implicitPermissions.add(npi.name); } } @@ -2463,7 +2468,7 @@ public class PackageParser { for (int in = 0; in < newPerms.size(); in++) { final String perm = newPerms.get(in); if (!pkg.requestedPermissions.contains(perm)) { - pkg.requestedPermissions.add(perm); + addRequestedPermission(pkg, perm); pkg.implicitPermissions.add(perm); } } @@ -2543,13 +2548,13 @@ public class PackageParser { } } else { if (FORCE_AUDIO_PACKAGES.contains(pkg.packageName)) { - pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_AUDIO); + addRequestedPermission(pkg, android.Manifest.permission.READ_MEDIA_AUDIO); } if (FORCE_VIDEO_PACKAGES.contains(pkg.packageName)) { - pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_VIDEO); + addRequestedPermission(pkg, android.Manifest.permission.READ_MEDIA_VIDEO); } if (FORCE_IMAGES_PACKAGES.contains(pkg.packageName)) { - pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_IMAGES); + addRequestedPermission(pkg, android.Manifest.permission.READ_MEDIA_IMAGES); } } @@ -2589,6 +2594,14 @@ public class PackageParser { } /** + * Helper method for adding a requested permission to a package outside of a uses-permission. + */ + private void addRequestedPermission(Package pkg, String permission) { + pkg.requestedPermissions.add(permission); + pkg.usesPermissionInfos.add(new UsesPermissionInfo(permission)); + } + + /** * Computes the targetSdkVersion to use at runtime. If the package is not * compatible with this platform, populates {@code outError[0]} with an * error message. @@ -2845,8 +2858,8 @@ public class PackageParser { return certSha256Digests; } - private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser) - throws XmlPullParserException, IOException { + private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser, + String[] outError) throws XmlPullParserException, IOException { TypedArray sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestUsesPermission); @@ -2870,6 +2883,44 @@ public class PackageParser { final String requiredNotfeature = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredNotFeature, 0); + int dataSentOffDevice = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesPermission_dataSentOffDevice, 0); + + int dataSharedWithThirdParty = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesPermission_dataSharedWithThirdParty, 0); + + int dataUsedForMonetization = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesPermission_dataUsedForMonetization, 0); + + int retentionWeeks = -1; + int retention; + + String rawRetention = sa.getString( + com.android.internal.R.styleable.AndroidManifestUsesPermission_dataRetentionTime); + + if (rawRetention == null) { + retention = UsesPermissionInfo.RETENTION_UNDEFINED; + } else if ("notRetained".equals(rawRetention)) { + retention = UsesPermissionInfo.RETENTION_NOT_RETAINED; + } else if ("userSelected".equals(rawRetention)) { + retention = UsesPermissionInfo.RETENTION_USER_SELECTED; + } else if ("unlimited".equals(rawRetention)) { + retention = UsesPermissionInfo.RETENTION_UNLIMITED; + } else { + // A number of weeks was specified + retention = UsesPermissionInfo.RETENTION_SPECIFIED; + retentionWeeks = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesPermission_dataRetentionTime, + -1); + + if (retentionWeeks < 0) { + outError[0] = "Bad value provided for dataRetentionTime."; + mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; + XmlUtils.skipCurrentTag(parser); + sa.recycle(); + return false; + } + } sa.recycle(); XmlUtils.skipCurrentTag(parser); @@ -2902,6 +2953,10 @@ public class PackageParser { + parser.getPositionDescription()); } + UsesPermissionInfo info = new UsesPermissionInfo(name, dataSentOffDevice, + dataSharedWithThirdParty, dataUsedForMonetization, retention, retentionWeeks); + pkg.usesPermissionInfos.add(info); + return true; } @@ -3236,6 +3291,10 @@ public class PackageParser { perm.info.flags = sa.getInt( com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0); + perm.info.usageInfoRequired = sa.getInt( + com.android.internal.R.styleable.AndroidManifestPermission_usageInfoRequired, 0) + != 0; + sa.recycle(); if (perm.info.protectionLevel == -1) { @@ -6370,6 +6429,9 @@ public class PackageParser { @UnsupportedAppUsage public final ArrayList<String> requestedPermissions = new ArrayList<String>(); + public final ArrayList<UsesPermissionInfo> usesPermissionInfos = + new ArrayList<>(); + /** Permissions requested but not in the manifest. */ public final ArrayList<String> implicitPermissions = new ArrayList<>(); @@ -6900,6 +6962,7 @@ public class PackageParser { dest.readStringList(requestedPermissions); internStringArrayList(requestedPermissions); + dest.readParcelableList(usesPermissionInfos, boot); dest.readStringList(implicitPermissions); internStringArrayList(implicitPermissions); protectedBroadcasts = dest.createStringArrayList(); @@ -7066,6 +7129,7 @@ public class PackageParser { dest.writeParcelableList(instrumentation, flags); dest.writeStringList(requestedPermissions); + dest.writeParcelableList(usesPermissionInfos, flags); dest.writeStringList(implicitPermissions); dest.writeStringList(protectedBroadcasts); diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index e21c33ad3bc1..be6ed51e3c89 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -21,7 +21,6 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import static android.content.pm.PackageManager.MATCH_ALL; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; @@ -130,9 +129,6 @@ public class PackageUserState { * </p> */ public boolean isMatch(ComponentInfo componentInfo, int flags) { - if ((flags & MATCH_ALL) != 0) { - return true; - } final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp(); final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0; if (!isAvailable(flags) diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java index 60c06a1e4d87..d9d6b5f87eac 100644 --- a/core/java/android/content/pm/PermissionInfo.java +++ b/core/java/android/content/pm/PermissionInfo.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -308,6 +309,12 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { */ public CharSequence nonLocalizedDescription; + /** + * If {@code true} an application targeting {@link Build.VERSION_CODES#Q} <em>must</em> + * include permission data usage information in order to be able to be granted this permission. + */ + public boolean usageInfoRequired; + /** @hide */ public static int fixProtectionLevel(int level) { if (level == PROTECTION_SIGNATURE_OR_SYSTEM) { @@ -394,6 +401,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { descriptionRes = orig.descriptionRes; requestRes = orig.requestRes; nonLocalizedDescription = orig.nonLocalizedDescription; + usageInfoRequired = orig.usageInfoRequired; } /** @@ -458,6 +466,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { dest.writeInt(descriptionRes); dest.writeInt(requestRes); TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags); + dest.writeInt(usageInfoRequired ? 1 : 0); } /** @hide */ @@ -498,5 +507,6 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { descriptionRes = source.readInt(); requestRes = source.readInt(); nonLocalizedDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); + usageInfoRequired = source.readInt() != 0; } } diff --git a/core/java/android/content/pm/UsesPermissionInfo.java b/core/java/android/content/pm/UsesPermissionInfo.java new file mode 100644 index 000000000000..d08548fa31a5 --- /dev/null +++ b/core/java/android/content/pm/UsesPermissionInfo.java @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +import android.annotation.IntDef; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.RetentionPolicy; +/** + * Information you can retrive about a particular application requested permission. This + * corresponds to information collected from the AndroidManifest.xml's <uses-permission> + * tags. + */ +public final class UsesPermissionInfo extends PackageItemInfo implements Parcelable { + + /** + * Flag for {@link #getFlags()}: the requested permission is currently granted to the + * application. + */ + public static final int FLAG_REQUESTED_PERMISSION_GRANTED = 1 << 1; + + /** @hide */ + @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_REQUESTED_PERMISSION_GRANTED}) + @java.lang.annotation.Retention(RetentionPolicy.SOURCE) + public @interface Flags {} + + /** An unset value for {@link #getDataSentOffDevice()}, + * {@link #getDataSharedWithThirdParty()}, and {@link #getDataUsedForMonetization()} + */ + public static final int USAGE_UNDEFINED = 0; + + /** + * A yes value for {@link #getDataSentOffDevice()}, {@link #getDataSharedWithThirdParty()}, + * and {@link #getDataUsedForMonetization()} corresponding to the <code>yes</code> value of + * {@link android.R.attr#dataSentOffDevice}, {@link android.R.attr#dataSharedWithThirdParty}, + * and {@link android.R.attr#dataUsedForMonetization} attributes. + */ + public static final int USAGE_YES = 1; + + /** + * A user triggered only value for {@link #getDataSentOffDevice()}, + * {@link #getDataSharedWithThirdParty()}, and {@link #getDataUsedForMonetization()} + * corresponding to the <code>userTriggered</code> value of + * {@link android.R.attr#dataSentOffDevice}, {@link android.R.attr#dataSharedWithThirdParty}, + * and {@link android.R.attr#dataUsedForMonetization} attributes. + */ + public static final int USAGE_USER_TRIGGERED = 2; + + /** + * A no value for {@link #getDataSentOffDevice()}, {@link #getDataSharedWithThirdParty()}, + * and {@link #getDataUsedForMonetization()} corresponding to the <code>no</code> value of + * {@link android.R.attr#dataSentOffDevice}, {@link android.R.attr#dataSharedWithThirdParty}, + * and {@link android.R.attr#dataUsedForMonetization} attributes. + */ + public static final int USAGE_NO = 3; + + /** @hide */ + @IntDef(prefix = {"USAGE_"}, value = { + USAGE_UNDEFINED, + USAGE_YES, + USAGE_USER_TRIGGERED, + USAGE_NO}) + @java.lang.annotation.Retention(RetentionPolicy.SOURCE) + public @interface Usage {} + + /** + * An unset value for {@link #getDataRetention}. + */ + public static final int RETENTION_UNDEFINED = 0; + + /** + * A data not retained value for {@link #getDataRetention()} corresponding to the + * <code>notRetained</code> value of {@link android.R.attr#dataRetentionTime}. + */ + public static final int RETENTION_NOT_RETAINED = 1; + + /** + * A user selected value for {@link #getDataRetention()} corresponding to the + * <code>userSelected</code> value of {@link android.R.attr#dataRetentionTime}. + */ + public static final int RETENTION_USER_SELECTED = 2; + + /** + * An unlimited value for {@link #getDataRetention()} corresponding to the + * <code>unlimited</code> value of {@link android.R.attr#dataRetentionTime}. + */ + public static final int RETENTION_UNLIMITED = 3; + + /** + * A specified value for {@link #getDataRetention()} corresponding to providing the number of + * weeks data is retained in {@link android.R.attr#dataRetentionTime}. The number of weeks + * is available in {@link #getDataRetentionWeeks()}. + */ + public static final int RETENTION_SPECIFIED = 4; + + /** @hide */ + @IntDef(prefix = {"RETENTION_"}, value = { + RETENTION_UNDEFINED, + RETENTION_NOT_RETAINED, + RETENTION_USER_SELECTED, + RETENTION_UNLIMITED, + RETENTION_SPECIFIED}) + @java.lang.annotation.Retention(RetentionPolicy.SOURCE) + public @interface Retention {} + + private final String mPermission; + private final @Flags int mFlags; + private final @Usage int mDataSentOffDevice; + private final @Usage int mDataSharedWithThirdParty; + private final @Usage int mDataUsedForMonetization; + private final @Retention int mDataRetention; + private final int mDataRetentionWeeks; + + /** @hide */ + public UsesPermissionInfo(String permission) { + mPermission = permission; + mDataSentOffDevice = USAGE_UNDEFINED; + mDataSharedWithThirdParty = USAGE_UNDEFINED; + mDataUsedForMonetization = USAGE_UNDEFINED; + mDataRetention = RETENTION_UNDEFINED; + mDataRetentionWeeks = -1; + mFlags = 0; + } + + /** @hide */ + public UsesPermissionInfo(String permission, + @Usage int dataSentOffDevice, @Usage int dataSharedWithThirdParty, + @Usage int dataUsedForMonetization, @Retention int dataRetention, + int dataRetentionWeeks) { + mPermission = permission; + mDataSentOffDevice = dataSentOffDevice; + mDataSharedWithThirdParty = dataSharedWithThirdParty; + mDataUsedForMonetization = dataUsedForMonetization; + mDataRetention = dataRetention; + mDataRetentionWeeks = dataRetentionWeeks; + mFlags = 0; + } + + /** @hide */ + public UsesPermissionInfo(UsesPermissionInfo orig) { + this(orig, orig.mFlags); + } + + /** @hide */ + public UsesPermissionInfo(UsesPermissionInfo orig, int flags) { + super(orig); + mPermission = orig.mPermission; + mFlags = flags; + mDataSentOffDevice = orig.mDataSentOffDevice; + mDataSharedWithThirdParty = orig.mDataSharedWithThirdParty; + mDataUsedForMonetization = orig.mDataUsedForMonetization; + mDataRetention = orig.mDataRetention; + mDataRetentionWeeks = orig.mDataRetentionWeeks; + } + + /** + * The name of the requested permission. + */ + public String getPermission() { + return mPermission; + } + + public @Flags int getFlags() { + return mFlags; + } + + /** + * If the application sends the data guarded by this permission off the device. + * + * See {@link android.R.attr#dataSentOffDevice} + */ + public @Usage int getDataSentOffDevice() { + return mDataSentOffDevice; + } + + /** + * If the application or its services shares the data guarded by this permission with third + * parties. + * + * See {@link android.R.attr#dataSharedWithThirdParty} + */ + public @Usage int getDataSharedWithThirdParty() { + return mDataSharedWithThirdParty; + } + + /** + * If the application or its services use the data guarded by this permission for monetization + * purposes. + * + * See {@link android.R.attr#dataUsedForMonetization} + */ + public @Usage int getDataUsedForMonetization() { + return mDataUsedForMonetization; + } + + /** + * How long the application or its services store the data guarded by this permission. + * If set to {@link #RETENTION_SPECIFIED} {@link #getDataRetentionWeeks()} will contain the + * number of weeks the data is stored. + * + * See {@link android.R.attr#dataRetentionTime} + */ + public @Retention int getDataRetention() { + return mDataRetention; + } + + /** + * If {@link #getDataRetention()} is {@link #RETENTION_SPECIFIED} the number of weeks the + * application or its services store data guarded by this permission. + * + * @throws IllegalStateException if {@link #getDataRetention} is not + * {@link #RETENTION_SPECIFIED}. + */ + public int getDataRetentionWeeks() { + if (mDataRetention != RETENTION_SPECIFIED) { + throw new IllegalStateException("Data retention weeks not specified"); + } + return mDataRetentionWeeks; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(mPermission); + dest.writeInt(mFlags); + dest.writeInt(mDataSentOffDevice); + dest.writeInt(mDataSharedWithThirdParty); + dest.writeInt(mDataUsedForMonetization); + dest.writeInt(mDataRetention); + dest.writeInt(mDataRetentionWeeks); + } + + private UsesPermissionInfo(Parcel source) { + super(source); + mPermission = source.readString(); + mFlags = source.readInt(); + mDataSentOffDevice = source.readInt(); + mDataSharedWithThirdParty = source.readInt(); + mDataUsedForMonetization = source.readInt(); + mDataRetention = source.readInt(); + mDataRetentionWeeks = source.readInt(); + } + + public static final Creator<UsesPermissionInfo> CREATOR = + new Creator<UsesPermissionInfo>() { + @Override + public UsesPermissionInfo createFromParcel(Parcel source) { + return new UsesPermissionInfo(source); + } + @Override + public UsesPermissionInfo[] newArray(int size) { + return new UsesPermissionInfo[size]; + } + }; +} diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index 9db1f922bd5d..9d61f028bc91 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -24,7 +24,7 @@ import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; -import android.view.SurfaceControl; +import android.view.SurfaceControl.Transaction; /** * Display manager local system service interface. @@ -126,7 +126,7 @@ public abstract class DisplayManagerInternal { * Called by the window manager to perform traversals while holding a * surface flinger transaction. */ - public abstract void performTraversal(SurfaceControl.Transaction t); + public abstract void performTraversal(Transaction t); /** * Tells the display manager about properties of the display that depend on the windows on it. @@ -383,6 +383,6 @@ public abstract class DisplayManagerInternal { * update the position of its surfaces as part of the same transaction. */ public interface DisplayTransactionListener { - void onDisplayTransaction(); + void onDisplayTransaction(Transaction t); } } diff --git a/core/java/android/hardware/display/DisplayViewport.java b/core/java/android/hardware/display/DisplayViewport.java index df0d46be1354..f2c50b5cc464 100644 --- a/core/java/android/hardware/display/DisplayViewport.java +++ b/core/java/android/hardware/display/DisplayViewport.java @@ -19,6 +19,7 @@ package android.hardware.display; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; +import android.annotation.Nullable; import android.graphics.Rect; import android.text.TextUtils; @@ -71,6 +72,9 @@ public final class DisplayViewport { // The ID used to uniquely identify this display. public String uniqueId; + // The physical port that the associated display device is connected to. + public @Nullable Byte physicalPort; + public @ViewportType int type; public void copyFrom(DisplayViewport viewport) { @@ -82,6 +86,7 @@ public final class DisplayViewport { deviceWidth = viewport.deviceWidth; deviceHeight = viewport.deviceHeight; uniqueId = viewport.uniqueId; + physicalPort = viewport.physicalPort; type = viewport.type; } @@ -113,6 +118,7 @@ public final class DisplayViewport { && deviceWidth == other.deviceWidth && deviceHeight == other.deviceHeight && TextUtils.equals(uniqueId, other.uniqueId) + && physicalPort == other.physicalPort && type == other.type; } @@ -128,6 +134,7 @@ public final class DisplayViewport { result += prime * result + deviceWidth; result += prime * result + deviceHeight; result += prime * result + uniqueId.hashCode(); + result += prime * result + physicalPort; result += prime * result + type; return result; } @@ -139,6 +146,7 @@ public final class DisplayViewport { + ", valid=" + valid + ", displayId=" + displayId + ", uniqueId='" + uniqueId + "'" + + ", physicalPort=" + physicalPort + ", orientation=" + orientation + ", logicalFrame=" + logicalFrame + ", physicalFrame=" + physicalFrame diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 651caece01f9..2abcb4cd9379 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -1055,6 +1055,9 @@ public class Process { */ public static final native long getPss(int pid); + /** @hide */ + public static final native long[] getRss(int pid); + /** * Specifies the outcome of having started a process. * @hide diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b175f3800f94..d7729037bfad 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11618,7 +11618,7 @@ public final class Settings { /** * Whether or not show hidden launcher icon apps feature is enabled. * Type: int (0 for false, 1 for true) - * Default: 0 + * Default: 1 * @hide */ public static final String SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED = diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl index ab94f432968c..1ddc099efa49 100644 --- a/core/java/android/service/notification/INotificationListener.aidl +++ b/core/java/android/service/notification/INotificationListener.aidl @@ -16,6 +16,7 @@ package android.service.notification; +import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.content.pm.ParceledListSlice; @@ -50,4 +51,5 @@ oneway interface INotificationListener void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded); void onNotificationDirectReply(String key); void onSuggestedReplySent(String key, in CharSequence reply, int source); + void onActionClicked(String key, in Notification.Action action, int source); } diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index 68da83f9e7d8..c850a4e0f815 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -19,9 +19,11 @@ package android.service.notification; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.app.Notification; import android.app.NotificationChannel; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; @@ -189,11 +191,20 @@ public abstract class NotificationAssistantService extends NotificationListenerS * Implement this to know when a suggested reply is sent. * @param key the notification key * @param reply the reply that is just sent - * @param source the source of the reply, e.g. SOURCE_FROM_APP + * @param source the source that provided the reply, e.g. SOURCE_FROM_APP */ public void onSuggestedReplySent(String key, CharSequence reply, @Source int source) {} /** + * Implement this to know when an action is clicked. + * @param key the notification key + * @param action the action that is just clicked + * @param source the source that provided the action, e.g. SOURCE_FROM_APP + */ + public void onActionClicked(String key, @Nullable Notification.Action action, int source) { + } + + /** * Updates a notification. N.B. this won’t cause * an existing notification to alert, but might allow a future update to * this notification to alert. @@ -317,6 +328,15 @@ public abstract class NotificationAssistantService extends NotificationListenerS args.argi2 = source; mHandler.obtainMessage(MyHandler.MSG_ON_SUGGESTED_REPLY_SENT, args).sendToTarget(); } + + @Override + public void onActionClicked(String key, Notification.Action action, int source) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = key; + args.arg2 = action; + args.argi2 = source; + mHandler.obtainMessage(MyHandler.MSG_ON_ACTION_CLICKED, args).sendToTarget(); + } } private final class MyHandler extends Handler { @@ -326,6 +346,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS public static final int MSG_ON_NOTIFICATION_EXPANSION_CHANGED = 4; public static final int MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT = 5; public static final int MSG_ON_SUGGESTED_REPLY_SENT = 6; + public static final int MSG_ON_ACTION_CLICKED = 7; public MyHandler(Looper looper) { super(looper, null, false); @@ -395,6 +416,15 @@ public abstract class NotificationAssistantService extends NotificationListenerS onSuggestedReplySent(key, reply, source); break; } + case MSG_ON_ACTION_CLICKED: { + SomeArgs args = (SomeArgs) msg.obj; + String key = (String) args.arg1; + Notification.Action action = (Notification.Action) args.arg2; + int source = args.argi2; + args.recycle(); + onActionClicked(key, action, source); + break; + } } } } diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 756a7c6a54b0..1fe97b79fd69 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -1382,6 +1382,11 @@ public abstract class NotificationListenerService extends Service { } @Override + public void onActionClicked(String key, Notification.Action action, int source) { + // no-op in the listener + } + + @Override public void onNotificationChannelModification(String pkgName, UserHandle user, NotificationChannel channel, @ChannelOrGroupModificationTypes int modificationType) { diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl index dccce406e32c..ebce4846c16b 100644 --- a/core/java/android/service/wallpaper/IWallpaperEngine.aidl +++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl @@ -27,7 +27,7 @@ oneway interface IWallpaperEngine { void setDesiredSize(int width, int height); void setDisplayPadding(in Rect padding); void setVisibility(boolean visible); - void setInAmbientMode(boolean inAmbientDisplay, boolean animated); + void setInAmbientMode(boolean inAmbientDisplay, long animationDuration); void dispatchPointer(in MotionEvent event); void dispatchWallpaperCommand(String action, int x, int y, int z, in Bundle extras); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index f6bb762a0bef..a095b0d8b239 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -19,6 +19,7 @@ package android.service.wallpaper; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.app.Service; import android.app.WallpaperColors; @@ -56,6 +57,7 @@ import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; +import android.view.InsetsState; import android.view.WindowManager; import android.view.WindowManagerGlobal; @@ -184,6 +186,7 @@ public abstract class WallpaperService extends Service { final DisplayCutout.ParcelableWrapper mDisplayCutout = new DisplayCutout.ParcelableWrapper(); DisplayCutout mDispatchedDisplayCutout = DisplayCutout.NO_CUTOUT; + final InsetsState mInsetsState = new InsetsState(); final MergedConfiguration mMergedConfiguration = new MergedConfiguration(); final WindowManager.LayoutParams mLayout @@ -440,7 +443,9 @@ public abstract class WallpaperService extends Service { /** * Returns true if this engine is running in ambient mode -- that is, * it is being shown in low power mode, on always on display. + * @hide */ + @SystemApi public boolean isInAmbientMode() { return mIsInAmbientMode; } @@ -566,14 +571,16 @@ public abstract class WallpaperService extends Service { * Called when the device enters or exits ambient mode. * * @param inAmbientMode {@code true} if in ambient mode. - * @param animated {@code true} if you'll have the opportunity of animating your transition - * {@code false} when the wallpaper should present its ambient version - * immediately. + * @param animationDuration How long the transition animation to change the ambient state + * should run, in milliseconds. If 0 is passed as the argument + * here, the state should be switched immediately. * * @see #isInAmbientMode() * @see WallpaperInfo#supportsAmbientMode() + * @hide */ - public void onAmbientModeChanged(boolean inAmbientMode, boolean animated) { + @SystemApi + public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { } /** @@ -803,9 +810,11 @@ public abstract class WallpaperService extends Service { mLayout.windowAnimations = com.android.internal.R.style.Animation_Wallpaper; mInputChannel = new InputChannel(); + if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE, mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets, - mOutsets, mDisplayCutout, mInputChannel) < 0) { + mOutsets, mDisplayCutout, mInputChannel, + mInsetsState) < 0) { Log.w(TAG, "Failed to add window while updating wallpaper surface."); return; } @@ -831,7 +840,8 @@ public abstract class WallpaperService extends Service { mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, View.VISIBLE, 0, -1, mWinFrame, mOverscanInsets, mContentInsets, mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame, - mDisplayCutout, mMergedConfiguration, mSurfaceHolder.mSurface); + mDisplayCutout, mMergedConfiguration, mSurfaceHolder.mSurface, + mInsetsState); if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface + ", frame=" + mWinFrame); @@ -1044,19 +1054,19 @@ public abstract class WallpaperService extends Service { * message sent from handler. * * @param inAmbientMode {@code true} if in ambient mode. - * @param animated {@code true} if the transition will be animated. + * @param animationDuration For how long the transition will last, in ms. * @hide */ @VisibleForTesting - public void doAmbientModeChanged(boolean inAmbientMode, boolean animated) { + public void doAmbientModeChanged(boolean inAmbientMode, long animationDuration) { if (!mDestroyed) { if (DEBUG) { Log.v(TAG, "onAmbientModeChanged(" + inAmbientMode + ", " - + animated + "): " + this); + + animationDuration + "): " + this); } mIsInAmbientMode = inAmbientMode; if (mCreated) { - onAmbientModeChanged(inAmbientMode, animated); + onAmbientModeChanged(inAmbientMode, animationDuration); } } } @@ -1315,10 +1325,10 @@ public abstract class WallpaperService extends Service { } @Override - public void setInAmbientMode(boolean inAmbientDisplay, boolean animated) + public void setInAmbientMode(boolean inAmbientDisplay, long animationDuration) throws RemoteException { - Message msg = mCaller.obtainMessageII(DO_IN_AMBIENT_MODE, inAmbientDisplay ? 1 : 0, - animated ? 1 : 0); + Message msg = mCaller.obtainMessageIO(DO_IN_AMBIENT_MODE, inAmbientDisplay ? 1 : 0, + animationDuration); mCaller.sendMessage(msg); } @@ -1389,7 +1399,7 @@ public abstract class WallpaperService extends Service { return; } case DO_IN_AMBIENT_MODE: { - mEngine.doAmbientModeChanged(message.arg1 != 0, message.arg2 != 0); + mEngine.doAmbientModeChanged(message.arg1 != 0, (Long) message.obj); return; } case MSG_UPDATE_SURFACE: diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java index c8228326b8e4..de182daaeb53 100644 --- a/core/java/android/transition/ChangeBounds.java +++ b/core/java/android/transition/ChangeBounds.java @@ -32,6 +32,7 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.util.AttributeSet; import android.util.Property; import android.view.View; @@ -109,7 +110,7 @@ public class ChangeBounds extends Transition { } }; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static final Property<View, PointF> BOTTOM_RIGHT_ONLY_PROPERTY = new Property<View, PointF>(PointF.class, "bottomRight") { @Override @@ -144,7 +145,7 @@ public class ChangeBounds extends Transition { } }; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static final Property<View, PointF> POSITION_PROPERTY = new Property<View, PointF>(PointF.class, "position") { @Override diff --git a/core/java/android/transition/Scene.java b/core/java/android/transition/Scene.java index 7e499f29122a..b1fc17a4ecd1 100644 --- a/core/java/android/transition/Scene.java +++ b/core/java/android/transition/Scene.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.Context; +import android.os.Build; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; @@ -38,9 +39,9 @@ public final class Scene { private int mLayoutId = -1; private ViewGroup mSceneRoot; private View mLayout; // alternative to layoutId - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) Runnable mEnterAction; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) Runnable mExitAction; /** @@ -200,7 +201,7 @@ public final class Scene { * * @param sceneRoot The view on which the current scene is being set */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) static void setCurrentScene(@NonNull View sceneRoot, @Nullable Scene scene) { sceneRoot.setTagInternal(com.android.internal.R.id.current_scene, scene); } diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index 4b8b7f304b0f..af41b6942a5e 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -24,6 +24,7 @@ import android.view.DragEvent; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.DisplayCutout; +import android.view.InsetsState; import com.android.internal.os.IResultReceiver; import android.util.MergedConfiguration; @@ -53,6 +54,12 @@ oneway interface IWindow { in MergedConfiguration newMergedConfiguration, in Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId, in DisplayCutout.ParcelableWrapper displayCutout); + + /** + * Called when the window insets configuration has changed. + */ + void insetsChanged(in InsetsState insetsState); + void moved(int newX, int newY); void dispatchAppVisibility(boolean visible); void dispatchGetNewSurface(); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index bedfa9ff133c..97625869209d 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -28,6 +28,7 @@ import android.view.IWindow; import android.view.IWindowId; import android.view.MotionEvent; import android.view.WindowManager; +import android.view.InsetsState; import android.view.Surface; import android.view.SurfaceControl; @@ -40,10 +41,11 @@ interface IWindowSession { int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets, out Rect outOutsets, - out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel); + out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel, + out InsetsState insetsState); int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outContentInsets, - out Rect outStableInsets); + out Rect outStableInsets, out InsetsState insetsState); void remove(IWindow window); /** @@ -86,6 +88,7 @@ interface IWindowSession { * config for window, if it is now becoming visible and the merged configuration has changed * since it was last displayed. * @param outSurface Object in which is placed the new display surface. + * @param insetsState The current insets state in the system. * * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS}, * {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}. @@ -96,7 +99,8 @@ interface IWindowSession { out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets, out Rect outOutsets, out Rect outBackdropFrame, out DisplayCutout.ParcelableWrapper displayCutout, - out MergedConfiguration outMergedConfiguration, out Surface outSurface); + out MergedConfiguration outMergedConfiguration, out Surface outSurface, + out InsetsState insetsState); /* * Notify the window manager that an application is relaunching and diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java new file mode 100644 index 000000000000..7841d0417a2b --- /dev/null +++ b/core/java/android/view/InsetsController.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.graphics.Rect; + +import java.io.PrintWriter; + +/** + * Implements {@link WindowInsetsController} on the client. + */ +class InsetsController { + + private final InsetsState mState = new InsetsState(); + private final Rect mFrame = new Rect(); + + void onFrameChanged(Rect frame) { + mFrame.set(frame); + } + + public InsetsState getState() { + return mState; + } + + public void setState(InsetsState state) { + mState.set(state); + } + + /** + * @see InsetsState#calculateInsets + */ + WindowInsets calculateInsets(boolean isScreenRound, + boolean alwaysConsumeNavBar, DisplayCutout cutout) { + return mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout); + } + + void dump(String prefix, PrintWriter pw) { + pw.println(prefix); pw.println("InsetsController:"); + mState.dump(prefix + " ", pw); + } +} diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java new file mode 100644 index 000000000000..0cb8ad72f102 --- /dev/null +++ b/core/java/android/view/InsetsSource.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.graphics.Insets; +import android.graphics.Rect; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.InsetsState.InternalInsetType; + +import java.io.PrintWriter; + +/** + * Represents the state of a single window generating insets for clients. + * @hide + */ +public class InsetsSource implements Parcelable { + + private final @InternalInsetType int mType; + + /** Frame of the source in screen coordinate space */ + private final Rect mFrame; + private boolean mVisible; + + private final Rect mTmpFrame = new Rect(); + + public InsetsSource(@InternalInsetType int type) { + mType = type; + mFrame = new Rect(); + } + + public InsetsSource(InsetsSource other) { + mType = other.mType; + mFrame = new Rect(other.mFrame); + mVisible = other.mVisible; + } + + public void setFrame(Rect frame) { + mFrame.set(frame); + } + + public void setVisible(boolean visible) { + mVisible = visible; + } + + public @InternalInsetType int getType() { + return mType; + } + + public Rect getFrame() { + return mFrame; + } + + /** + * Calculates the insets this source will cause to a client window. + * + * @param relativeFrame The frame to calculate the insets relative to. + * @param ignoreVisibility If true, always reports back insets even if source isn't visible. + * @return The resulting insets. + */ + public Insets calculateInsets(Rect relativeFrame, boolean ignoreVisibility) { + if (!ignoreVisibility && !mVisible) { + return Insets.NONE; + } + if (!mTmpFrame.setIntersect(mFrame, relativeFrame)) { + return Insets.NONE; + } + + // Intersecting at top/bottom + if (mTmpFrame.width() == relativeFrame.width()) { + if (mTmpFrame.top == relativeFrame.top) { + return Insets.of(0, mTmpFrame.height(), 0, 0); + } else { + return Insets.of(0, 0, 0, mTmpFrame.height()); + } + } + // Intersecting at left/right + else if (mTmpFrame.height() == relativeFrame.height()) { + if (mTmpFrame.left == relativeFrame.left) { + return Insets.of(mTmpFrame.width(), 0, 0, 0); + } else { + return Insets.of(0, 0, mTmpFrame.width(), 0); + } + } else { + return Insets.NONE; + } + } + + public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); + pw.print("InsetsSource type="); pw.print(InsetsState.typeToString(mType)); + pw.print(" frame="); pw.print(mFrame.toShortString()); + pw.print(" visible="); pw.print(mVisible); + pw.println(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + InsetsSource that = (InsetsSource) o; + + if (mType != that.mType) return false; + if (mVisible != that.mVisible) return false; + return mFrame.equals(that.mFrame); + } + + @Override + public int hashCode() { + int result = mType; + result = 31 * result + mFrame.hashCode(); + result = 31 * result + (mVisible ? 1 : 0); + return result; + } + + public InsetsSource(Parcel in) { + mType = in.readInt(); + mFrame = in.readParcelable(null /* loader */); + mVisible = in.readBoolean(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mType); + dest.writeParcelable(mFrame, 0 /* flags*/); + dest.writeBoolean(mVisible); + } + + public static final Creator<InsetsSource> CREATOR = new Creator<InsetsSource>() { + + public InsetsSource createFromParcel(Parcel in) { + return new InsetsSource(in); + } + + public InsetsSource[] newArray(int size) { + return new InsetsSource[size]; + } + }; +} diff --git a/core/java/android/view/InsetsState.aidl b/core/java/android/view/InsetsState.aidl new file mode 100644 index 000000000000..d02ddd15a8c9 --- /dev/null +++ b/core/java/android/view/InsetsState.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +parcelable InsetsState; diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java new file mode 100644 index 000000000000..9895adcad23a --- /dev/null +++ b/core/java/android/view/InsetsState.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.annotation.IntDef; +import android.graphics.Insets; +import android.graphics.Rect; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArrayMap; + +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Holder for state of system windows that cause window insets for all other windows in the system. + * @hide + */ +public class InsetsState implements Parcelable { + + /** + * Internal representation of inset source types. This is different from the public API in + * {@link WindowInsets.Type} as one type from the public API might indicate multiple windows + * at the same time. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "TYPE", value = { + TYPE_TOP_BAR, + TYPE_SIDE_BAR_1, + TYPE_SIDE_BAR_2, + TYPE_SIDE_BAR_3, + TYPE_IME + }) + public @interface InternalInsetType {} + + static final int FIRST_TYPE = 0; + + /** Top bar. Can be status bar or caption in freeform windowing mode. */ + public static final int TYPE_TOP_BAR = FIRST_TYPE; + + /** + * Up to 3 side bars that appear on left/right/bottom. On phones there is only one side bar + * (the navigation bar, see {@link #TYPE_NAVIGATION_BAR}), but other form factors might have + * multiple, like Android Auto. + */ + public static final int TYPE_SIDE_BAR_1 = 1; + public static final int TYPE_SIDE_BAR_2 = 2; + public static final int TYPE_SIDE_BAR_3 = 3; + + /** Input method window. */ + public static final int TYPE_IME = 4; + static final int LAST_TYPE = TYPE_IME; + + // Derived types + + /** First side bar is navigation bar. */ + public static final int TYPE_NAVIGATION_BAR = TYPE_SIDE_BAR_1; + + /** A shelf is the same as the navigation bar. */ + public static final int TYPE_SHELF = TYPE_NAVIGATION_BAR; + + private final ArrayMap<Integer, InsetsSource> mSources = new ArrayMap<>(); + + public InsetsState() { + } + + /** + * Calculates {@link WindowInsets} based on the current source configuration. + * + * @param frame The frame to calculate the insets relative to. + * @return The calculated insets. + */ + public WindowInsets calculateInsets(Rect frame, boolean isScreenRound, + boolean alwaysConsumeNavBar, DisplayCutout cutout) { + Insets systemInsets = Insets.NONE; + Insets maxInsets = Insets.NONE; + final Rect relativeFrame = new Rect(frame); + final Rect relativeFrameMax = new Rect(frame); + for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) { + InsetsSource source = mSources.get(type); + if (source == null) { + continue; + } + systemInsets = processSource(source, systemInsets, relativeFrame, + false /* ignoreVisibility */); + + // IME won't be reported in max insets as the size depends on the EditorInfo of the IME + // target. + if (source.getType() != TYPE_IME) { + maxInsets = processSource(source, maxInsets, relativeFrameMax, + true /* ignoreVisibility */); + } + } + return new WindowInsets(new Rect(systemInsets), null, new Rect(maxInsets), isScreenRound, + alwaysConsumeNavBar, cutout); + } + + private Insets processSource(InsetsSource source, Insets insets, Rect relativeFrame, + boolean ignoreVisibility) { + Insets currentInsets = source.calculateInsets(relativeFrame, ignoreVisibility); + insets = Insets.add(currentInsets, insets); + relativeFrame.inset(insets); + return insets; + } + + public InsetsSource getSource(@InternalInsetType int type) { + return mSources.computeIfAbsent(type, InsetsSource::new); + } + + /** + * Modifies the state of this class to exclude a certain type to make it ready for dispatching + * to the client. + * + * @param type The {@link InternalInsetType} of the source to remove + */ + public void removeSource(int type) { + mSources.remove(type); + } + + public void set(InsetsState other) { + set(other, false /* copySources */); + } + + public void set(InsetsState other, boolean copySources) { + mSources.clear(); + if (copySources) { + for (int i = 0; i < other.mSources.size(); i++) { + InsetsSource source = other.mSources.valueAt(i); + mSources.put(source.getType(), new InsetsSource(source)); + } + } else { + mSources.putAll(other.mSources); + } + } + + public void dump(String prefix, PrintWriter pw) { + pw.println(prefix + "InsetsState"); + for (int i = mSources.size() - 1; i >= 0; i--) { + mSources.valueAt(i).dump(prefix + " ", pw); + } + } + + static String typeToString(int type) { + switch (type) { + case TYPE_TOP_BAR: + return "TYPE_TOP_BAR"; + case TYPE_SIDE_BAR_1: + return "TYPE_SIDE_BAR_1"; + case TYPE_SIDE_BAR_2: + return "TYPE_SIDE_BAR_2"; + case TYPE_SIDE_BAR_3: + return "TYPE_SIDE_BAR_3"; + case TYPE_IME: + return "TYPE_IME"; + default: + return "TYPE_UNKNOWN"; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { return true; } + if (o == null || getClass() != o.getClass()) { return false; } + + InsetsState state = (InsetsState) o; + + if (mSources.size() != state.mSources.size()) { + return false; + } + for (int i = mSources.size() - 1; i >= 0; i--) { + InsetsSource source = mSources.valueAt(i); + InsetsSource otherSource = state.mSources.get(source.getType()); + if (otherSource == null) { + return false; + } + if (!otherSource.equals(source)) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return mSources.hashCode(); + } + + public InsetsState(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mSources.size()); + for (int i = 0; i < mSources.size(); i++) { + dest.writeParcelable(mSources.valueAt(i), 0 /* flags */); + } + } + + public static final Creator<InsetsState> CREATOR = new Creator<InsetsState>() { + + public InsetsState createFromParcel(Parcel in) { + return new InsetsState(in); + } + + public InsetsState[] newArray(int size) { + return new InsetsState[size]; + } + }; + + public void readFromParcel(Parcel in) { + mSources.clear(); + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + final InsetsSource source = in.readParcelable(null /* loader */); + mSources.put(source.getType(), source); + } + } +} + diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index a7a5024cd2a6..46f396a0b66b 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -375,9 +375,13 @@ public class SurfaceControl implements Parcelable { * Construct a new {@link SurfaceControl} with the set parameters. */ public SurfaceControl build() { - if (mWidth <= 0 || mHeight <= 0) { + if (mWidth < 0 || mHeight < 0) { throw new IllegalArgumentException( - "width and height must be set"); + "width and height must be positive or unset"); + } + if ((mWidth > 0 || mHeight > 0) && (isColorLayerSet() || isContainerLayerSet())) { + throw new IllegalArgumentException( + "Only buffer layers can set a valid buffer size."); } return new SurfaceControl(mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mWindowType, mOwnerUid); @@ -399,8 +403,8 @@ public class SurfaceControl implements Parcelable { * @param width The buffer width in pixels. * @param height The buffer height in pixels. */ - public Builder setSize(int width, int height) { - if (width <= 0 || height <= 0) { + public Builder setBufferSize(int width, int height) { + if (width < 0 || height < 0) { throw new IllegalArgumentException( "width and height must be positive"); } @@ -533,6 +537,10 @@ public class SurfaceControl implements Parcelable { return this; } + private boolean isColorLayerSet() { + return (mFlags & FX_SURFACE_DIM) == FX_SURFACE_DIM; + } + /** * Indicates whether a 'ContainerLayer' is to be constructed. * @@ -550,6 +558,10 @@ public class SurfaceControl implements Parcelable { return this; } + private boolean isContainerLayerSet() { + return (mFlags & FX_SURFACE_CONTAINER) == FX_SURFACE_CONTAINER; + } + /** * Set 'Surface creation flags' such as {@link HIDDEN}, {@link SECURE}. * @@ -869,10 +881,10 @@ public class SurfaceControl implements Parcelable { } } - public void setSize(int w, int h) { + public void setBufferSize(int w, int h) { checkNotReleased(); synchronized(SurfaceControl.class) { - sGlobalTransaction.setSize(this, w, h); + sGlobalTransaction.setBufferSize(this, w, h); } } @@ -1427,7 +1439,7 @@ public class SurfaceControl implements Parcelable { } @UnsupportedAppUsage - public Transaction setSize(SurfaceControl sc, int w, int h) { + public Transaction setBufferSize(SurfaceControl sc, int w, int h) { sc.checkNotReleased(); mResizedSurfaces.put(sc, new Point(w, h)); nativeSetSize(mNativeObject, sc.mNativeObject, w, h); diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 2b68ec0edcbe..3c4ce8f7cfad 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -557,7 +557,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb name, (mSurfaceFlags & SurfaceControl.OPAQUE) != 0, new SurfaceControl.Builder(mSurfaceSession) - .setSize(mSurfaceWidth, mSurfaceHeight) + .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFormat(mFormat) .setFlags(mSurfaceFlags)); } else if (mSurfaceControl == null) { @@ -595,10 +595,14 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth, 0.0f, 0.0f, mScreenRect.height() / (float) mSurfaceHeight); + // Set a window crop when creating the surface or changing its size to + // crop the buffer to the surface size since the buffer producer may + // use SCALING_MODE_SCALE and submit a larger size than the surface + // size. + mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight); } if (sizeChanged && !creating) { - mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight); - mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight); + mSurfaceControl.setBufferSize(mSurfaceWidth, mSurfaceHeight); } } finally { SurfaceControl.closeTransaction(); @@ -1133,6 +1137,8 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb mBackgroundControl = b.setName("Background for -" + name) .setFormat(OPAQUE) + // Unset the buffer size of the background color layer. + .setBufferSize(0, 0) .setColorLayer(true) .build(); mOpaque = opaque; @@ -1158,9 +1164,9 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb } @Override - public void setSize(int w, int h) { - super.setSize(w, h); - mBackgroundControl.setSize(w, h); + public void setBufferSize(int w, int h) { + super.setBufferSize(w, h); + // The background surface is a color layer so we do not set a size. } @Override diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0eaef5aa3c53..2767505aece3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -21525,10 +21525,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. - * @hide + * Assign a size and position to this view. + * + * This method is meant to be used in animations only as it applies this position and size + * for the view only temporary and it can be changed back at any time by the layout. + * + * @param left Left position, relative to parent + * @param top Top position, relative to parent + * @param right Right position, relative to parent + * @param bottom Bottom position, relative to parent + * + * @see #setLeft(int), #setRight(int), #setTop(int), #setBottom(int) */ - @UnsupportedAppUsage public void setLeftTopRightBottom(int left, int top, int right, int bottom) { setFrame(left, top, right, bottom); } @@ -24741,7 +24749,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final SurfaceSession session = new SurfaceSession(root.mSurface); final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) .setName("drag surface") - .setSize(shadowSize.x, shadowSize.y) + .setBufferSize(shadowSize.x, shadowSize.y) .setFormat(PixelFormat.TRANSLUCENT) .build(); final Surface surface = new Surface(); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 484c6f38e962..937e23813cec 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -161,6 +161,19 @@ public final class ViewRootImpl implements ViewParent, private static final boolean MT_RENDERER_AVAILABLE = true; /** + * If set to true, the view system will switch from using rectangles retrieved from window to + * dispatch to the view hierarchy to using {@link InsetsController}, that derives the insets + * directly from the full configuration, enabling richer information about the insets state, as + * well as new APIs to control it frame-by-frame, and synchronize animations with it. + * <p> + * Only switch this to true once the new insets system is productionized and the old APIs are + * fully migrated over. + */ + private static final String USE_NEW_INSETS_PROPERTY = "persist.wm.new_insets"; + private static final boolean USE_NEW_INSETS = + SystemProperties.getBoolean(USE_NEW_INSETS_PROPERTY, false); + + /** * Set this system property to true to force the view hierarchy to render * at 60 Hz. This can be used to measure the potential framerate. */ @@ -432,6 +445,8 @@ public final class ViewRootImpl implements ViewParent, boolean mAdded; boolean mAddedTouchMode; + final Rect mTmpFrame = new Rect(); + // These are accessed by multiple threads. final Rect mWinFrame; // frame given by window manager. @@ -444,6 +459,7 @@ public final class ViewRootImpl implements ViewParent, final DisplayCutout.ParcelableWrapper mPendingDisplayCutout = new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT); boolean mPendingAlwaysConsumeNavBar; + private InsetsState mPendingInsets = new InsetsState(); final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets = new ViewTreeObserver.InternalInsetsInfo(); @@ -531,6 +547,8 @@ public final class ViewRootImpl implements ViewParent, InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, 0) : null; + private final InsetsController mInsetsController = new InsetsController(); + static final class SystemUiVisibilityInfo { int seq; int globalVisibility; @@ -797,9 +815,11 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, - getHostVisibility(), mDisplay.getDisplayId(), mWinFrame, + getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, - mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel); + mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, + mInsetsController.getState()); + setFrame(mTmpFrame); } catch (RemoteException e) { mAdded = false; mView = null; @@ -826,6 +846,7 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mAlwaysConsumeNavBar = (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0; mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar; + mPendingInsets = mInsetsController.getState(); if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); if (res < WindowManagerGlobal.ADD_OKAY) { mAttachInfo.mRootView = null; @@ -1473,31 +1494,22 @@ public final class ViewRootImpl implements ViewParent, mBoundsSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName("Bounds for - " + getTitle().toString()) - .setSize(mWidth, mHeight) .build(); - setBoundsSurfaceSizeAndCrop(); + setBoundsSurfaceCrop(); mTransaction.setLayer(mBoundsSurfaceControl, zOrderLayer) .show(mBoundsSurfaceControl) .apply(); mBoundsSurface.copyFrom(mBoundsSurfaceControl); } - private void setBoundsSurfaceSizeAndCrop() { + private void setBoundsSurfaceCrop() { // mWinFrame is already adjusted for surface insets. So offset it and use it as // the cropping bounds. mTempBoundsRect.set(mWinFrame); mTempBoundsRect.offsetTo(mWindowAttributes.surfaceInsets.left, mWindowAttributes.surfaceInsets.top); mTransaction.setWindowCrop(mBoundsSurfaceControl, mTempBoundsRect); - - // Expand the bounds by the surface insets to get the size of surface. - mTempBoundsRect.inset(-mWindowAttributes.surfaceInsets.left, - -mWindowAttributes.surfaceInsets.top, - -mWindowAttributes.surfaceInsets.right, - -mWindowAttributes.surfaceInsets.bottom); - mTransaction.setSize(mBoundsSurfaceControl, mTempBoundsRect.width(), - mTempBoundsRect.height()); } /** @@ -1506,7 +1518,7 @@ public final class ViewRootImpl implements ViewParent, */ private void updateBoundsSurface() { if (mBoundsSurfaceControl != null && mSurface.isValid()) { - setBoundsSurfaceSizeAndCrop(); + setBoundsSurfaceCrop(); mTransaction.deferTransactionUntilSurface(mBoundsSurfaceControl, mSurface, mSurface.getNextFrameNumber()) .apply(); @@ -1780,7 +1792,8 @@ public final class ViewRootImpl implements ViewParent, Rect stableInsets = mDispatchStableInsets; DisplayCutout displayCutout = mDispatchDisplayCutout; // For dispatch we preserve old logic, but for direct requests from Views we allow to - // immediately use pending insets. + // immediately use pending insets. This is such that getRootWindowInsets returns the + // result from the layout hint before we ran a traversal shortly after adding a window. if (!forceConstruct && (!mPendingContentInsets.equals(contentInsets) || !mPendingStableInsets.equals(stableInsets) || @@ -1797,10 +1810,16 @@ public final class ViewRootImpl implements ViewParent, } contentInsets = ensureInsetsNonNegative(contentInsets, "content"); stableInsets = ensureInsetsNonNegative(stableInsets, "stable"); - mLastWindowInsets = new WindowInsets(contentInsets, - null /* windowDecorInsets */, stableInsets, - mContext.getResources().getConfiguration().isScreenRound(), - mAttachInfo.mAlwaysConsumeNavBar, displayCutout); + if (USE_NEW_INSETS) { + mLastWindowInsets = mInsetsController.calculateInsets( + mContext.getResources().getConfiguration().isScreenRound(), + mAttachInfo.mAlwaysConsumeNavBar, displayCutout); + } else { + mLastWindowInsets = new WindowInsets(contentInsets, + null /* windowDecorInsets */, stableInsets, + mContext.getResources().getConfiguration().isScreenRound(), + mAttachInfo.mAlwaysConsumeNavBar, displayCutout); + } } return mLastWindowInsets; } @@ -2000,6 +2019,9 @@ public final class ViewRootImpl implements ViewParent, if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) { insetsChanged = true; } + if (!mPendingInsets.equals(mInsetsController.getState())) { + insetsChanged = true; + } if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { windowSizeMayChange = true; @@ -2193,6 +2215,8 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mStableInsets); final boolean cutoutChanged = !mPendingDisplayCutout.equals( mAttachInfo.mDisplayCutout); + final boolean insetsStateChanged = !mPendingInsets.equals( + mInsetsController.getState()); final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets); final boolean surfaceSizeChanged = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0; @@ -2230,6 +2254,10 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar; contentInsetsChanged = true; } + if (insetsStateChanged) { + mInsetsController.setState(mPendingInsets); + contentInsetsChanged = true; + } if (contentInsetsChanged || mLastSystemUiVisibility != mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested || mLastOverscanRequested != mAttachInfo.mOverscanRequested @@ -2675,7 +2703,6 @@ public final class ViewRootImpl implements ViewParent, } private void maybeHandleWindowMove(Rect frame) { - // TODO: Well, we are checking whether the frame has changed similarly // to how this is done for the insets. This is however incorrect since // the insets and the frame are translated. For example, the old frame @@ -4180,6 +4207,7 @@ public final class ViewRootImpl implements ViewParent, private final static int MSG_UPDATE_POINTER_ICON = 27; private final static int MSG_POINTER_CAPTURE_CHANGED = 28; private final static int MSG_DRAW_FINISHED = 29; + private final static int MSG_INSETS_CHANGED = 30; final class ViewRootHandler extends Handler { @Override @@ -4235,6 +4263,8 @@ public final class ViewRootImpl implements ViewParent, return "MSG_POINTER_CAPTURE_CHANGED"; case MSG_DRAW_FINISHED: return "MSG_DRAW_FINISHED"; + case MSG_INSETS_CHANGED: + return "MSG_INSETS_CHANGED"; } return super.getMessageName(message); } @@ -4315,7 +4345,7 @@ public final class ViewRootImpl implements ViewParent, || !mPendingVisibleInsets.equals(args.arg3) || !mPendingOutsets.equals(args.arg7); - mWinFrame.set((Rect) args.arg1); + setFrame((Rect) args.arg1); mPendingOverscanInsets.set((Rect) args.arg5); mPendingContentInsets.set((Rect) args.arg2); mPendingStableInsets.set((Rect) args.arg6); @@ -4338,16 +4368,25 @@ public final class ViewRootImpl implements ViewParent, requestLayout(); } break; + case MSG_INSETS_CHANGED: + mPendingInsets = (InsetsState) msg.obj; + + // TODO: Full traversal not needed here + if (USE_NEW_INSETS) { + requestLayout(); + } + break; case MSG_WINDOW_MOVED: if (mAdded) { final int w = mWinFrame.width(); final int h = mWinFrame.height(); final int l = msg.arg1; final int t = msg.arg2; - mWinFrame.left = l; - mWinFrame.right = l + w; - mWinFrame.top = t; - mWinFrame.bottom = t + h; + mTmpFrame.left = l; + mTmpFrame.right = l + w; + mTmpFrame.top = t; + mTmpFrame.bottom = t + h; + setFrame(mTmpFrame); mPendingBackDropFrame.set(mWinFrame); maybeHandleWindowMove(mWinFrame); @@ -6733,9 +6772,9 @@ public final class ViewRootImpl implements ViewParent, (int) (mView.getMeasuredWidth() * appScale + 0.5f), (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber, - mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, + mTmpFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout, - mPendingMergedConfiguration, mSurface); + mPendingMergedConfiguration, mSurface, mPendingInsets); mPendingAlwaysConsumeNavBar = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0; @@ -6745,15 +6784,22 @@ public final class ViewRootImpl implements ViewParent, } if (mTranslator != null) { - mTranslator.translateRectInScreenToAppWinFrame(mWinFrame); + mTranslator.translateRectInScreenToAppWinFrame(mTmpFrame); mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets); mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets); mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets); mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets); } + setFrame(mTmpFrame); + return relayoutResult; } + private void setFrame(Rect frame) { + mWinFrame.set(frame); + mInsetsController.onFrameChanged(frame); + } + /** * {@inheritDoc} */ @@ -6856,6 +6902,8 @@ public final class ViewRootImpl implements ViewParent, mChoreographer.dump(prefix, writer); + mInsetsController.dump(prefix, writer); + writer.print(prefix); writer.println("View Hierarchy:"); dumpViewHierarchy(innerPrefix, writer, mView); } @@ -7064,6 +7112,10 @@ public final class ViewRootImpl implements ViewParent, mHandler.sendMessage(msg); } + private void dispatchInsetsChanged(InsetsState insetsState) { + mHandler.obtainMessage(MSG_INSETS_CHANGED, insetsState).sendToTarget(); + } + public void dispatchMoved(int newX, int newY) { if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY); if (mTranslator != null) { @@ -8127,6 +8179,14 @@ public final class ViewRootImpl implements ViewParent, } @Override + public void insetsChanged(InsetsState insetsState) { + final ViewRootImpl viewAncestor = mViewAncestor.get(); + if (viewAncestor != null) { + viewAncestor.dispatchInsetsChanged(insetsState); + } + } + + @Override public void moved(int newX, int newY) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index f4c25c3831be..7d027574198d 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -837,7 +837,7 @@ public final class Magnifier { mSurfaceSession = new SurfaceSession(parentSurface); mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setFormat(PixelFormat.TRANSLUCENT) - .setSize(mSurfaceWidth, mSurfaceHeight) + .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setName("magnifier surface") .setFlags(SurfaceControl.HIDDEN) .build(); diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index c0979fe13de4..7b39efed0c3a 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -161,6 +161,7 @@ public class RemoteViews implements Parcelable, Filter { private static final int LAYOUT_PARAM_ACTION_TAG = 19; private static final int OVERRIDE_TEXT_COLORS_TAG = 20; private static final int SET_RIPPLE_DRAWABLE_COLOR_TAG = 21; + private static final int SET_INT_TAG_TAG = 22; /** * Application that hosts the remote views. @@ -274,6 +275,15 @@ public class RemoteViews implements Parcelable, Filter { } /** + * Sets an integer tag to the view. + * + * @hide + */ + public void setIntTag(int viewId, int key, int tag) { + addAction(new SetIntTagAction(viewId, key, tag)); + } + + /** * Set that it is disallowed to reapply another remoteview with the same layout as this view. * This should be done if an action is destroying the view tree of the base layout. * @@ -2122,6 +2132,43 @@ public class RemoteViews implements Parcelable, Filter { } } + private class SetIntTagAction extends Action { + private final int mViewId; + private final int mKey; + private final int mTag; + + SetIntTagAction(int viewId, int key, int tag) { + mViewId = viewId; + mKey = key; + mTag = tag; + } + + SetIntTagAction(Parcel parcel) { + mViewId = parcel.readInt(); + mKey = parcel.readInt(); + mTag = parcel.readInt(); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mViewId); + dest.writeInt(mKey); + dest.writeInt(mTag); + } + + @Override + public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { + final View target = root.findViewById(mViewId); + if (target == null) return; + + target.setTagInternal(mKey, mTag); + } + + @Override + public int getActionTag() { + return SET_INT_TAG_TAG; + } + } + /** * Create a new RemoteViews object that will display the views contained * in the specified layout file. @@ -2326,6 +2373,8 @@ public class RemoteViews implements Parcelable, Filter { return new OverrideTextColorsAction(parcel); case SET_RIPPLE_DRAWABLE_COLOR_TAG: return new SetRippleDrawableColor(parcel); + case SET_INT_TAG_TAG: + return new SetIntTagAction(parcel); default: throw new ActionException("Tag " + tag + " not found"); } diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java index b9d53c1b5884..d78bfac1f878 100644 --- a/core/java/com/android/internal/os/SomeArgs.java +++ b/core/java/com/android/internal/os/SomeArgs.java @@ -120,6 +120,8 @@ public final class SomeArgs { arg5 = null; arg6 = null; arg7 = null; + arg8 = null; + arg9 = null; argi1 = 0; argi2 = 0; argi3 = 0; diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 69ba07090284..b7ffb5768a31 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -16,6 +16,7 @@ package com.android.internal.statusbar; +import android.app.Notification; import android.content.ComponentName; import android.graphics.Rect; import android.os.Bundle; @@ -55,7 +56,7 @@ interface IStatusBarService // Mark current notifications as "seen" and stop ringing, vibrating, blinking. void clearNotificationEffects(); void onNotificationClick(String key, in NotificationVisibility nv); - void onNotificationActionClick(String key, int actionIndex, in NotificationVisibility nv); + void onNotificationActionClick(String key, int actionIndex, in Notification.Action action, in NotificationVisibility nv, boolean generatedByAssistant); void onNotificationError(String pkg, String tag, int id, int uid, int initialPid, String message, int userId); void onClearAllNotifications(int userId); diff --git a/core/java/com/android/internal/util/function/NonaConsumer.java b/core/java/com/android/internal/util/function/NonaConsumer.java new file mode 100644 index 000000000000..3e7ce2b405a7 --- /dev/null +++ b/core/java/com/android/internal/util/function/NonaConsumer.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Consumer; + +/** + * A 9-argument {@link Consumer} + * + * @hide + */ +public interface NonaConsumer<A, B, C, D, E, F, G, H, I> { + void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i); +} diff --git a/core/java/com/android/internal/util/function/NonaFunction.java b/core/java/com/android/internal/util/function/NonaFunction.java new file mode 100644 index 000000000000..560b4f157ee1 --- /dev/null +++ b/core/java/com/android/internal/util/function/NonaFunction.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Function; + +/** + * A 9-argument {@link Function} + * + * @hide + */ +public interface NonaFunction<A, B, C, D, E, F, G, H, I, R> { + R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i); +} diff --git a/core/java/com/android/internal/util/function/NonaPredicate.java b/core/java/com/android/internal/util/function/NonaPredicate.java new file mode 100644 index 000000000000..c1e6f377e7ae --- /dev/null +++ b/core/java/com/android/internal/util/function/NonaPredicate.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Predicate; + +/** + * A 9-argument {@link Predicate} + * + * @hide + */ +public interface NonaPredicate<A, B, C, D, E, F, G, H, I> { + boolean test(A a, B b, C c, D d, E e, F f, G g, H h, I i); +} diff --git a/core/java/com/android/internal/util/function/OctConsumer.java b/core/java/com/android/internal/util/function/OctConsumer.java new file mode 100644 index 000000000000..83ee30530c26 --- /dev/null +++ b/core/java/com/android/internal/util/function/OctConsumer.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Consumer; + +/** + * A 8-argument {@link Consumer} + * + * @hide + */ +public interface OctConsumer<A, B, C, D, E, F, G, H> { + void accept(A a, B b, C c, D d, E e, F f, G g, H h); +} diff --git a/core/java/com/android/internal/util/function/OctFunction.java b/core/java/com/android/internal/util/function/OctFunction.java new file mode 100644 index 000000000000..cb16624725b7 --- /dev/null +++ b/core/java/com/android/internal/util/function/OctFunction.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Function; + +/** + * A 8-argument {@link Function} + * + * @hide + */ +public interface OctFunction<A, B, C, D, E, F, G, H, R> { + R apply(A a, B b, C c, D d, E e, F f, G g, H h); +} diff --git a/core/java/com/android/internal/util/function/OctPredicate.java b/core/java/com/android/internal/util/function/OctPredicate.java new file mode 100644 index 000000000000..7f36d6acc066 --- /dev/null +++ b/core/java/com/android/internal/util/function/OctPredicate.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Predicate; + +/** + * A 8-argument {@link Predicate} + * + * @hide + */ +public interface OctPredicate<A, B, C, D, E, F, G, H> { + boolean test(A a, B b, C c, D d, E e, F f, G g, H h); +} diff --git a/core/java/com/android/internal/util/function/pooled/OmniFunction.java b/core/java/com/android/internal/util/function/pooled/OmniFunction.java index 4ffe44194958..d74e715605bb 100755 --- a/core/java/com/android/internal/util/function/pooled/OmniFunction.java +++ b/core/java/com/android/internal/util/function/pooled/OmniFunction.java @@ -22,6 +22,10 @@ import com.android.internal.util.function.HeptConsumer; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; +import com.android.internal.util.function.NonaConsumer; +import com.android.internal.util.function.NonaFunction; +import com.android.internal.util.function.OctConsumer; +import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadConsumer; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuintConsumer; @@ -39,61 +43,62 @@ import java.util.function.Function; * * @hide */ -abstract class OmniFunction<A, B, C, D, E, F, G, R> implements +abstract class OmniFunction<A, B, C, D, E, F, G, H, I, R> implements PooledFunction<A, R>, BiFunction<A, B, R>, TriFunction<A, B, C, R>, QuadFunction<A, B, C, D, R>, QuintFunction<A, B, C, D, E, R>, HexFunction<A, B, C, D, E, F, R>, HeptFunction<A, B, C, D, E, F, G, R>, + OctFunction<A, B, C, D, E, F, G, H, R>, NonaFunction<A, B, C, D, E, F, G, H, I, R>, PooledConsumer<A>, BiConsumer<A, B>, TriConsumer<A, B, C>, QuadConsumer<A, B, C, D>, QuintConsumer<A, B, C, D, E>, HexConsumer<A, B, C, D, E, F>, - HeptConsumer<A, B, C, D, E, F, G>, - PooledPredicate<A>, BiPredicate<A, B>, + HeptConsumer<A, B, C, D, E, F, G>, OctConsumer<A, B, C, D, E, F, G, H>, + NonaConsumer<A, B, C, D, E, F, G, H, I>, PooledPredicate<A>, BiPredicate<A, B>, PooledSupplier<R>, PooledRunnable, ThrowingRunnable, ThrowingSupplier<R>, PooledSupplier.OfInt, PooledSupplier.OfLong, PooledSupplier.OfDouble { - abstract R invoke(A a, B b, C c, D d, E e, F f, G g); + abstract R invoke(A a, B b, C c, D d, E e, F f, G g, H h, I i); @Override public R apply(A o, B o2) { - return invoke(o, o2, null, null, null, null, null); + return invoke(o, o2, null, null, null, null, null, null, null); } @Override public R apply(A o) { - return invoke(o, null, null, null, null, null, null); + return invoke(o, null, null, null, null, null, null, null, null); } - public abstract <V> OmniFunction<A, B, C, D, E, F, G, V> andThen( + public abstract <V> OmniFunction<A, B, C, D, E, F, G, H, I, V> andThen( Function<? super R, ? extends V> after); - public abstract OmniFunction<A, B, C, D, E, F, G, R> negate(); + public abstract OmniFunction<A, B, C, D, E, F, G, H, I, R> negate(); @Override public void accept(A o, B o2) { - invoke(o, o2, null, null, null, null, null); + invoke(o, o2, null, null, null, null, null, null, null); } @Override public void accept(A o) { - invoke(o, null, null, null, null, null, null); + invoke(o, null, null, null, null, null, null, null, null); } @Override public void run() { - invoke(null, null, null, null, null, null, null); + invoke(null, null, null, null, null, null, null, null, null); } @Override public R get() { - return invoke(null, null, null, null, null, null, null); + return invoke(null, null, null, null, null, null, null, null, null); } @Override public boolean test(A o, B o2) { - return (Boolean) invoke(o, o2, null, null, null, null, null); + return (Boolean) invoke(o, o2, null, null, null, null, null, null, null); } @Override public boolean test(A o) { - return (Boolean) invoke(o, null, null, null, null, null, null); + return (Boolean) invoke(o, null, null, null, null, null, null, null, null); } @Override @@ -108,52 +113,72 @@ abstract class OmniFunction<A, B, C, D, E, F, G, R> implements @Override public R apply(A a, B b, C c) { - return invoke(a, b, c, null, null, null, null); + return invoke(a, b, c, null, null, null, null, null, null); } @Override public void accept(A a, B b, C c) { - invoke(a, b, c, null, null, null, null); + invoke(a, b, c, null, null, null, null, null, null); } @Override public R apply(A a, B b, C c, D d) { - return invoke(a, b, c, d, null, null, null); + return invoke(a, b, c, d, null, null, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e) { - return invoke(a, b, c, d, e, null, null); + return invoke(a, b, c, d, e, null, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e, F f) { - return invoke(a, b, c, d, e, f, null); + return invoke(a, b, c, d, e, f, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e, F f, G g) { - return invoke(a, b, c, d, e, f, g); + return invoke(a, b, c, d, e, f, g, null, null); + } + + @Override + public R apply(A a, B b, C c, D d, E e, F f, G g, H h) { + return invoke(a, b, c, d, e, f, g, h, null); + } + + @Override + public R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i) { + return invoke(a, b, c, d, e, f, g, h, i); } @Override public void accept(A a, B b, C c, D d) { - invoke(a, b, c, d, null, null, null); + invoke(a, b, c, d, null, null, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e) { - invoke(a, b, c, d, e, null, null); + invoke(a, b, c, d, e, null, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e, F f) { - invoke(a, b, c, d, e, f, null); + invoke(a, b, c, d, e, f, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e, F f, G g) { - invoke(a, b, c, d, e, f, g); + invoke(a, b, c, d, e, f, g, null, null); + } + + @Override + public void accept(A a, B b, C c, D d, E e, F f, G g, H h) { + invoke(a, b, c, d, e, f, g, h, null); + } + + @Override + public void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i) { + invoke(a, b, c, d, e, f, g, h, i); } @Override @@ -167,5 +192,5 @@ abstract class OmniFunction<A, B, C, D, E, F, G, R> implements } @Override - public abstract OmniFunction<A, B, C, D, E, F, G, R> recycleOnUse(); + public abstract OmniFunction<A, B, C, D, E, F, G, H, I, R> recycleOnUse(); } diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java index af3c7527c432..c00932e7a8aa 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambda.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java @@ -25,6 +25,10 @@ import com.android.internal.util.function.HeptConsumer; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; +import com.android.internal.util.function.NonaConsumer; +import com.android.internal.util.function.NonaFunction; +import com.android.internal.util.function.OctConsumer; +import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadConsumer; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuintConsumer; @@ -176,7 +180,8 @@ public interface PooledLambda { Consumer<? super A> function, A arg1) { return acquire(PooledLambdaImpl.sPool, - function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null); + function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null, + null); } /** @@ -192,7 +197,8 @@ public interface PooledLambda { Predicate<? super A> function, A arg1) { return acquire(PooledLambdaImpl.sPool, - function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null, null, null, null); + function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null, null, null, null, null, + null); } /** @@ -208,7 +214,8 @@ public interface PooledLambda { Function<? super A, ? extends R> function, A arg1) { return acquire(PooledLambdaImpl.sPool, - function, 1, 0, ReturnType.OBJECT, arg1, null, null, null, null, null, null); + function, 1, 0, ReturnType.OBJECT, arg1, null, null, null, null, null, null, null, + null); } /** @@ -238,7 +245,8 @@ public interface PooledLambda { A arg1) { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, - function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null); + function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null, + null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -257,7 +265,8 @@ public interface PooledLambda { BiConsumer<? super A, ? super B> function, A arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, - function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null); + function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, + null); } /** @@ -274,7 +283,8 @@ public interface PooledLambda { BiPredicate<? super A, ? super B> function, A arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, - function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null); + function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null, + null); } /** @@ -291,7 +301,8 @@ public interface PooledLambda { BiFunction<? super A, ? super B, ? extends R> function, A arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, - function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null); + function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null, + null); } /** @@ -308,7 +319,8 @@ public interface PooledLambda { BiConsumer<? super A, ? super B> function, ArgumentPlaceholder<A> arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, - function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null); + function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, + null); } /** @@ -325,7 +337,8 @@ public interface PooledLambda { BiPredicate<? super A, ? super B> function, ArgumentPlaceholder<A> arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, - function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null); + function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null, + null); } /** @@ -342,7 +355,8 @@ public interface PooledLambda { BiFunction<? super A, ? super B, ? extends R> function, ArgumentPlaceholder<A> arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, - function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null); + function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null, + null); } /** @@ -359,7 +373,8 @@ public interface PooledLambda { BiConsumer<? super A, ? super B> function, A arg1, ArgumentPlaceholder<B> arg2) { return acquire(PooledLambdaImpl.sPool, - function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null); + function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, + null); } /** @@ -376,7 +391,8 @@ public interface PooledLambda { BiPredicate<? super A, ? super B> function, A arg1, ArgumentPlaceholder<B> arg2) { return acquire(PooledLambdaImpl.sPool, - function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null); + function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null, + null); } /** @@ -393,7 +409,8 @@ public interface PooledLambda { BiFunction<? super A, ? super B, ? extends R> function, A arg1, ArgumentPlaceholder<B> arg2) { return acquire(PooledLambdaImpl.sPool, - function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null); + function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null, + null); } /** @@ -424,7 +441,8 @@ public interface PooledLambda { A arg1, B arg2) { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, - function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null); + function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, + null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -444,7 +462,8 @@ public interface PooledLambda { TriConsumer<? super A, ? super B, ? super C> function, A arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, - function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null); + function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, + null); } /** @@ -462,7 +481,8 @@ public interface PooledLambda { TriFunction<? super A, ? super B, ? super C, ? extends R> function, A arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, - function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null); + function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, + null); } /** @@ -480,7 +500,8 @@ public interface PooledLambda { TriConsumer<? super A, ? super B, ? super C> function, ArgumentPlaceholder<A> arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, - function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null); + function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, + null); } /** @@ -498,7 +519,8 @@ public interface PooledLambda { TriFunction<? super A, ? super B, ? super C, ? extends R> function, ArgumentPlaceholder<A> arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, - function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null); + function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, + null); } /** @@ -516,7 +538,8 @@ public interface PooledLambda { TriConsumer<? super A, ? super B, ? super C> function, A arg1, ArgumentPlaceholder<B> arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, - function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null); + function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, + null); } /** @@ -534,7 +557,8 @@ public interface PooledLambda { TriFunction<? super A, ? super B, ? super C, ? extends R> function, A arg1, ArgumentPlaceholder<B> arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, - function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null); + function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, + null); } /** @@ -552,7 +576,8 @@ public interface PooledLambda { TriConsumer<? super A, ? super B, ? super C> function, A arg1, B arg2, ArgumentPlaceholder<C> arg3) { return acquire(PooledLambdaImpl.sPool, - function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null); + function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, + null); } /** @@ -570,7 +595,8 @@ public interface PooledLambda { TriFunction<? super A, ? super B, ? super C, ? extends R> function, A arg1, B arg2, ArgumentPlaceholder<C> arg3) { return acquire(PooledLambdaImpl.sPool, - function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null); + function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, + null); } /** @@ -602,7 +628,8 @@ public interface PooledLambda { A arg1, B arg2, C arg3) { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, - function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null); + function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, + null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -623,7 +650,8 @@ public interface PooledLambda { QuadConsumer<? super A, ? super B, ? super C, ? super D> function, A arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, - function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, + null); } /** @@ -642,7 +670,8 @@ public interface PooledLambda { QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function, A arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, - function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, + null); } /** @@ -661,7 +690,8 @@ public interface PooledLambda { QuadConsumer<? super A, ? super B, ? super C, ? super D> function, ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, - function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, + null); } /** @@ -680,7 +710,8 @@ public interface PooledLambda { QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function, ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, - function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, + null); } /** @@ -699,7 +730,8 @@ public interface PooledLambda { QuadConsumer<? super A, ? super B, ? super C, ? super D> function, A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, - function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, + null); } /** @@ -718,7 +750,8 @@ public interface PooledLambda { QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function, A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, - function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, + null); } /** @@ -737,7 +770,8 @@ public interface PooledLambda { QuadConsumer<? super A, ? super B, ? super C, ? super D> function, A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, - function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, + null); } /** @@ -756,7 +790,8 @@ public interface PooledLambda { QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function, A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, - function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, + null); } /** @@ -775,7 +810,8 @@ public interface PooledLambda { QuadConsumer<? super A, ? super B, ? super C, ? super D> function, A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) { return acquire(PooledLambdaImpl.sPool, - function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, + null); } /** @@ -794,7 +830,8 @@ public interface PooledLambda { QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function, A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) { return acquire(PooledLambdaImpl.sPool, - function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, + null); } /** @@ -827,7 +864,8 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4) { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, - function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null); + function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, + null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -849,7 +887,8 @@ public interface PooledLambda { QuintConsumer<? super A, ? super B, ? super C, ? super D, ? super E> function, A arg1, B arg2, C arg3, D arg4, E arg5) { return acquire(PooledLambdaImpl.sPool, - function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null); + function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null, + null); } /** @@ -869,7 +908,8 @@ public interface PooledLambda { QuintFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? extends R> function, A arg1, B arg2, C arg3, D arg4, E arg5) { return acquire(PooledLambdaImpl.sPool, - function, 5, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, null, null); + function, 5, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, null, null, null, + null); } /** @@ -904,7 +944,8 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5) { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, - function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null); + function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null, + null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -927,7 +968,8 @@ public interface PooledLambda { HexConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) { return acquire(PooledLambdaImpl.sPool, - function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null); + function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null, + null); } /** @@ -948,7 +990,8 @@ public interface PooledLambda { HexFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, ? extends R> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) { return acquire(PooledLambdaImpl.sPool, - function, 6, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, null); + function, 6, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, null, null, + null); } /** @@ -984,7 +1027,8 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, - function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null); + function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null, + null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -1008,7 +1052,8 @@ public interface PooledLambda { HeptConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, ? super G> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) { return acquire(PooledLambdaImpl.sPool, - function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null, + null); } /** @@ -1031,7 +1076,8 @@ public interface PooledLambda { ? super G, ? extends R> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) { return acquire(PooledLambdaImpl.sPool, - function, 7, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + function, 7, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null, + null); } /** @@ -1068,7 +1114,195 @@ public interface PooledLambda { ? super G> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, - function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null, + null); + return Message.obtain().setCallback(callback.recycleOnUse()); + } + } + + /** + * {@link PooledRunnable} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @return a {@link PooledRunnable}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) } + */ + static <A, B, C, D, E, F, G, H> PooledRunnable obtainRunnable( + OctConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, ? super G, + ? super H> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, + H arg8) { + return acquire(PooledLambdaImpl.sPool, + function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + null); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) } + */ + static <A, B, C, D, E, F, G, H, R> PooledSupplier<R> obtainSupplier( + OctFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? extends R> function, + A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8) { + return acquire(PooledLambdaImpl.sPool, + function, 8, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + null); + } + + /** + * Factory of {@link Message}s that contain an + * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its + * {@link Message#getCallback internal callback}. + * + * The callback is equivalent to one obtainable via + * {@link #obtainRunnable(QuintConsumer, Object, Object, Object, Object, Object)} + * + * Note that using this method with {@link android.os.Handler#handleMessage} + * is more efficient than the alternative of {@link android.os.Handler#post} + * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points + * when obtaining {@link Message} and {@link PooledRunnable} from pools separately + * + * You may optionally set a {@link Message#what} for the message if you want to be + * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise + * there's no need to do so + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4, arg5, arg6, + * arg7, arg8) } when handled + */ + static <A, B, C, D, E, F, G, H> Message obtainMessage( + OctConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, ? super G, + ? super H> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, + H arg8) { + synchronized (Message.sPoolSync) { + PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, + function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + null); + return Message.obtain().setCallback(callback.recycleOnUse()); + } + } + + /** + * {@link PooledRunnable} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @return a {@link PooledRunnable}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) } + */ + static <A, B, C, D, E, F, G, H, I> PooledRunnable obtainRunnable( + NonaConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I> function, A arg1, B arg2, C arg3, D arg4, + E arg5, F arg6, G arg7, H arg8, I arg9) { + return acquire(PooledLambdaImpl.sPool, + function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) } + */ + static <A, B, C, D, E, F, G, H, I, R> PooledSupplier<R> obtainSupplier( + NonaFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? extends R> function, + A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9) { + return acquire(PooledLambdaImpl.sPool, + function, 9, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9); + } + + /** + * Factory of {@link Message}s that contain an + * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its + * {@link Message#getCallback internal callback}. + * + * The callback is equivalent to one obtainable via + * {@link #obtainRunnable(QuintConsumer, Object, Object, Object, Object, Object)} + * + * Note that using this method with {@link android.os.Handler#handleMessage} + * is more efficient than the alternative of {@link android.os.Handler#post} + * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points + * when obtaining {@link Message} and {@link PooledRunnable} from pools separately + * + * You may optionally set a {@link Message#what} for the message if you want to be + * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise + * there's no need to do so + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4, arg5, arg6, + * arg7, arg8, arg9) } when handled + */ + static <A, B, C, D, E, F, G, H, I> Message obtainMessage( + NonaConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I> function, A arg1, B arg2, C arg3, D arg4, + E arg5, F arg6, G arg7, H arg8, I arg9) { + synchronized (Message.sPoolSync) { + PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, + function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9); return Message.obtain().setCallback(callback.recycleOnUse()); } } diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java index eea1e5f0ac5c..6be626a5134a 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java @@ -30,6 +30,12 @@ import com.android.internal.util.function.HeptPredicate; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; import com.android.internal.util.function.HexPredicate; +import com.android.internal.util.function.NonaConsumer; +import com.android.internal.util.function.NonaFunction; +import com.android.internal.util.function.NonaPredicate; +import com.android.internal.util.function.OctConsumer; +import com.android.internal.util.function.OctFunction; +import com.android.internal.util.function.OctPredicate; import com.android.internal.util.function.QuadConsumer; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuadPredicate; @@ -54,12 +60,12 @@ import java.util.function.Supplier; * @hide */ final class PooledLambdaImpl<R> extends OmniFunction<Object, - Object, Object, Object, Object, Object, Object, R> { + Object, Object, Object, Object, Object, Object, Object, Object, R> { private static final boolean DEBUG = false; private static final String LOG_TAG = "PooledLambdaImpl"; - private static final int MAX_ARGS = 7; + private static final int MAX_ARGS = 9; private static final int MAX_POOL_SIZE = 50; @@ -125,7 +131,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, /** * Bit schema: - * AAAAAAABCDEEEEEEFFFFFF + * AAAAAAAAABCDEEEEEEFFFFFF * * Where: * A - whether {@link #mArgs arg} at corresponding index was specified at @@ -161,17 +167,19 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, } @Override - R invoke(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) { + R invoke(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, + Object a8, Object a9) { checkNotRecycled(); if (DEBUG) { Log.i(LOG_TAG, this + ".invoke(" + commaSeparateFirstN( - new Object[] { a1, a2, a3, a4, a5, a6, a7 }, + new Object[] { a1, a2, a3, a4, a5, a6, a7, a8, a9 }, LambdaType.decodeArgCount(getFlags(MASK_EXPOSED_AS))) + ")"); } - final boolean notUsed = fillInArg(a1) && fillInArg(a2) && fillInArg(a3) - && fillInArg(a4) && fillInArg(a5) && fillInArg(a6) && fillInArg(a7); + final boolean notUsed = fillInArg(a1) && fillInArg(a2) && fillInArg(a3) && fillInArg(a4) + && fillInArg(a5) && fillInArg(a6) && fillInArg(a7) && fillInArg(a8) + && fillInArg(a9); int argCount = LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)); if (argCount != LambdaType.MASK_ARG_COUNT) { for (int i = 0; i < argCount; i++) { @@ -335,7 +343,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, popArg(2), popArg(3), popArg(4), popArg(5)); } } - } + } break; case 7: { switch (returnType) { @@ -356,7 +364,49 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, popArg(5), popArg(6)); } } - } + } break; + + case 8: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((OctConsumer) mFunc).accept(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), + popArg(5), popArg(6), popArg(7)); + return null; + } + case LambdaType.ReturnType.BOOLEAN: { + return (R) (Object) ((OctPredicate) mFunc).test(popArg(0), + popArg(1), popArg(2), popArg(3), + popArg(4), popArg(5), popArg(6), popArg(7)); + } + case LambdaType.ReturnType.OBJECT: { + return (R) ((OctFunction) mFunc).apply(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), + popArg(5), popArg(6), popArg(7)); + } + } + } break; + + case 9: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((NonaConsumer) mFunc).accept(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), popArg(5), + popArg(6), popArg(7), popArg(8)); + return null; + } + case LambdaType.ReturnType.BOOLEAN: { + return (R) (Object) ((NonaPredicate) mFunc).test(popArg(0), + popArg(1), popArg(2), popArg(3), popArg(4), + popArg(5), popArg(6), popArg(7), popArg(8)); + } + case LambdaType.ReturnType.OBJECT: { + return (R) ((NonaFunction) mFunc).apply(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), popArg(5), + popArg(6), popArg(7), popArg(8)); + } + } + } break; } throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType)); } @@ -419,8 +469,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, * Internal non-typesafe factory method for {@link PooledLambdaImpl} */ static <E extends PooledLambda> E acquire(Pool pool, Object func, - int fNumArgs, int numPlaceholders, int fReturnType, - Object a, Object b, Object c, Object d, Object e, Object f, Object g) { + int fNumArgs, int numPlaceholders, int fReturnType, Object a, Object b, Object c, + Object d, Object e, Object f, Object g, Object h, Object i) { PooledLambdaImpl r = acquire(pool); if (DEBUG) { Log.i(LOG_TAG, @@ -436,6 +486,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, + ", e = " + e + ", f = " + f + ", g = " + g + + ", h = " + h + + ", i = " + i + ")"); } r.mFunc = func; @@ -449,6 +501,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, setIfInBounds(r.mArgs, 4, e); setIfInBounds(r.mArgs, 5, f); setIfInBounds(r.mArgs, 6, g); + setIfInBounds(r.mArgs, 7, h); + setIfInBounds(r.mArgs, 8, i); return (E) r; } @@ -474,13 +528,14 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, } @Override - public OmniFunction<Object, Object, Object, Object, Object, Object, Object, R> negate() { + public OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, + R> negate() { throw new UnsupportedOperationException(); } @Override - public <V> OmniFunction<Object, Object, Object, Object, Object, Object, Object, V> andThen( - Function<? super R, ? extends V> after) { + public <V> OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, + V> andThen(Function<? super R, ? extends V> after) { throw new UnsupportedOperationException(); } @@ -500,7 +555,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, } @Override - public OmniFunction<Object, Object, Object, Object, Object, Object, Object, R> recycleOnUse() { + public OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, + R> recycleOnUse() { if (DEBUG) Log.i(LOG_TAG, this + ".recycleOnUse()"); mFlags |= FLAG_RECYCLE_ON_USE; return this; @@ -584,6 +640,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, case 5: return "Quint"; case 6: return "Hex"; case 7: return "Hept"; + case 8: return "Oct"; + case 9: return "Nona"; default: throw new IllegalArgumentException("" + argCount); } } diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index 137ca7f2ac27..36fe4fc5af49 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -27,6 +27,7 @@ import android.view.DragEvent; import android.view.IWindow; import android.view.IWindowSession; import android.view.PointerIcon; +import android.view.InsetsState; import com.android.internal.os.IResultReceiver; @@ -53,6 +54,10 @@ public class BaseIWindow extends IWindow.Stub { } @Override + public void insetsChanged(InsetsState insetsState) { + } + + @Override public void moved(int newX, int newY) { } diff --git a/core/jni/android_hardware_display_DisplayViewport.cpp b/core/jni/android_hardware_display_DisplayViewport.cpp index 05f6556bfb35..e74aafe61e00 100644 --- a/core/jni/android_hardware_display_DisplayViewport.cpp +++ b/core/jni/android_hardware_display_DisplayViewport.cpp @@ -40,6 +40,7 @@ static struct { jfieldID deviceWidth; jfieldID deviceHeight; jfieldID uniqueId; + jfieldID physicalPort; jfieldID type; } gDisplayViewportClassInfo; @@ -54,6 +55,9 @@ static struct { status_t android_hardware_display_DisplayViewport_toNative(JNIEnv* env, jobject viewportObj, DisplayViewport* viewport) { + static const jclass byteClass = FindClassOrDie(env, "java/lang/Byte"); + static const jmethodID byteValue = env->GetMethodID(byteClass, "byteValue", "()B"); + viewport->displayId = env->GetIntField(viewportObj, gDisplayViewportClassInfo.displayId); viewport->orientation = env->GetIntField(viewportObj, gDisplayViewportClassInfo.orientation); viewport->deviceWidth = env->GetIntField(viewportObj, gDisplayViewportClassInfo.deviceWidth); @@ -65,6 +69,12 @@ status_t android_hardware_display_DisplayViewport_toNative(JNIEnv* env, jobject viewport->uniqueId = ScopedUtfChars(env, uniqueId).c_str(); } + viewport->physicalPort = std::nullopt; + jobject physicalPort = env->GetObjectField(viewportObj, gDisplayViewportClassInfo.physicalPort); + if (physicalPort != nullptr) { + viewport->physicalPort = std::make_optional(env->CallByteMethod(physicalPort, byteValue)); + } + viewport->type = static_cast<ViewportType>(env->GetIntField(viewportObj, gDisplayViewportClassInfo.type)); @@ -112,6 +122,9 @@ int register_android_hardware_display_DisplayViewport(JNIEnv* env) { gDisplayViewportClassInfo.uniqueId = GetFieldIDOrDie(env, gDisplayViewportClassInfo.clazz, "uniqueId", "Ljava/lang/String;"); + gDisplayViewportClassInfo.physicalPort = GetFieldIDOrDie(env, + gDisplayViewportClassInfo.clazz, "physicalPort", "Ljava/lang/Byte;"); + gDisplayViewportClassInfo.type = GetFieldIDOrDie(env, gDisplayViewportClassInfo.clazz, "type", "I"); diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 49d500754290..fa1da4bfbf3a 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -33,8 +33,6 @@ #include <iomanip> #include <string> -#include <android-base/stringprintf.h> -#include <android-base/unique_fd.h> #include <debuggerd/client.h> #include <log/log.h> #include <utils/misc.h> @@ -50,10 +48,6 @@ namespace android { -static inline UniqueFile MakeUniqueFile(const char* path, const char* mode) { - return UniqueFile(fopen(path, mode), safeFclose); -} - enum { HEAP_UNKNOWN, HEAP_DALVIK, diff --git a/core/jni/android_os_Debug.h b/core/jni/android_os_Debug.h index 81270ca994bb..c7b731bdb615 100644 --- a/core/jni/android_os_Debug.h +++ b/core/jni/android_os_Debug.h @@ -19,6 +19,8 @@ #include <memory> #include <stdio.h> +#include <android-base/stringprintf.h> +#include <android-base/unique_fd.h> namespace android { @@ -27,6 +29,11 @@ inline void safeFclose(FILE* fp) { } using UniqueFile = std::unique_ptr<FILE, decltype(&safeFclose)>; + +inline UniqueFile MakeUniqueFile(const char* path, const char* mode) { + return UniqueFile(fopen(path, mode), safeFclose); +} + UniqueFile OpenSmapsOrRollup(int pid); } // namespace android diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 4c7defbf7358..377e65c33dd0 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -1128,6 +1128,39 @@ static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid) return pss * 1024; } +static jlongArray android_os_Process_getRss(JNIEnv* env, jobject clazz, jint pid) +{ + // total, file, anon, swap + jlong rss[4] = {0, 0, 0, 0}; + std::string status_path = + android::base::StringPrintf("/proc/%d/status", pid); + UniqueFile file = MakeUniqueFile(status_path.c_str(), "re"); + + char line[256]; + while (fgets(line, sizeof(line), file.get())) { + jlong v; + if ( sscanf(line, "VmRSS: %" SCNd64 " kB", &v) == 1) { + rss[0] = v; + } else if ( sscanf(line, "RssFile: %" SCNd64 " kB", &v) == 1) { + rss[1] = v; + } else if ( sscanf(line, "RssAnon: %" SCNd64 " kB", &v) == 1) { + rss[2] = v; + } else if ( sscanf(line, "VmSwap: %" SCNd64 " kB", &v) == 1) { + rss[3] = v; + } + } + + jlongArray rssArray = env->NewLongArray(4); + if (rssArray == NULL) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return NULL; + } + + env->SetLongArrayRegion(rssArray, 0, 4, rss); + + return rssArray; +} + jintArray android_os_Process_getPidsForCommands(JNIEnv* env, jobject clazz, jobjectArray commandNames) { @@ -1253,6 +1286,7 @@ static const JNINativeMethod methods[] = { {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine}, {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime}, {"getPss", "(I)J", (void*)android_os_Process_getPss}, + {"getRss", "(I)[J", (void*)android_os_Process_getRss}, {"getPidsForCommands", "([Ljava/lang/String;)[I", (void*)android_os_Process_getPidsForCommands}, //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject}, {"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup}, diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index e89b5933fdc8..752624b0a0be 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -468,6 +468,10 @@ static jboolean android_view_RenderNode_getAllowForceDark(jlong renderNodePtr) { return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getAllowForceDark(); } +static jlong android_view_RenderNode_getUniqueId(jlong renderNodePtr) { + return reinterpret_cast<RenderNode*>(renderNodePtr)->uniqueId(); +} + // ---------------------------------------------------------------------------- // RenderProperties - Animations // ---------------------------------------------------------------------------- @@ -694,6 +698,7 @@ static const JNINativeMethod gMethods[] = { { "nGetHeight", "(J)I", (void*) android_view_RenderNode_getHeight }, { "nSetAllowForceDark", "(JZ)Z", (void*) android_view_RenderNode_setAllowForceDark }, { "nGetAllowForceDark", "(J)Z", (void*) android_view_RenderNode_getAllowForceDark }, + { "nGetUniqueId", "(J)J", (void*) android_view_RenderNode_getUniqueId }, }; int register_android_view_RenderNode(JNIEnv* env) { diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 99f096d57dba..679a1d254cf1 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -156,7 +156,7 @@ message DisplayContentProto { optional int32 rotation = 11; optional ScreenRotationAnimationProto screen_rotation_animation = 12; optional DisplayFramesProto display_frames = 13; - optional int32 surface_size = 14; + optional int32 surface_size = 14 [deprecated=true]; optional string focused_app = 15; optional AppTransitionProto app_transition = 16; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 8c5b6f4765fb..8b66be310abc 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -620,6 +620,8 @@ <protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL" /> + <protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" /> + <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> <!-- ====================================================================== --> @@ -4204,6 +4206,22 @@ <permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS" android:protectionLevel="signature|appop" /> + <!-- @SystemApi Allows requesting the framework broadcast the + {@link Intent#ACTION_DEVICE_CUSTOMIZATION_READY} intent. + @hide --> + <permission android:name="android.permission.SEND_DEVICE_CUSTOMIZATION_READY" + android:protectionLevel="signature|privileged" /> + + <!-- @SystemApi Permission that protects the {@link Intent#ACTION_DEVICE_CUSTOMIZATION_READY} + intent. + @hide --> + <permission android:name="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY" + android:protectionLevel="signature|preinstalled" /> + <!-- @SystemApi Allows wallpaper to be rendered in ambient mode. + @hide --> + <permission android:name="android.permission.AMBIENT_WALLPAPER" + android:protectionLevel="signature|preinstalled" /> + <application android:process="system" android:persistent="true" android:hasCode="false" diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 470e1ccf36e8..918070cbf829 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -7935,7 +7935,9 @@ wallpaper. --> <attr name="showMetadataInPreview" format="boolean" /> - <!-- Wallpapers optimized and capable of drawing in ambient mode will return true. --> + <!-- Wallpapers optimized and capable of drawing in ambient mode will return true. + This feature requires the android.permission.AMBIENT_WALLPAPER permission. + @hide @SystemApi --> <attr name="supportsAmbientMode" format="boolean" /> <!-- Uri that specifies a settings Slice for this wallpaper. --> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 18d1d5dbdbe3..089c59f3a09f 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1601,6 +1601,10 @@ <attr name="request" /> <attr name="protectionLevel" /> <attr name="permissionFlags" /> + <!-- If {@code true} applications that target Q <em>must</em> specify the permission usage + attributes in their {@code uses-permission} elements or the permission will not be + granted. --> + <attr name="usageInfoRequired" format="boolean" /> </declare-styleable> <!-- The <code>permission-group</code> tag declares a logical grouping of @@ -1700,6 +1704,81 @@ requested. If it does support the feature, it will be as if the manifest didn't request it at all. --> <attr name="requiredNotFeature" format="string" /> + + <!-- Specify if the app uploads data, or derived data, guarded by this permission. + + If the permission is defined with {@link android.R.attr#usageInfoRequired} + {@code true} this <em>must</em> be specified by apps that target Android Q or the + permission will not be granted, it will be as if the manifest didn't request it at all. + --> + <attr name="dataSentOffDevice"> + <!-- The application may send data, or derived data, guarded by this permission off of the + device. --> + <enum name="yes" value="1" /> + <!-- The application may send data, or derived data, guarded by this permission off of the + device, however it will only do so when explicitly triggered by a user action. --> + <enum name="userTriggered" value="2" /> + <!-- The application does not send data, or derived data, guarded by this permission off + of the device. --> + <enum name="no" value="3" /> + </attr> + + <!-- Specify if the application or its related off-device services provide data, + or derived data, guarded by this permission to third parties outside of the developer's + organization that do not qualify as data processors. + + If the permission is defined with {@link android.R.attr#usageInfoRequired} + {@code true} this <em>must</em> be specified by apps that target Android Q or the + permission will not be granted, it will be as if the manifest didn't request it at all. + --> + <attr name="dataSharedWithThirdParty"> + <!-- The application or its services may provide data, or derived data, guarded by this + permission to third party organizations. --> + <enum name="yes" value="1" /> + <!-- The application or its services may provide data, or derived data, guarded by this + permission to third party organizations, however it will only do so when explicitly + triggered by a user action. --> + <enum name="userTriggered" value="2" /> + <!-- The application or its services does not provide data, or derived data, guarded by + this permission to third party organizations. --> + <enum name="no" value="3" /> + </attr> + + <!-- Specify if the application or its related off-device services use data, + or derived data, guarded by this permission for monetization purposes. + + For example, if the data is sold to another party or used for targeting advertisements + this must be set to {@code yes}. + + If the permission is defined with {@link android.R.attr#usageInfoRequired} + {@code true} this <em>must</em> be specified by apps that target Android Q or the + permission will not be granted, it will be as if the manifest didn't request it at all. + --> + <attr name="dataUsedForMonetization"> + <!-- The application or its services may use data, or derived data, guarded by this + permission for monetization purposes. --> + <enum name="yes" value="1" /> + <!-- The application or its services may use data, or derived data, guarded by this + permission for monetization purposes, however it will only do so when explicity + triggered by a user action. --> + <enum name="userTriggered" value="2" /> + <!-- The application or its services does not use data, or derived data, guarded by + this permission for monetization purposes. --> + <enum name="no" value="3" /> + </attr> + + <!-- Specify how long the application or its related off-device services store + data, or derived data, guarded by this permission. + + This can be one of "notRetained", "userSelected", "unlimited", or a number + representing the number of weeks the data is retained. + + If the permission is defined with {@link android.R.attr#usageInfoRequired} + {@code true} this <em>must</em> be specified by apps that target Android Q or the + permission will not be granted, it will be as if the manifest didn't request it at all. + --> + <attr name="dataRetentionTime" format="string" /> + </declare-styleable> <!-- The <code>uses-configuration</code> tag specifies diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index 64e5bc0dbc50..bbe3ff995ac3 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -190,4 +190,7 @@ <!-- A tag used to save the view added to a transition overlay --> <item type="id" name="transition_overlay_view_tag" /> + + <!-- A tag used to save the notification action object --> + <item type="id" name="notification_action_index_tag" /> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 63cac5172f8a..feefcad3f56f 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2909,6 +2909,7 @@ <public name="opticalInsetRight" /> <public name="opticalInsetBottom" /> <public name="forceDarkAllowed" /> + <!-- @hide @SystemApi --> <public name="supportsAmbientMode" /> <!-- @hide For use by platform and tools only. Developers should not specify this value. --> <public name="usesNonSdkApi" /> @@ -2922,6 +2923,11 @@ <public name="importantForContentCapture" /> <public name="supportsMultipleDisplays" /> <public name="useAppZygote" /> + <public name="usageInfoRequired" /> + <public name="dataSentOffDevice" /> + <public name="dataSharedWithThirdParty" /> + <public name="dataUsedForMonetization" /> + <public name="dataRetentionTime" /> </public-group> <public-group type="drawable" first-id="0x010800b4"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 9264f90f8901..e251e27a5496 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2683,6 +2683,7 @@ <java-symbol type="id" name="smart_reply_container" /> <java-symbol type="id" name="remote_input_tag" /> <java-symbol type="id" name="pending_intent_tag" /> + <java-symbol type="id" name="notification_action_index_tag" /> <java-symbol type="attr" name="seekBarDialogPreferenceStyle" /> <java-symbol type="string" name="ext_media_status_removed" /> diff --git a/core/tests/coretests/src/android/view/InsetsSourceTest.java b/core/tests/coretests/src/android/view/InsetsSourceTest.java new file mode 100644 index 000000000000..ed472d2a7f64 --- /dev/null +++ b/core/tests/coretests/src/android/view/InsetsSourceTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import static android.view.InsetsState.TYPE_NAVIGATION_BAR; +import static junit.framework.Assert.assertEquals; + +import android.graphics.Insets; +import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.FlakyTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@Presubmit +@FlakyTest(detail = "Promote once confirmed non-flaky") +@RunWith(AndroidJUnit4.class) +public class InsetsSourceTest { + + private InsetsSource mSource = new InsetsSource(TYPE_NAVIGATION_BAR); + + @Before + public void setUp() { + mSource.setVisible(true); + } + + @Test + public void testCalculateInsetsTop() { + mSource.setFrame(new Rect(0, 0, 500, 100)); + Insets insets = mSource.calculateInsets(new Rect(0, 0, 500, 500), + false /* ignoreVisibility */); + assertEquals(Insets.of(0, 100, 0, 0), insets); + } + + @Test + public void testCalculateInsetsBottom() { + mSource.setFrame(new Rect(0, 400, 500, 500)); + Insets insets = mSource.calculateInsets(new Rect(0, 0, 500, 500), + false /* ignoreVisibility */); + assertEquals(Insets.of(0, 0, 0, 100), insets); + } + + @Test + public void testCalculateInsetsLeft() { + mSource.setFrame(new Rect(0, 0, 100, 500)); + Insets insets = mSource.calculateInsets(new Rect(0, 0, 500, 500), + false /* ignoreVisibility */); + assertEquals(Insets.of(100, 0, 0, 0), insets); + } + + @Test + public void testCalculateInsetsRight() { + mSource.setFrame(new Rect(400, 0, 500, 500)); + Insets insets = mSource.calculateInsets(new Rect(0, 0, 500, 500), + false /* ignoreVisibility */); + assertEquals(Insets.of(0, 0, 100, 0), insets); + } + + @Test + public void testCalculateInsets_overextend() { + mSource.setFrame(new Rect(0, 0, 500, 100)); + Insets insets = mSource.calculateInsets(new Rect(100, 0, 500, 500), + false /* ignoreVisibility */); + assertEquals(Insets.of(0, 100, 0, 0), insets); + } + + @Test + public void testCalculateInsets_invisible() { + mSource.setFrame(new Rect(0, 0, 500, 100)); + mSource.setVisible(false); + Insets insets = mSource.calculateInsets(new Rect(100, 0, 500, 500), + false /* ignoreVisibility */); + assertEquals(Insets.of(0, 0, 0, 0), insets); + } + + @Test + public void testCalculateInsets_ignoreVisibility() { + mSource.setFrame(new Rect(0, 0, 500, 100)); + mSource.setVisible(false); + Insets insets = mSource.calculateInsets(new Rect(100, 0, 500, 500), + true /* ignoreVisibility */); + assertEquals(Insets.of(0, 100, 0, 0), insets); + } + + // Parcel and equals already tested via InsetsStateTest +} diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java new file mode 100644 index 000000000000..6bb9539e89bd --- /dev/null +++ b/core/tests/coretests/src/android/view/InsetsStateTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import static android.view.InsetsState.TYPE_IME; +import static android.view.InsetsState.TYPE_NAVIGATION_BAR; +import static android.view.InsetsState.TYPE_TOP_BAR; +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.graphics.Rect; +import android.os.Parcel; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.FlakyTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@Presubmit +@FlakyTest(detail = "Promote once confirmed non-flaky") +@RunWith(AndroidJUnit4.class) +public class InsetsStateTest { + + private InsetsState mState = new InsetsState(); + private InsetsState mState2 = new InsetsState(); + + @Test + public void testCalculateInsets() { + mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(TYPE_TOP_BAR).setVisible(true); + mState.getSource(TYPE_IME).setFrame(new Rect(0, 200, 100, 300)); + mState.getSource(TYPE_IME).setVisible(true); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, + DisplayCutout.NO_CUTOUT); + assertEquals(new Rect(0, 100, 0, 100), insets.getSystemWindowInsets()); + } + + @Test + public void testCalculateInsets_imeAndNav() { + mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(0, 200, 100, 300)); + mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true); + mState.getSource(TYPE_IME).setFrame(new Rect(0, 100, 100, 300)); + mState.getSource(TYPE_IME).setVisible(true); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, + DisplayCutout.NO_CUTOUT); + assertEquals(100, insets.getStableInsetBottom()); + assertEquals(new Rect(0, 0, 0, 200), insets.getSystemWindowInsets()); + } + + @Test + public void testCalculateInsets_navRightStatusTop() { + mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(TYPE_TOP_BAR).setVisible(true); + mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300)); + mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, + DisplayCutout.NO_CUTOUT); + assertEquals(new Rect(0, 100, 20, 0), insets.getSystemWindowInsets()); + } + + @Test + public void testStripForDispatch() { + mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(TYPE_TOP_BAR).setVisible(true); + mState.getSource(TYPE_IME).setFrame(new Rect(0, 200, 100, 300)); + mState.getSource(TYPE_IME).setVisible(true); + mState.removeSource(TYPE_IME); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, + DisplayCutout.NO_CUTOUT); + assertEquals(0, insets.getSystemWindowInsetBottom()); + } + + @Test + public void testEquals_differentRect() { + mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState2.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 10, 10)); + assertNotEquals(mState, mState2); + } + + @Test + public void testEquals_differentSource() { + mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState2.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); + assertNotEquals(mState, mState2); + } + + @Test + public void testEquals_sameButDifferentInsertOrder() { + mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); + mState2.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); + mState2.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); + assertEquals(mState, mState2); + } + + @Test + public void testEquals_visibility() { + mState.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(TYPE_IME).setVisible(true); + mState2.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); + assertNotEquals(mState, mState2); + } + + @Test + public void testParcelUnparcel() { + mState.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(TYPE_IME).setVisible(true); + mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100)); + Parcel p = Parcel.obtain(); + mState.writeToParcel(p, 0 /* flags */); + mState2.readFromParcel(p); + p.recycle(); + assertEquals(mState, mState2); + } +} diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java index 44561227a497..36792bbf6fb6 100644 --- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java +++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java @@ -467,6 +467,21 @@ public class RemoteViewsTest { assertArrayEquals(container.mSharedViewNames, new String[] {"e0", "e1", "e2"}); } + @Test + public void setIntTag() { + RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test); + int index = 10; + views.setIntTag( + R.id.layout, com.android.internal.R.id.notification_action_index_tag, index); + + RemoteViews recovered = parcelAndRecreate(views); + RemoteViews cloned = new RemoteViews(recovered); + View inflated = cloned.apply(mContext, mContainer); + + assertEquals( + index, inflated.getTag(com.android.internal.R.id.notification_action_index_tag)); + } + private class WidgetContainer extends AppWidgetHostView { int[] mSharedViewIds; String[] mSharedViewNames; diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 3b0dc9d9f125..135c13703131 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -64,7 +64,7 @@ public class Canvas extends BaseCanvas { public boolean isRecordingFor(Object o) { return false; } // may be null - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117521088) private Bitmap mBitmap; // optional field set by the caller diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java index de110c849338..d9da27c8b931 100644 --- a/graphics/java/android/graphics/Insets.java +++ b/graphics/java/android/graphics/Insets.java @@ -82,6 +82,17 @@ public final class Insets { } /** + * Add two Insets. + * + * @param a The first Insets to add. + * @param b The second Insets to add. + * @return a + b, i. e. all insets on every side are added together. + */ + public static @NonNull Insets add(@NonNull Insets a, @NonNull Insets b) { + return Insets.of(a.left + b.left, a.top + b.top, a.right + b.right, a.bottom + b.bottom); + } + + /** * Two Insets instances are equal iff they belong to the same class and their fields are * pairwise equal. * diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java index c4dc0adb3be0..40a32f3429dc 100644 --- a/graphics/java/android/graphics/Rect.java +++ b/graphics/java/android/graphics/Rect.java @@ -106,6 +106,20 @@ public final class Rect implements Parcelable { } /** + * @hide + */ + public Rect(@Nullable Insets r) { + if (r == null) { + left = top = right = bottom = 0; + } else { + left = r.left; + top = r.top; + right = r.right; + bottom = r.bottom; + } + } + + /** * Returns a copy of {@code r} if {@code r} is not {@code null}, or {@code null} otherwise. * * @hide @@ -418,6 +432,18 @@ public final class Rect implements Parcelable { } /** + * Insets the rectangle on all sides specified by the dimensions of {@code insets}. + * @hide + * @param insets The insets to inset the rect by. + */ + public void inset(Insets insets) { + left += insets.left; + top += insets.top; + right -= insets.right; + bottom -= insets.bottom; + } + + /** * Insets the rectangle on all sides specified by the insets. * @hide * @param left The amount to add from the rectangle's left diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index 45d7a2178b84..d6f08b92a648 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -1173,6 +1173,22 @@ public final class RenderNode { return nGetAllowForceDark(mNativeRenderNode); } + /** + * Returns the unique ID that identifies this RenderNode. This ID is unique for the + * lifetime of the process. IDs are reset on process death, and are unique only within + * the process. + * + * This ID is intended to be used with debugging tools to associate a particular + * RenderNode across different debug dumping & inspection tools. For example + * a View layout inspector should include the unique ID for any RenderNodes that it owns + * to associate the drawing content with the layout content. + * + * @return the unique ID for this RenderNode + */ + public long getUniqueId() { + return nGetUniqueId(mNativeRenderNode); + } + /////////////////////////////////////////////////////////////////////////// // Animations /////////////////////////////////////////////////////////////////////////// @@ -1479,4 +1495,7 @@ public final class RenderNode { @CriticalNative private static native boolean nGetAllowForceDark(long renderNode); + + @CriticalNative + private static native long nGetUniqueId(long renderNode); } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index caf610b8c236..5bd59d479876 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -713,11 +713,12 @@ public abstract class Drawable { } /** - * Whether this drawable requests projection. + * Whether this drawable requests projection. Indicates that the + * {@link android.graphics.RenderNode} this Drawable will draw into should be drawn immediately + * after the closest ancestor RenderNode containing a projection receiver. * - * @hide magic! + * @see android.graphics.RenderNode#setProjectBackwards(boolean) */ - @UnsupportedAppUsage public boolean isProjected() { return false; } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 4a5b61a2d6cd..5f27faed08f3 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -179,6 +179,7 @@ cc_defaults { "renderthread/CanvasContext.cpp", "renderthread/DrawFrameTask.cpp", "renderthread/EglManager.cpp", + "renderthread/ReliableSurface.cpp", "renderthread/VulkanManager.cpp", "renderthread/RenderProxy.cpp", "renderthread/RenderTask.cpp", diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d2a8f02cc6a7..4a639102192f 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -29,6 +29,7 @@ #include <SkPathOps.h> #include <algorithm> +#include <atomic> #include <sstream> #include <string> @@ -47,8 +48,14 @@ private: TreeInfo* mTreeInfo; }; +static int64_t generateId() { + static std::atomic<int64_t> sNextId{1}; + return sNextId++; +} + RenderNode::RenderNode() - : mDirtyPropertyFields(0) + : mUniqueId(generateId()) + , mDirtyPropertyFields(0) , mNeedsDisplayListSync(false) , mDisplayList(nullptr) , mStagingDisplayList(nullptr) @@ -444,5 +451,38 @@ const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const { return &mClippedOutlineCache.clippedOutline; } +using StringBuffer = FatVector<char, 128>; + +template <typename... T> +static void format(StringBuffer& buffer, const std::string_view& format, T... args) { + buffer.resize(buffer.capacity()); + while (1) { + int needed = snprintf(buffer.data(), buffer.size(), + format.data(), std::forward<T>(args)...); + if (needed < 0) { + buffer[0] = '\0'; + buffer.resize(1); + return; + } + if (needed < buffer.size()) { + buffer.resize(needed + 1); + return; + } + buffer.resize(buffer.size() * 2); + } +} + +void RenderNode::markDrawStart(SkCanvas& canvas) { + StringBuffer buffer; + format(buffer, "RenderNode(id=%d, name='%s')", uniqueId(), getName()); + canvas.drawAnnotation(SkRect::MakeWH(getWidth(), getHeight()), buffer.data(), nullptr); +} + +void RenderNode::markDrawEnd(SkCanvas& canvas) { + StringBuffer buffer; + format(buffer, "/RenderNode(id=%d, name='%s')", uniqueId(), getName()); + canvas.drawAnnotation(SkRect::MakeWH(getWidth(), getHeight()), buffer.data(), nullptr); +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index be0b46b1c45f..6060123ed759 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -213,6 +213,11 @@ public: UsageHint usageHint() const { return mUsageHint; } + int64_t uniqueId() const { return mUniqueId; } + + void markDrawStart(SkCanvas& canvas); + void markDrawEnd(SkCanvas& canvas); + private: void computeOrderingImpl(RenderNodeOp* opState, std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface, @@ -233,6 +238,7 @@ private: void incParentRefCount() { mParentCount++; } void decParentRefCount(TreeObserver& observer, TreeInfo* info = nullptr); + const int64_t mUniqueId; String8 mName; sp<VirtualLightRefBase> mUserContext; diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index ea14d11b7b3e..d80cb6d1ab70 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -115,12 +115,26 @@ void RenderNodeDrawable::onDraw(SkCanvas* canvas) { } } +class MarkDraw { +public: + explicit MarkDraw(SkCanvas& canvas, RenderNode& node) : mCanvas(canvas), mNode(node) { + if (CC_UNLIKELY(Properties::skpCaptureEnabled)) { + mNode.markDrawStart(mCanvas); + } + } + ~MarkDraw() { + if (CC_UNLIKELY(Properties::skpCaptureEnabled)) { + mNode.markDrawEnd(mCanvas); + } + } +private: + SkCanvas& mCanvas; + RenderNode& mNode; +}; + void RenderNodeDrawable::forceDraw(SkCanvas* canvas) { RenderNode* renderNode = mRenderNode.get(); - if (CC_UNLIKELY(Properties::skpCaptureEnabled)) { - SkRect dimensions = SkRect::MakeWH(renderNode->getWidth(), renderNode->getHeight()); - canvas->drawAnnotation(dimensions, renderNode->getName(), nullptr); - } + MarkDraw _marker{*canvas, *renderNode}; // We only respect the nothingToDraw check when we are composing a layer. This // ensures that we paint the layer even if it is not currently visible in the diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 142bca95e598..07979a22c988 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -155,7 +155,7 @@ void SkiaOpenGLPipeline::onStop() { } } -bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, +bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior, ColorMode colorMode) { if (mEglSurface != EGL_NO_SURFACE) { mEglManager.destroySurface(mEglSurface); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 4ab3541d447b..479910697871 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -42,7 +42,7 @@ public: bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) override; DeferredLayerUpdater* createTextureLayer() override; - bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior, + bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior, renderthread::ColorMode colorMode) override; void onStop() override; bool isSurfaceReady() override; diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index a494e490aea1..e50ad1cd8c44 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -115,7 +115,7 @@ DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() { void SkiaVulkanPipeline::onStop() {} -bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, +bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior, ColorMode colorMode) { if (mVkSurface) { mVkManager.destroySurface(mVkSurface); diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 14c0d69dba33..02874c7d2c69 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -38,7 +38,7 @@ public: bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) override; DeferredLayerUpdater* createTextureLayer() override; - bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior, + bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior, renderthread::ColorMode colorMode) override; void onStop() override; bool isSurfaceReady() override; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index f1a522ecd588..182233fb3715 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -142,7 +142,12 @@ void CanvasContext::destroy() { void CanvasContext::setSurface(sp<Surface>&& surface) { ATRACE_CALL(); - mNativeSurface = std::move(surface); + if (surface) { + mNativeSurface = new ReliableSurface{std::move(surface)}; + mNativeSurface->setDequeueTimeout(500_ms); + } else { + mNativeSurface = nullptr; + } ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB; bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode); @@ -285,6 +290,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy info.damageAccumulator = &mDamageAccumulator; info.layerUpdateQueue = &mLayerUpdateQueue; + info.out.canDrawThisFrame = true; mAnimationContext->startFrame(info.mode); mRenderPipeline->onPrepareTree(); @@ -304,7 +310,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy mIsDirty = true; - if (CC_UNLIKELY(!mNativeSurface.get())) { + if (CC_UNLIKELY(!hasSurface())) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); info.out.canDrawThisFrame = false; return; @@ -323,27 +329,6 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy // the deadline for RT animations info.out.canDrawThisFrame = false; } - /* This logic exists to try and recover from a display latch miss, which essentially - * results in the bufferqueue being double-buffered instead of triple-buffered. - * SurfaceFlinger itself now tries to handle & recover from this situation, so this - * logic should no longer be necessary. As it's occasionally triggering when - * undesired disable it. - * TODO: Remove this entirely if the results are solid. - else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 || - (latestVsync - mLastDropVsync) < 500_ms) { - // It's been several frame intervals, assume the buffer queue is fine - // or the last drop was too recent - info.out.canDrawThisFrame = true; - } else { - info.out.canDrawThisFrame = !isSwapChainStuffed(); - if (!info.out.canDrawThisFrame) { - // dropping frame - mLastDropVsync = mRenderThread.timeLord().latestVsync(); - } - } - */ - } else { - info.out.canDrawThisFrame = true; } // TODO: Do we need to abort out if the backdrop is added but not ready? Should that even @@ -354,6 +339,19 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy if (!info.out.canDrawThisFrame) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); + return; + } + + int err = mNativeSurface->reserveNext(); + if (err != OK) { + mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); + info.out.canDrawThisFrame = false; + ALOGW("reserveNext failed, error = %d", err); + if (err != TIMED_OUT) { + // A timed out surface can still recover, but assume others are permanently dead. + setSurface(nullptr); + } + return; } bool postedFrameCallback = false; diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 70be4a6d7730..9e7abf447cd6 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -25,6 +25,7 @@ #include "IRenderPipeline.h" #include "LayerUpdateQueue.h" #include "RenderNode.h" +#include "ReliableSurface.h" #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" #include "thread/Task.h" @@ -219,7 +220,7 @@ private: EGLint mLastFrameHeight = 0; RenderThread& mRenderThread; - sp<Surface> mNativeSurface; + sp<ReliableSurface> mNativeSurface; // stopped indicates the CanvasContext will reject actual redraw operations, // and defer repaint until it is un-stopped bool mStopped = false; diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 65ced6ad9316..8230dfd44f9a 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -31,6 +31,8 @@ #include <string> #include <vector> +#include <system/window.h> +#include <gui/Surface.h> #define GLES_VERSION 2 @@ -106,7 +108,7 @@ void EglManager::initialize() { LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE, "Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString()); - ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor); + ALOGV("Initialized EGL, version %d.%d", (int)major, (int)minor); initExtensions(); diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index 4972554c65cc..42e17b273bee 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -28,9 +28,9 @@ class GrContext; -namespace android { +struct ANativeWindow; -class Surface; +namespace android { namespace uirenderer { @@ -67,7 +67,7 @@ public: virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) = 0; virtual DeferredLayerUpdater* createTextureLayer() = 0; - virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0; + virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0; virtual void onStop() = 0; virtual bool isSurfaceReady() = 0; virtual bool isContextReady() = 0; diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp new file mode 100644 index 000000000000..0ab4cd29f1cd --- /dev/null +++ b/libs/hwui/renderthread/ReliableSurface.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2018 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 "ReliableSurface.h" + +#include <private/android/AHardwareBufferHelpers.h> + +namespace android::uirenderer::renderthread { + +// TODO: Make surface less protected +// This exists because perform is a varargs, and ANativeWindow has no va_list perform. +// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do +// that instead +struct SurfaceExposer : Surface { + // Make warnings happy + SurfaceExposer() = delete; + + using Surface::setBufferCount; + using Surface::setSwapInterval; + using Surface::dequeueBuffer; + using Surface::queueBuffer; + using Surface::cancelBuffer; + using Surface::lockBuffer_DEPRECATED; + using Surface::perform; +}; + +#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__) + +ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) { + LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr"); + + ANativeWindow::setSwapInterval = hook_setSwapInterval; + ANativeWindow::dequeueBuffer = hook_dequeueBuffer; + ANativeWindow::cancelBuffer = hook_cancelBuffer; + ANativeWindow::queueBuffer = hook_queueBuffer; + ANativeWindow::query = hook_query; + ANativeWindow::perform = hook_perform; + + ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; + ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; + ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; + ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; +} + +void ReliableSurface::perform(int operation, va_list args) { + std::lock_guard _lock{mMutex}; + + switch (operation) { + case NATIVE_WINDOW_SET_USAGE: + mUsage = va_arg(args, uint32_t); + break; + case NATIVE_WINDOW_SET_USAGE64: + mUsage = va_arg(args, uint64_t); + break; + case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: + /* width */ va_arg(args, uint32_t); + /* height */ va_arg(args, uint32_t); + mFormat = va_arg(args, PixelFormat); + break; + case NATIVE_WINDOW_SET_BUFFERS_FORMAT: + mFormat = va_arg(args, PixelFormat); + break; + } +} + +int ReliableSurface::reserveNext() { + { + std::lock_guard _lock{mMutex}; + if (mReservedBuffer) { + ALOGW("reserveNext called but there was already a buffer reserved?"); + return OK; + } + if (mInErrorState) { + return UNKNOWN_ERROR; + } + } + + int fenceFd = -1; + ANativeWindowBuffer* buffer = nullptr; + int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd); + + { + std::lock_guard _lock{mMutex}; + LOG_ALWAYS_FATAL_IF(mReservedBuffer, "race condition in reserveNext"); + mReservedBuffer = buffer; + mReservedFenceFd.reset(fenceFd); + if (result != OK) { + ALOGW("reserveNext failed, error %d", result); + } + } + + return result; +} + +void ReliableSurface::clearReservedBuffer() { + std::lock_guard _lock{mMutex}; + if (mReservedBuffer) { + ALOGW("Reserved buffer %p was never used", mReservedBuffer); + } + mReservedBuffer = nullptr; + mReservedFenceFd.reset(); +} + +int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) { + clearReservedBuffer(); + if (isFallbackBuffer(buffer)) { + if (fenceFd > 0) { + close(fenceFd); + } + return OK; + } + int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd); + return result; +} + +int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) { + { + std::lock_guard _lock{mMutex}; + if (mReservedBuffer) { + *buffer = mReservedBuffer; + *fenceFd = mReservedFenceFd.release(); + mReservedBuffer = nullptr; + return OK; + } + } + + int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd); + if (result != OK) { + ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result); + *buffer = acquireFallbackBuffer(); + *fenceFd = -1; + return *buffer ? OK : INVALID_OPERATION; + } + return OK; +} + +int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) { + clearReservedBuffer(); + + if (isFallbackBuffer(buffer)) { + if (fenceFd > 0) { + close(fenceFd); + } + return OK; + } + + int result = callProtected(mSurface, queueBuffer, buffer, fenceFd); + return result; +} + +bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const { + if (!mScratchBuffer || !windowBuffer) { + return false; + } + ANativeWindowBuffer* scratchBuffer = + AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get()); + return windowBuffer == scratchBuffer; +} + +ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer() { + std::lock_guard _lock{mMutex}; + mInErrorState = true; + + if (mScratchBuffer) { + return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get()); + } + + AHardwareBuffer_Desc desc; + desc.usage = mUsage; + desc.format = mFormat; + desc.width = 1; + desc.height = 1; + desc.layers = 1; + desc.rfu0 = 0; + desc.rfu1 = 0; + AHardwareBuffer* newBuffer = nullptr; + int err = AHardwareBuffer_allocate(&desc, &newBuffer); + if (err) { + // Allocate failed, that sucks + ALOGW("Failed to allocate scratch buffer, error=%d", err); + return nullptr; + } + mScratchBuffer.reset(newBuffer); + return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer); +} + +Surface* ReliableSurface::getWrapped(const ANativeWindow* window) { + return getSelf(window)->mSurface.get(); +} + +int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) { + return callProtected(getWrapped(window), setSwapInterval, interval); +} + +int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, + int* fenceFd) { + return getSelf(window)->dequeueBuffer(buffer, fenceFd); +} + +int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, + int fenceFd) { + return getSelf(window)->cancelBuffer(buffer, fenceFd); +} + +int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, + int fenceFd) { + return getSelf(window)->queueBuffer(buffer, fenceFd); +} + +int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer** buffer) { + ANativeWindowBuffer* buf; + int fenceFd = -1; + int result = window->dequeueBuffer(window, &buf, &fenceFd); + if (result != OK) { + return result; + } + sp<Fence> fence(new Fence(fenceFd)); + int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED"); + if (waitResult != OK) { + ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult); + window->cancelBuffer(window, buf, -1); + return waitResult; + } + *buffer = buf; + return result; +} + +int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + return window->cancelBuffer(window, buffer, -1); +} + +int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + // This method is a no-op in Surface as well + return OK; +} + +int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + return window->queueBuffer(window, buffer, -1); +} + +int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) { + return getWrapped(window)->query(what, value); +} + +int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) { + va_list args; + va_start(args, operation); + int result = callProtected(getWrapped(window), perform, operation, args); + va_end(args); + + switch (operation) { + case NATIVE_WINDOW_SET_BUFFERS_FORMAT: + case NATIVE_WINDOW_SET_USAGE: + case NATIVE_WINDOW_SET_USAGE64: + va_start(args, operation); + getSelf(window)->perform(operation, args); + va_end(args); + break; + default: + break; + } + + return result; +} + +}; // namespace android::uirenderer::renderthread
\ No newline at end of file diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h new file mode 100644 index 000000000000..9ae53a9798d3 --- /dev/null +++ b/libs/hwui/renderthread/ReliableSurface.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <gui/Surface.h> +#include <utils/Macros.h> +#include <utils/StrongPointer.h> + +#include <memory> + +namespace android::uirenderer::renderthread { + +class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> { + PREVENT_COPY_AND_ASSIGN(ReliableSurface); + +public: + ReliableSurface(sp<Surface>&& surface); + + void setDequeueTimeout(nsecs_t timeout) { mSurface->setDequeueTimeout(timeout); } + + int reserveNext(); + + void allocateBuffers() { mSurface->allocateBuffers(); } + + int query(int what, int* value) const { return mSurface->query(what, value); } + + nsecs_t getLastDequeueStartTime() const { return mSurface->getLastDequeueStartTime(); } + + uint64_t getNextFrameNumber() const { return mSurface->getNextFrameNumber(); } + +private: + const sp<Surface> mSurface; + + mutable std::mutex mMutex; + + uint64_t mUsage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; + PixelFormat mFormat = PIXEL_FORMAT_RGBA_8888; + std::unique_ptr<AHardwareBuffer, void (*)(AHardwareBuffer*)> mScratchBuffer{ + nullptr, AHardwareBuffer_release}; + bool mInErrorState = false; + ANativeWindowBuffer* mReservedBuffer = nullptr; + base::unique_fd mReservedFenceFd; + + bool isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const; + ANativeWindowBuffer* acquireFallbackBuffer(); + void clearReservedBuffer(); + + void perform(int operation, va_list args); + int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); + int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); + int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); + + static Surface* getWrapped(const ANativeWindow*); + + // ANativeWindow hooks + static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); + static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, + int* fenceFd); + static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); + + static int hook_perform(ANativeWindow* window, int operation, ...); + static int hook_query(const ANativeWindow* window, int what, int* value); + static int hook_setSwapInterval(ANativeWindow* window, int interval); + + static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); + static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer); + static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); + static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); +}; + +}; // namespace android::uirenderer::renderthread
\ No newline at end of file diff --git a/media/java/android/media/CallbackDataSourceDesc.java b/media/java/android/media/CallbackDataSourceDesc.java index e22203dab4bc..0e8e6ceeaa15 100644 --- a/media/java/android/media/CallbackDataSourceDesc.java +++ b/media/java/android/media/CallbackDataSourceDesc.java @@ -31,18 +31,18 @@ import android.annotation.NonNull; * */ public class CallbackDataSourceDesc extends DataSourceDesc { - private Media2DataSource mMedia2DataSource; + private DataSourceCallback mDataSourceCallback; private CallbackDataSourceDesc() { } /** - * Return the Media2DataSource of this data source. + * Return the DataSourceCallback of this data source. * It's meaningful only when {@code getType} returns {@link #TYPE_CALLBACK}. - * @return the Media2DataSource of this data source + * @return the DataSourceCallback of this data source */ - public Media2DataSource getMedia2DataSource() { - return mMedia2DataSource; + public DataSourceCallback getDataSourceCallback() { + return mDataSourceCallback; } /** @@ -60,7 +60,7 @@ public class CallbackDataSourceDesc extends DataSourceDesc { * </pre> */ public static class Builder extends BuilderBase<Builder> { - private Media2DataSource mMedia2DataSource; + private DataSourceCallback mDataSourceCallback; /** * Constructs a new Builder with the defaults. @@ -79,7 +79,7 @@ public class CallbackDataSourceDesc extends DataSourceDesc { if (dsd == null) { return; // use default } - mMedia2DataSource = dsd.mMedia2DataSource; + mDataSourceCallback = dsd.mDataSourceCallback; } /** @@ -92,21 +92,21 @@ public class CallbackDataSourceDesc extends DataSourceDesc { public @NonNull CallbackDataSourceDesc build() { CallbackDataSourceDesc dsd = new CallbackDataSourceDesc(); super.build(dsd); - dsd.mMedia2DataSource = mMedia2DataSource; + dsd.mDataSourceCallback = mDataSourceCallback; return dsd; } /** - * Sets the data source (Media2DataSource) to use. + * Sets the data source (DataSourceCallback) to use. * - * @param m2ds the Media2DataSource for the media to play + * @param dscb the DataSourceCallback for the media to play * @return the same Builder instance. - * @throws NullPointerException if m2ds is null. + * @throws NullPointerException if dscb is null. */ - public @NonNull Builder setDataSource(@NonNull Media2DataSource m2ds) { - Media2Utils.checkArgument(m2ds != null, "data source cannot be null."); - mMedia2DataSource = m2ds; + public @NonNull Builder setDataSource(@NonNull DataSourceCallback dscb) { + Media2Utils.checkArgument(dscb != null, "data source cannot be null."); + mDataSourceCallback = dscb; return this; } } diff --git a/media/java/android/media/Media2DataSource.java b/media/java/android/media/DataSourceCallback.java index 08df632a99b3..9b27baf32204 100644 --- a/media/java/android/media/Media2DataSource.java +++ b/media/java/android/media/DataSourceCallback.java @@ -27,12 +27,12 @@ import java.io.IOException; * * <p class="note">Methods of this interface may be called on multiple different * threads. There will be a thread synchronization point between each call to ensure that - * modifications to the state of your Media2DataSource are visible to future calls. This means + * modifications to the state of your DataSourceCallback are visible to future calls. This means * you don't need to do your own synchronization unless you're modifying the - * Media2DataSource from another thread while it's being used by the framework.</p> + * DataSourceCallback from another thread while it's being used by the framework.</p> * */ -public abstract class Media2DataSource implements Closeable { +public abstract class DataSourceCallback implements Closeable { /** * Called to request data from the given position. * diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java index 0f2604e3f2ce..b047f8de515d 100644 --- a/media/java/android/media/MediaPlayer2.java +++ b/media/java/android/media/MediaPlayer2.java @@ -805,7 +805,7 @@ public class MediaPlayer2 implements AutoCloseable CallbackDataSourceDesc cbDSD = (CallbackDataSourceDesc) dsd; handleDataSource(isCurrent, srcId, - cbDSD.getMedia2DataSource(), + cbDSD.getDataSourceCallback(), cbDSD.getStartPosition(), cbDSD.getEndPosition()); } else if (dsd instanceof FileDataSourceDesc) { @@ -1007,15 +1007,15 @@ public class MediaPlayer2 implements AutoCloseable /** * @throws IllegalStateException if it is called in an invalid state - * @throws IllegalArgumentException if dataSource is not a valid Media2DataSource + * @throws IllegalArgumentException if dataSource is not a valid DataSourceCallback */ - private void handleDataSource(boolean isCurrent, long srcId, Media2DataSource dataSource, + private void handleDataSource(boolean isCurrent, long srcId, DataSourceCallback dataSource, long startPos, long endPos) { nativeHandleDataSourceCallback(isCurrent, srcId, dataSource, startPos, endPos); } private native void nativeHandleDataSourceCallback( - boolean isCurrent, long srcId, Media2DataSource dataSource, + boolean isCurrent, long srcId, DataSourceCallback dataSource, long startPos, long endPos); // return true if there is a next data source, false otherwise. diff --git a/media/java/android/media/midi/MidiOutputPort.java b/media/java/android/media/midi/MidiOutputPort.java index 511f6cd51917..5411e669f14d 100644 --- a/media/java/android/media/midi/MidiOutputPort.java +++ b/media/java/android/media/midi/MidiOutputPort.java @@ -59,6 +59,8 @@ public final class MidiOutputPort extends MidiSender implements Closeable { // read next event int count = mInputStream.read(buffer); if (count < 0) { + // This is the exit condition as read() returning <0 indicates + // that the pipe has been closed. break; // FIXME - inform receivers here? } @@ -81,10 +83,15 @@ public final class MidiOutputPort extends MidiSender implements Closeable { Log.e(TAG, "Unknown packet type " + packetType); break; } - } + } // while (true) } catch (IOException e) { // FIXME report I/O failure? - Log.e(TAG, "read failed", e); + // TODO: The comment above about the exit condition is not currently working + // as intended. The read from the closed pipe is throwing an error rather than + // returning <0, so this becomes (probably) not an error, but the exit case. + // This warrants further investigation; + // Silence the (probably) spurious error message. + // Log.e(TAG, "read failed", e); } finally { IoUtils.closeQuietly(mInputStream); } diff --git a/media/jni/Android.bp b/media/jni/Android.bp index faf4301a7245..e25e6a5e735f 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -88,7 +88,7 @@ cc_library_shared { name: "libmedia2_jni", srcs: [ - "android_media_Media2DataSource.cpp", + "android_media_DataSourceCallback.cpp", "android_media_MediaMetricsJNI.cpp", "android_media_MediaPlayer2.cpp", "android_media_SyncParams.cpp", diff --git a/media/jni/android_media_Media2DataSource.cpp b/media/jni/android_media_DataSourceCallback.cpp index b3434e9ab8ea..c91d4095a32f 100644 --- a/media/jni/android_media_Media2DataSource.cpp +++ b/media/jni/android_media_DataSourceCallback.cpp @@ -15,10 +15,10 @@ */ //#define LOG_NDEBUG 0 -#define LOG_TAG "JMedia2DataSource-JNI" +#define LOG_TAG "JDataSourceCallback-JNI" #include <utils/Log.h> -#include "android_media_Media2DataSource.h" +#include "android_media_DataSourceCallback.h" #include "log/log.h" #include "jni.h" @@ -33,14 +33,14 @@ namespace android { static const size_t kBufferSize = 64 * 1024; -JMedia2DataSource::JMedia2DataSource(JNIEnv* env, jobject source) +JDataSourceCallback::JDataSourceCallback(JNIEnv* env, jobject source) : mJavaObjStatus(OK), mSizeIsCached(false), mCachedSize(0) { - mMedia2DataSourceObj = env->NewGlobalRef(source); - CHECK(mMedia2DataSourceObj != NULL); + mDataSourceCallbackObj = env->NewGlobalRef(source); + CHECK(mDataSourceCallbackObj != NULL); - ScopedLocalRef<jclass> media2DataSourceClass(env, env->GetObjectClass(mMedia2DataSourceObj)); + ScopedLocalRef<jclass> media2DataSourceClass(env, env->GetObjectClass(mDataSourceCallbackObj)); CHECK(media2DataSourceClass.get() != NULL); mReadAtMethod = env->GetMethodID(media2DataSourceClass.get(), "readAt", "(J[BII)I"); @@ -55,17 +55,17 @@ JMedia2DataSource::JMedia2DataSource(JNIEnv* env, jobject source) CHECK(mByteArrayObj != NULL); } -JMedia2DataSource::~JMedia2DataSource() { +JDataSourceCallback::~JDataSourceCallback() { JNIEnv* env = JavaVMHelper::getJNIEnv(); - env->DeleteGlobalRef(mMedia2DataSourceObj); + env->DeleteGlobalRef(mDataSourceCallbackObj); env->DeleteGlobalRef(mByteArrayObj); } -status_t JMedia2DataSource::initCheck() const { +status_t JDataSourceCallback::initCheck() const { return OK; } -ssize_t JMedia2DataSource::readAt(off64_t offset, void *data, size_t size) { +ssize_t JDataSourceCallback::readAt(off64_t offset, void *data, size_t size) { Mutex::Autolock lock(mLock); if (mJavaObjStatus != OK) { @@ -76,7 +76,7 @@ ssize_t JMedia2DataSource::readAt(off64_t offset, void *data, size_t size) { } JNIEnv* env = JavaVMHelper::getJNIEnv(); - jint numread = env->CallIntMethod(mMedia2DataSourceObj, mReadAtMethod, + jint numread = env->CallIntMethod(mDataSourceCallbackObj, mReadAtMethod, (jlong)offset, mByteArrayObj, (jint)0, (jint)size); if (env->ExceptionCheck()) { ALOGW("An exception occurred in readAt()"); @@ -106,7 +106,7 @@ ssize_t JMedia2DataSource::readAt(off64_t offset, void *data, size_t size) { return numread; } -status_t JMedia2DataSource::getSize(off64_t* size) { +status_t JDataSourceCallback::getSize(off64_t* size) { Mutex::Autolock lock(mLock); if (mJavaObjStatus != OK) { @@ -118,7 +118,7 @@ status_t JMedia2DataSource::getSize(off64_t* size) { } JNIEnv* env = JavaVMHelper::getJNIEnv(); - *size = env->CallLongMethod(mMedia2DataSourceObj, mGetSizeMethod); + *size = env->CallLongMethod(mDataSourceCallbackObj, mGetSizeMethod); if (env->ExceptionCheck()) { ALOGW("An exception occurred in getSize()"); jniLogException(env, ANDROID_LOG_WARN, LOG_TAG); @@ -139,20 +139,20 @@ status_t JMedia2DataSource::getSize(off64_t* size) { return OK; } -void JMedia2DataSource::close() { +void JDataSourceCallback::close() { Mutex::Autolock lock(mLock); JNIEnv* env = JavaVMHelper::getJNIEnv(); - env->CallVoidMethod(mMedia2DataSourceObj, mCloseMethod); + env->CallVoidMethod(mDataSourceCallbackObj, mCloseMethod); // The closed state is effectively the same as an error state. mJavaObjStatus = UNKNOWN_ERROR; } -String8 JMedia2DataSource::toString() { - return String8::format("JMedia2DataSource(pid %d, uid %d)", getpid(), getuid()); +String8 JDataSourceCallback::toString() { + return String8::format("JDataSourceCallback(pid %d, uid %d)", getpid(), getuid()); } -String8 JMedia2DataSource::getMIMEType() const { +String8 JDataSourceCallback::getMIMEType() const { return String8("application/octet-stream"); } diff --git a/media/jni/android_media_Media2DataSource.h b/media/jni/android_media_DataSourceCallback.h index dc085f3f90d1..5bde682754f3 100644 --- a/media/jni/android_media_Media2DataSource.h +++ b/media/jni/android_media_DataSourceCallback.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef _ANDROID_MEDIA_MEDIA2DATASOURCE_H_ -#define _ANDROID_MEDIA_MEDIA2DATASOURCE_H_ +#ifndef _ANDROID_MEDIA_DATASOURCECALLBACK_H_ +#define _ANDROID_MEDIA_DATASOURCECALLBACK_H_ #include "jni.h" @@ -26,16 +26,16 @@ namespace android { -// The native counterpart to a Java android.media.Media2DataSource. It inherits from +// The native counterpart to a Java android.media.DataSourceCallback. It inherits from // DataSource. // // If the java DataSource returns an error or throws an exception it // will be considered to be in a broken state, and the only further call this // will make is to close(). -class JMedia2DataSource : public DataSource { +class JDataSourceCallback : public DataSource { public: - JMedia2DataSource(JNIEnv *env, jobject source); - virtual ~JMedia2DataSource(); + JDataSourceCallback(JNIEnv *env, jobject source); + virtual ~JDataSourceCallback(); virtual status_t initCheck() const override; virtual ssize_t readAt(off64_t offset, void *data, size_t size) override; @@ -56,15 +56,15 @@ private: bool mSizeIsCached; off64_t mCachedSize; - jobject mMedia2DataSourceObj; + jobject mDataSourceCallbackObj; jmethodID mReadAtMethod; jmethodID mGetSizeMethod; jmethodID mCloseMethod; jbyteArray mByteArrayObj; - DISALLOW_EVIL_CONSTRUCTORS(JMedia2DataSource); + DISALLOW_EVIL_CONSTRUCTORS(JDataSourceCallback); }; } // namespace android -#endif // _ANDROID_MEDIA_MEDIA2DATASOURCE_H_ +#endif // _ANDROID_MEDIA_DATASOURCECALLBACK_H_ diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp index f7de2e78e822..456749279696 100644 --- a/media/jni/android_media_MediaPlayer2.cpp +++ b/media/jni/android_media_MediaPlayer2.cpp @@ -46,7 +46,7 @@ #include "utils/KeyedVector.h" #include "utils/String8.h" #include "android_media_BufferingParams.h" -#include "android_media_Media2DataSource.h" +#include "android_media_DataSourceCallback.h" #include "android_media_MediaMetricsJNI.h" #include "android_media_PlaybackParams.h" #include "android_media_SyncParams.h" @@ -423,7 +423,7 @@ android_media_MediaPlayer2_handleDataSourceCallback( jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } - sp<DataSource> callbackDataSource = new JMedia2DataSource(env, dataSource); + sp<DataSource> callbackDataSource = new JDataSourceCallback(env, dataSource); sp<DataSourceDesc> dsd = new DataSourceDesc(); dsd->mId = srcId; dsd->mType = DataSourceDesc::TYPE_CALLBACK; @@ -1390,7 +1390,7 @@ static const JNINativeMethod gMethods[] = { }, { "nativeHandleDataSourceCallback", - "(ZJLandroid/media/Media2DataSource;JJ)V", + "(ZJLandroid/media/DataSourceCallback;JJ)V", (void *)android_media_MediaPlayer2_handleDataSourceCallback }, {"nativePlayNextDataSource", "(J)V", (void *)android_media_MediaPlayer2_playNextDataSource}, diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index 22d0e3b7bdc9..4b212c25c89e 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -378,6 +378,14 @@ public class Assistant extends NotificationAssistantService { } @Override + public void onActionClicked(String key, Notification.Action action, int source) { + if (DEBUG) { + Log.d(TAG, "onActionClicked() called with: key = [" + key + "], action = [" + action.title + + "], source = [" + source + "]"); + } + } + + @Override public void onListenerConnected() { if (DEBUG) Log.i(TAG, "CONNECTED"); try { diff --git a/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml index 06782633a4de..789d185b8b42 100644 --- a/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml +++ b/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml @@ -72,7 +72,6 @@ </LinearLayout> <LinearLayout - android:id="@+id/entity_header_links" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_centerVertical="true" @@ -85,6 +84,7 @@ android:layout_width="wrap_content" android:layout_weight="1" android:layout_height="0dp" + android:visibility="gone" android:minWidth="24dp" android:src="@null" android:tint="?android:attr/colorAccent"/> @@ -95,6 +95,7 @@ android:layout_width="wrap_content" android:layout_weight="1" android:layout_height="0dp" + android:visibility="gone" android:minWidth="24dp" android:src="@null" android:tint="?android:attr/colorAccent"/> diff --git a/packages/SettingsLib/tests/robotests/Android.mk b/packages/SettingsLib/tests/robotests/Android.mk index d15a3ef2946d..cfa067f13680 100644 --- a/packages/SettingsLib/tests/robotests/Android.mk +++ b/packages/SettingsLib/tests/robotests/Android.mk @@ -32,12 +32,13 @@ include frameworks/base/packages/SettingsLib/common.mk include $(BUILD_PACKAGE) -############################################# -# SettingsLib Robolectric test target. # -############################################# +############################################################ +# SettingsLib Robolectric test target. # +############################################################ include $(CLEAR_VARS) LOCAL_MODULE := SettingsLibRoboTests +LOCAL_MODULE_CLASS := JAVA_LIBRARIES LOCAL_SRC_FILES := $(call all-java-files-under, src) @@ -53,6 +54,9 @@ LOCAL_INSTRUMENTATION_FOR := SettingsLibShell LOCAL_MODULE_TAGS := optional +# Generate test_config.properties +include external/robolectric-shadows/gen_test_config.mk + include $(BUILD_STATIC_JAVA_LIBRARY) ############################################################# diff --git a/packages/SettingsLib/tests/robotests/config/robolectric.properties b/packages/SettingsLib/tests/robotests/config/robolectric.properties index 6b5b8e59472b..fab7251d020b 100644 --- a/packages/SettingsLib/tests/robotests/config/robolectric.properties +++ b/packages/SettingsLib/tests/robotests/config/robolectric.properties @@ -1,5 +1 @@ -manifest=frameworks/base/packages/SettingsLib/tests/robotests/AndroidManifest.xml sdk=NEWEST_SDK - -shadows=\ - com.android.settingslib.testutils.shadow.ShadowXmlUtils
\ No newline at end of file diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceComaptTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceComaptTest.java index 9ba996752f49..3a4e2e403ee0 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceComaptTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceComaptTest.java @@ -30,10 +30,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class CustomEditTextPreferenceComaptTest { @Mock @@ -70,7 +71,7 @@ public class CustomEditTextPreferenceComaptTest { } private static class TestPreference extends CustomEditTextPreferenceCompat { - public TestPreference(Context context) { + private TestPreference(Context context) { super(context); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java index 9d7f59a78fa5..e94a06ce7f6d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java @@ -30,10 +30,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class CustomEditTextPreferenceTest { @Mock @@ -70,7 +71,7 @@ public class CustomEditTextPreferenceTest { } private static class TestPreference extends CustomEditTextPreference { - public TestPreference(Context context) { + private TestPreference(Context context) { super(context); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java index 19a916cf85da..4e8af7350f8a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java @@ -24,9 +24,10 @@ import android.system.StructUtsname; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class DeviceInfoUtilsTest { private Context mContext; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java index 36b70dfe2297..4d76331d8da7 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java @@ -18,12 +18,13 @@ package com.android.settingslib; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.R; import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -36,20 +37,19 @@ import android.content.res.TypedArray; import android.provider.Settings; import android.view.MenuItem; -import android.R; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; /** * Tests for {@link HelpUtils}. */ -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class HelpUtilsTest { private static final String TEST_HELP_URL = "intent:#Intent;action=com.android.test;end"; private static final String PACKAGE_NAME_KEY = "package-name-key"; @@ -83,8 +83,6 @@ public class HelpUtilsTest { when(mContext.getResources().getString(R.string.config_feedbackIntentNameKey)) .thenReturn(FEEDBACK_INTENT_NAME_KEY); when(mActivity.getPackageManager()).thenReturn(mPackageManager); - - } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java index 88ac8ce5fae5..2b5a4e069001 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java @@ -25,8 +25,8 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; @@ -44,11 +44,12 @@ import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import java.util.Arrays; import java.util.Collections; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class RestrictedLockUtilsTest { @Mock @@ -178,8 +179,7 @@ public class RestrictedLockUtilsTest { public void checkIfKeyguardFeaturesAreDisabled_doesMatchAllowedFeature_unifiedManagedProfile() { UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1}); UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2}); - when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] { - userInfo, profileInfo})); + when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(userInfo, profileInfo)); when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId)) .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE); @@ -207,8 +207,7 @@ public class RestrictedLockUtilsTest { public void checkIfKeyguardFeaturesAreDisabled_notMatchOtherFeatures_unifiedManagedProfile() { UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1}); UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2}); - when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] { - userInfo, profileInfo})); + when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(userInfo, profileInfo)); when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId)) .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE); @@ -231,8 +230,7 @@ public class RestrictedLockUtilsTest { public void checkIfKeyguardFeaturesAreDisabled_onlyMatchesProfile_separateManagedProfile() { UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1}); UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2}); - when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] { - userInfo, profileInfo})); + when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(userInfo, profileInfo)); when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId)) .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE); @@ -268,8 +266,7 @@ public class RestrictedLockUtilsTest { public void checkIfKeyguardFeaturesAreDisabled_onlyMatchesParent_profileParentPolicy() { UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1}); UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2}); - when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] { - userInfo, profileInfo})); + when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(userInfo, profileInfo)); when(mProxy.getParentProfileInstance(any(DevicePolicyManager.class), any()) .getKeyguardDisabledFeatures(mAdmin2, mProfileId)) diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java index 79d682d67a4a..1b10c736f266 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java @@ -16,7 +16,6 @@ package com.android.settingslib; - import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -35,8 +34,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class RestrictedPreferenceHelperTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java deleted file mode 100644 index 8757eed8b746..000000000000 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.settingslib; - -import android.annotation.NonNull; - -import org.junit.runners.model.InitializationError; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.manifest.AndroidManifest; -import org.robolectric.res.Fs; -import org.robolectric.res.ResourcePath; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.List; - -public class SettingsLibRobolectricTestRunner extends RobolectricTestRunner { - - public SettingsLibRobolectricTestRunner(Class<?> testClass) throws InitializationError { - super(testClass); - } - - /** - * We are going to create our own custom manifest so we can add multiple resource paths to it. - */ - @Override - protected AndroidManifest getAppManifest(Config config) { - try { - // Using the manifest file's relative path, we can figure out the application directory. - final URL appRoot = - new URL("file:frameworks/base/packages/SettingsLib/tests/robotests"); - final URL manifestPath = new URL(appRoot, "AndroidManifest.xml"); - final URL resDir = new URL(appRoot, "res"); - final URL assetsDir = new URL(appRoot, "assets"); - - return new AndroidManifest(Fs.fromURL(manifestPath), Fs.fromURL(resDir), - Fs.fromURL(assetsDir), "com.android.settingslib") { - @Override - public List<ResourcePath> getIncludedResourcePaths() { - final List<ResourcePath> paths = super.getIncludedResourcePaths(); - paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/AppPreference/res")); - paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/HelpUtils/res")); - paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/RestrictedLockUtils/res")); - paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/" - + "SettingsLayoutPreference/res")); - paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/res")); - paths.add(resourcePath("file:frameworks/base/core/res/res")); - paths.add(resourcePath("file:out/soong/.intermediates/prebuilts/sdk/current/androidx/androidx.appcompat_appcompat-nodeps/android_common/aar/res/")); - return paths; - } - }; - } catch (MalformedURLException e) { - throw new RuntimeException("SettingsLibRobolectricTestRunner failure", e); - } - } - - private static ResourcePath resourcePath(@NonNull String spec) { - try { - return new ResourcePath(null, Fs.fromURL(new URL(spec)), null); - } catch (MalformedURLException e) { - throw new RuntimeException("SettingsLibRobolectricTestRunner failure", e); - } - } -} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java index e70baa197123..0ca779162ef2 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java @@ -32,12 +32,13 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.List; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class TetherUtilTest { private Context mContext; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java index c0b69f2260eb..3f0ba13ce50a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java @@ -36,9 +36,10 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class TwoTargetPreferenceTest { private PreferenceViewHolder mViewHolder; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java index 08a75ab3cfd5..594d767675c8 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java @@ -49,6 +49,7 @@ import org.mockito.ArgumentMatcher; import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; @@ -58,10 +59,8 @@ import org.robolectric.shadows.ShadowSettings; import java.util.HashMap; import java.util.Map; -@RunWith(SettingsLibRobolectricTestRunner.class) -@Config(shadows = { - UtilsTest.ShadowSecure.class, - UtilsTest.ShadowLocationManager.class}) +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {UtilsTest.ShadowSecure.class, UtilsTest.ShadowLocationManager.class}) public class UtilsTest { private static final double[] TEST_PERCENTAGES = {0, 0.4, 0.5, 0.6, 49, 49.3, 49.8, 50, 100}; private static final String PERCENTAGE_0 = "0%"; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java index 152d024d0155..44fdaec49f73 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java @@ -23,14 +23,13 @@ import android.content.Context; import android.os.UserHandle; import android.provider.Settings; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class AccessibilityUtilsTest { private Context mContext; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java index b307b4730fa1..ccec175aefad 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java @@ -41,7 +41,6 @@ import android.os.Handler; import android.os.UserHandle; import android.util.IconDrawableFactory; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.Callbacks; import com.android.settingslib.applications.ApplicationsState.Session; @@ -55,6 +54,7 @@ import org.mockito.ArgumentMatchers; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; @@ -67,7 +67,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowUserManager.class, ApplicationsStateRoboTest.ShadowIconDrawableFactory.class, ApplicationsStateRoboTest.ShadowPackageManager.class}) diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java index a92a2dd8c11a..50fad70f0a0e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java @@ -18,8 +18,8 @@ package com.android.settingslib.applications; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -32,16 +32,15 @@ import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class DefaultAppInfoTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java index d8c459c07b75..f7fd25b9fb7d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java @@ -26,14 +26,13 @@ import static org.mockito.Mockito.verify; import android.content.ComponentName; import android.provider.Settings; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class ServiceListingTest { private static final String TEST_SETTING = "testSetting"; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java index 29831a89027a..c555cbec4bab 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java @@ -17,8 +17,8 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -32,7 +32,6 @@ import android.content.Context; import android.content.res.Resources; import com.android.settingslib.R; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; @@ -40,26 +39,27 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class}) public class A2dpProfileTest { @Mock - Context mContext; + private Context mContext; @Mock - CachedBluetoothDeviceManager mDeviceManager; + private CachedBluetoothDeviceManager mDeviceManager; @Mock - LocalBluetoothProfileManager mProfileManager; + private LocalBluetoothProfileManager mProfileManager; @Mock - BluetoothDevice mDevice; + private BluetoothDevice mDevice; @Mock - BluetoothA2dp mBluetoothA2dp; - BluetoothProfile.ServiceListener mServiceListener; + private BluetoothA2dp mBluetoothA2dp; + private BluetoothProfile.ServiceListener mServiceListener; - A2dpProfile mProfile; + private A2dpProfile mProfile; private ShadowBluetoothAdapter mShadowBluetoothAdapter; @Before diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java index 274fff83ea8a..976445eb8c04 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java @@ -18,18 +18,14 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.bluetooth.BluetoothA2dpSink; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothA2dpSink; import android.bluetooth.BluetoothProfile; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; @@ -37,11 +33,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class}) public class A2dpSinkProfileTest { @@ -52,8 +49,6 @@ public class A2dpSinkProfileTest { @Mock private BluetoothA2dpSink mService; @Mock - private CachedBluetoothDevice mCachedBluetoothDevice; - @Mock private BluetoothDevice mBluetoothDevice; private BluetoothProfile.ServiceListener mServiceListener; private A2dpSinkProfile mProfile; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java index c147d5e306c2..27b8dfc28448 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java @@ -29,20 +29,18 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.os.Handler; import android.os.UserHandle; import android.telephony.TelephonyManager; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class BluetoothEventManagerTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java index 07310bd5746c..0eb6de9584eb 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java @@ -21,14 +21,14 @@ import android.bluetooth.BluetoothDevice; import android.graphics.drawable.Drawable; import com.android.settingslib.R; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.graph.BluetoothDeviceLayerDrawable; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class BluetoothUtilsTest { @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java index 9c7549147217..47b12103e772 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java @@ -28,18 +28,17 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.util.Collection; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class CachedBluetoothDeviceManagerTest { private final static String DEVICE_NAME_1 = "TestName_1"; private final static String DEVICE_NAME_2 = "TestName_2"; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java index 5ceede1ccf72..4e5d38ab5799 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java @@ -31,16 +31,15 @@ import android.bluetooth.BluetoothProfile; import android.content.Context; import android.media.AudioManager; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class CachedBluetoothDeviceTest { private final static String DEVICE_NAME = "TestName"; private final static String DEVICE_ALIAS = "TestAlias"; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java index c0a1f0cda3ee..9adef8287355 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java @@ -11,7 +11,6 @@ import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfile; import android.content.Context; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; @@ -19,11 +18,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class}) public class HeadsetProfileTest { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java index cb1b12d04f83..2b5466c4161f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java @@ -29,16 +29,15 @@ import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.content.Context; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class HearingAidDeviceManagerTest { private final static long HISYNCID1 = 10; private final static long HISYNCID2 = 11; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java index 187be0bf647b..69c020dd5c08 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java @@ -18,18 +18,14 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothProfile; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; @@ -37,11 +33,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class}) public class HfpClientProfileTest { @@ -52,8 +49,6 @@ public class HfpClientProfileTest { @Mock private BluetoothHeadsetClient mService; @Mock - private CachedBluetoothDevice mCachedBluetoothDevice; - @Mock private BluetoothDevice mBluetoothDevice; private BluetoothProfile.ServiceListener mServiceListener; private HfpClientProfile mProfile; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java index c91ee22d8587..f38af70c7498 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HidDeviceProfileTest.java @@ -18,18 +18,14 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHidDevice; import android.bluetooth.BluetoothProfile; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; @@ -37,11 +33,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class}) public class HidDeviceProfileTest { @@ -52,8 +49,6 @@ public class HidDeviceProfileTest { @Mock private BluetoothHidDevice mService; @Mock - private CachedBluetoothDevice mCachedBluetoothDevice; - @Mock private BluetoothDevice mBluetoothDevice; private BluetoothProfile.ServiceListener mServiceListener; private HidDeviceProfile mProfile; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java index a3c3a54c38f0..5d5872ea2354 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java @@ -37,7 +37,6 @@ import android.content.Context; import android.content.Intent; import android.os.ParcelUuid; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; @@ -45,6 +44,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; @@ -52,7 +52,7 @@ import org.robolectric.shadow.api.Shadow; import java.util.ArrayList; import java.util.List; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class}) public class LocalBluetoothProfileManagerTest { private final static long HISYNCID = 10; @@ -270,13 +270,13 @@ public class LocalBluetoothProfileManagerTest { verify(mCachedBluetoothDevice).refresh(); } - private List<Integer> generateList(int[] profile) { - if (profile == null) { + private List<Integer> generateList(int[] profiles) { + if (profiles == null) { return null; } - final List<Integer> profileList = new ArrayList<>(profile.length); - for(int i = 0; i < profile.length; i++) { - profileList.add(profile[i]); + final List<Integer> profileList = new ArrayList<>(profiles.length); + for (int profile : profiles) { + profileList.add(profile); } return profileList; } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java index c4c48a8bce8c..6f667094a5aa 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/MapClientProfileTest.java @@ -18,18 +18,14 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothMapClient; import android.bluetooth.BluetoothProfile; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; @@ -37,11 +33,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class}) public class MapClientProfileTest { @@ -52,8 +49,6 @@ public class MapClientProfileTest { @Mock private BluetoothMapClient mService; @Mock - private CachedBluetoothDevice mCachedBluetoothDevice; - @Mock private BluetoothDevice mBluetoothDevice; private BluetoothProfile.ServiceListener mServiceListener; private MapClientProfile mProfile; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java index e4a444c836ab..b21ec9c3e52a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/PbapClientProfileTest.java @@ -18,18 +18,14 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothPbapClient; import android.bluetooth.BluetoothProfile; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; @@ -37,12 +33,13 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(SettingsLibRobolectricTestRunner.class) -@Config(shadows = {ShadowBluetoothAdapter.class}) +@RunWith(RobolectricTestRunner.class) +@Config(shadows = ShadowBluetoothAdapter.class) public class PbapClientProfileTest { @Mock @@ -52,8 +49,6 @@ public class PbapClientProfileTest { @Mock private BluetoothPbapClient mService; @Mock - private CachedBluetoothDevice mCachedBluetoothDevice; - @Mock private BluetoothDevice mBluetoothDevice; private BluetoothProfile.ServiceListener mServiceListener; private PbapClientProfile mProfile; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java index 9bb53ee6a343..ec880345f6f0 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java @@ -18,18 +18,14 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothSap; import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothSap; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; @@ -37,11 +33,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class}) public class SapProfileTest { @@ -52,8 +49,6 @@ public class SapProfileTest { @Mock private BluetoothSap mService; @Mock - private CachedBluetoothDevice mCachedBluetoothDevice; - @Mock private BluetoothDevice mBluetoothDevice; private BluetoothProfile.ServiceListener mServiceListener; private SapProfile mProfile; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java index 4d7553cd85da..28de1914838f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java @@ -24,16 +24,15 @@ import android.content.Context; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class AbstractPreferenceControllerTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java index 4ec6fb2efab1..8a0ae9190a8c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java @@ -27,7 +27,6 @@ import android.content.Context; import android.content.Intent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Before; import org.junit.Test; @@ -35,13 +34,14 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; import java.util.ArrayList; import java.util.List; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class MetricsFeatureProviderTest { @Mock private LogWriter mLogWriter; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java index 6285fcdb10b3..8f51dece64e5 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java @@ -17,8 +17,8 @@ package com.android.settingslib.core.instrumentation; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -26,16 +26,15 @@ import android.app.settings.SettingsEnums; import android.content.Context; import android.content.SharedPreferences; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class SharedPreferenceLoggerTest { private static final String TEST_TAG = "tag"; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java index b251c09ff33e..097db176a99a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java @@ -17,10 +17,10 @@ package com.android.settingslib.core.instrumentation; import static com.android.settingslib.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -35,7 +35,6 @@ import android.os.Bundle; import androidx.fragment.app.FragmentActivity; import com.android.internal.logging.nano.MetricsProto; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Before; import org.junit.Test; @@ -43,10 +42,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; import org.robolectric.android.controller.ActivityController; - -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class VisibilityLoggerMixinTest { @Mock @@ -139,7 +138,7 @@ public class VisibilityLoggerMixinTest { private final class TestInstrumentable implements Instrumentable { - public static final int TEST_METRIC = 12345; + private static final int TEST_METRIC = 12345; @Override public int getMetricsCategory() { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java index 887c1d57c870..29e37e4938a8 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java @@ -28,7 +28,6 @@ import android.widget.LinearLayout; import androidx.lifecycle.LifecycleOwner; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.events.OnAttach; import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu; import com.android.settingslib.core.lifecycle.events.OnDestroy; @@ -43,10 +42,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; import org.robolectric.android.controller.ActivityController; import org.robolectric.shadows.androidx.fragment.FragmentController; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class LifecycleTest { private LifecycleOwner mLifecycleOwner; @@ -56,7 +56,7 @@ public class LifecycleTest { final TestObserver mFragObserver; - public TestDialogFragment() { + private TestDialogFragment() { mFragObserver = new TestObserver(); mLifecycle.addObserver(mFragObserver); } @@ -236,11 +236,11 @@ public class LifecycleTest { } private static class OptionItemAccepter implements LifecycleObserver, OnOptionsItemSelected { - public boolean wasCalled = false; + private boolean mWasCalled = false; @Override public boolean onOptionsItemSelected(MenuItem menuItem) { - wasCalled = true; + mWasCalled = true; return false; } } @@ -258,14 +258,14 @@ public class LifecycleTest { fragment.onPrepareOptionsMenu(null); fragment.onOptionsItemSelected(null); - assertThat(accepter.wasCalled).isFalse(); + assertThat(accepter.mWasCalled).isFalse(); } private class OnStartObserver implements LifecycleObserver, OnStart { private final Lifecycle mLifecycle; - public OnStartObserver(Lifecycle lifecycle) { + private OnStartObserver(Lifecycle lifecycle) { mLifecycle = lifecycle; } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DeveloperOptionsPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DeveloperOptionsPreferenceControllerTest.java index 9dd93b3af390..6191a00b377c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DeveloperOptionsPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DeveloperOptionsPreferenceControllerTest.java @@ -22,16 +22,15 @@ import static org.mockito.Mockito.verify; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class DeveloperOptionsPreferenceControllerTest { private static final String TEST_KEY = "Test_pref_key"; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java index a0fa6b599b45..3475ff7d96f8 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java @@ -18,23 +18,19 @@ package com.android.settingslib.development; import static com.google.common.truth.Truth.assertThat; -import android.os.UserManager; import android.content.Context; +import android.os.UserManager; import android.provider.Settings; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - -import org.robolectric.shadows.ShadowUserManager; -import org.robolectric.shadow.api.Shadow; - -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowUserManager; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class DevelopmentSettingsEnablerTest { private Context mContext; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java index d7b23b0ef636..e84a25c0ba4e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java @@ -32,17 +32,16 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.ShadowApplication; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class EnableAdbPreferenceControllerTest { @Mock(answer = RETURNS_DEEP_STUBS) private PreferenceScreen mScreen; @@ -150,7 +149,7 @@ public class EnableAdbPreferenceControllerTest { } class ConcreteEnableAdbPreferenceController extends AbstractEnableAdbPreferenceController { - public ConcreteEnableAdbPreferenceController(Context context) { + private ConcreteEnableAdbPreferenceController(Context context) { super(context); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java index 2f78899ff92d..146be23f1683 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java @@ -45,16 +45,16 @@ import androidx.preference.ListPreference; import androidx.preference.PreferenceScreen; import com.android.settingslib.R; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class LogdSizePreferenceControllerTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java index ed128e098c6f..d5afb4b08a93 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java @@ -29,7 +29,6 @@ import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; @@ -37,9 +36,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class LogpersistPreferenceControllerTest { private LifecycleOwner mLifecycleOwner; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropPokerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropPokerTest.java index 40db478f2dc7..d1212fcad864 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropPokerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropPokerTest.java @@ -27,16 +27,15 @@ import static org.mockito.Mockito.verify; import android.os.IBinder; import android.os.Parcel; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import org.robolectric.RobolectricTestRunner; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class SystemPropPokerTest { @Spy diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java index 234b4d5ac604..16de5f804b68 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java @@ -26,7 +26,6 @@ import android.content.Context; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; @@ -34,11 +33,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class BluetoothAddressPreferenceControllerTest { @Mock private Context mContext; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java index aee956cf5518..4444e6369b67 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java @@ -30,7 +30,6 @@ import android.content.Context; import android.content.IntentFilter; import android.os.Handler; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; @@ -39,8 +38,9 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class ConnectivityPreferenceControllerTest { @Mock private Context mContext; @@ -91,8 +91,7 @@ public class ConnectivityPreferenceControllerTest { private static class ConcreteConnectivityPreferenceController extends AbstractConnectivityPreferenceController { - - public ConcreteConnectivityPreferenceController(Context context, + private ConcreteConnectivityPreferenceController(Context context, Lifecycle lifecycle) { super(context, lifecycle); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java index 2b490ee63856..bd223bd778bb 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java @@ -25,12 +25,10 @@ import static org.mockito.Mockito.mock; import android.content.Context; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionManager; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; @@ -38,11 +36,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.shadows.ShadowSubscriptionManager; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class ImsStatusPreferenceControllerTest { @Mock private Context mContext; @@ -61,8 +58,9 @@ public class ImsStatusPreferenceControllerTest { } @Test - @Config(shadows = ShadowSubscriptionManager.class) public void testIsAvailable() { + ShadowSubscriptionManager.setDefaultDataSubscriptionId(1234); + CarrierConfigManager carrierConfigManager = mock(CarrierConfigManager.class); doReturn(carrierConfigManager).when(mContext).getSystemService(CarrierConfigManager.class); @@ -92,18 +90,10 @@ public class ImsStatusPreferenceControllerTest { .that(imsStatusPreferenceController.isAvailable()).isFalse(); } - @Implements(SubscriptionManager.class) - public static class ShadowSubscriptionManager { - @Implementation - public static int getDefaultDataSubscriptionId() { - return 1234; - } - } - private static class ConcreteImsStatusPreferenceController extends AbstractImsStatusPreferenceController { - public ConcreteImsStatusPreferenceController(Context context, + private ConcreteImsStatusPreferenceController(Context context, Lifecycle lifecycle) { super(context, lifecycle); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java index 1d957c3b5e5b..76a26d917969 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java @@ -27,7 +27,6 @@ import android.net.wifi.WifiManager; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; @@ -35,11 +34,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import java.util.Arrays; import java.util.List; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class IpAddressPreferenceControllerTest { @Mock private Context mContext; @@ -75,8 +75,7 @@ public class IpAddressPreferenceControllerTest { private static class ConcreteIpAddressPreferenceController extends AbstractIpAddressPreferenceController { - public ConcreteIpAddressPreferenceController(Context context, - Lifecycle lifecycle) { + private ConcreteIpAddressPreferenceController(Context context, Lifecycle lifecycle) { super(context, lifecycle); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java index dc77400e2547..5b71bdd3d760 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java @@ -25,16 +25,15 @@ import android.content.Context; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class SerialNumberPreferenceControllerTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java index eb77cb6271e9..5252c6c82754 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java @@ -24,17 +24,16 @@ import android.net.ConnectivityManager; import android.os.UserManager; import android.util.SparseBooleanArray; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {SimStatusImeiInfoPreferenceControllerTest.ShadowUserManager.class, SimStatusImeiInfoPreferenceControllerTest.ShadowConnectivityManager.class}) public class SimStatusImeiInfoPreferenceControllerTest { @@ -106,7 +105,7 @@ public class SimStatusImeiInfoPreferenceControllerTest { private final SparseBooleanArray mSupportedNetworkTypes = new SparseBooleanArray(); - public void setNetworkSupported(int networkType, boolean supported) { + private void setNetworkSupported(int networkType, boolean supported) { mSupportedNetworkTypes.put(networkType, supported); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java index 2e0348daaa51..f09879b95221 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java @@ -28,7 +28,6 @@ import android.text.format.DateUtils; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; @@ -36,9 +35,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowLooper; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class UptimePreferenceControllerTest { @Mock private Context mContext; @@ -92,7 +92,7 @@ public class UptimePreferenceControllerTest { private static class ConcreteUptimePreferenceController extends AbstractUptimePreferenceController { - public ConcreteUptimePreferenceController(Context context, + private ConcreteUptimePreferenceController(Context context, Lifecycle lifecycle) { super(context, lifecycle); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java index 359ea7791922..74e5bf5a8034 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java @@ -33,7 +33,6 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settingslib.R; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; @@ -41,13 +40,14 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.util.Arrays; import java.util.List; @SuppressLint("HardwareIds") -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class WifiMacAddressPreferenceControllerTest { @Mock private Lifecycle mLifecycle; @@ -197,7 +197,7 @@ public class WifiMacAddressPreferenceControllerTest { private static class ConcreteWifiMacAddressPreferenceController extends AbstractWifiMacAddressPreferenceController { - public ConcreteWifiMacAddressPreferenceController(Context context, + private ConcreteWifiMacAddressPreferenceController(Context context, Lifecycle lifecycle) { super(context, lifecycle); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java index ca621ca66829..c0924d9a8b35 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java @@ -20,12 +20,11 @@ import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX; import static com.google.common.truth.Truth.assertThat; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class BrightnessUtilsTest { private static final int MIN = 1; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java index 59a3dd61475c..605c861fa07f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java @@ -20,14 +20,13 @@ import static com.google.common.truth.Truth.assertThat; import android.util.ArraySet; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import java.util.Set; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class CategoryKeyTest { @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java index 40e7386cf5af..b77670bd01e5 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java @@ -13,15 +13,14 @@ import android.content.pm.ActivityInfo; import android.os.Bundle; import com.android.settingslib.R; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; - -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class TileTest { private ActivityInfo mActivityInfo; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java index 362ae4c84cbf..bbb4249317f7 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java @@ -54,7 +54,6 @@ import android.util.ArrayMap; import android.util.Pair; import com.android.settingslib.R; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Before; import org.junit.Test; @@ -62,12 +61,13 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import java.util.ArrayList; import java.util.List; import java.util.Map; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class TileUtilsTest { private Context mContext; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java index d0b6dab43281..2988905b44a6 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java @@ -33,28 +33,26 @@ import android.os.PowerManager; import android.provider.Settings.Global; import android.provider.Settings.Secure; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; - -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class BatterySaverUtilsTest { - final int BATTERY_SAVER_THRESHOLD_1 = 15; - final int BATTERY_SAVER_THRESHOLD_2 = 20; + private static final int BATTERY_SAVER_THRESHOLD_1 = 15; + private static final int BATTERY_SAVER_THRESHOLD_2 = 20; @Mock - Context mMockContext; + private Context mMockContext; @Mock - ContentResolver mMockResolver; + private ContentResolver mMockResolver; @Mock - PowerManager mMockPowerManager; + private PowerManager mMockPowerManager; @Before public void setUp() throws Exception { @@ -66,11 +64,11 @@ public class BatterySaverUtilsTest { } @Test - public void testSetPowerSaveMode_enable_firstCall_needWarning() throws Exception { + public void testSetPowerSaveMode_enable_firstCall_needWarning() { Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null"); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); - assertEquals(false, BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isFalse(); verify(mMockContext, times(1)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(0)).setPowerSaveMode(anyBoolean()); @@ -83,11 +81,11 @@ public class BatterySaverUtilsTest { } @Test - public void testSetPowerSaveMode_enable_secondCall_needWarning() throws Exception { + public void testSetPowerSaveMode_enable_secondCall_needWarning() { Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); // Already acked. Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); - assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isTrue(); verify(mMockContext, times(0)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true)); @@ -97,11 +95,11 @@ public class BatterySaverUtilsTest { } @Test - public void testSetPowerSaveMode_enable_thridCall_needWarning() throws Exception { + public void testSetPowerSaveMode_enable_thridCall_needWarning() { Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); // Already acked. Secure.putInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 1); - assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isTrue(); verify(mMockContext, times(0)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true)); @@ -111,11 +109,11 @@ public class BatterySaverUtilsTest { } @Test - public void testSetPowerSaveMode_enable_firstCall_noWarning() throws Exception { + public void testSetPowerSaveMode_enable_firstCall_noWarning() { Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null"); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); - assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, true, false)); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, false)).isTrue(); verify(mMockContext, times(0)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true)); @@ -125,12 +123,12 @@ public class BatterySaverUtilsTest { } @Test - public void testSetPowerSaveMode_disable_firstCall_noWarning() throws Exception { + public void testSetPowerSaveMode_disable_firstCall_noWarning() { Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null"); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); // When disabling, needFirstTimeWarning doesn't matter. - assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, false, false)); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, false, false)).isTrue(); verify(mMockContext, times(0)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(false)); @@ -141,12 +139,12 @@ public class BatterySaverUtilsTest { } @Test - public void testSetPowerSaveMode_disable_firstCall_needWarning() throws Exception { + public void testSetPowerSaveMode_disable_firstCall_needWarning() { Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null"); Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null"); // When disabling, needFirstTimeWarning doesn't matter. - assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, false, true)); + assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, false, true)).isTrue(); verify(mMockContext, times(0)).sendBroadcast(any(Intent.class)); verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(false)); @@ -157,7 +155,7 @@ public class BatterySaverUtilsTest { } @Test - public void testEnsureAutoBatterysaver_setNewPositiveValue_doNotOverwrite() throws Exception { + public void testEnsureAutoBatterysaver_setNewPositiveValue_doNotOverwrite() { Global.putInt(mMockResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0); BatterySaverUtils.ensureAutoBatterySaver(mMockContext, BATTERY_SAVER_THRESHOLD_1); @@ -172,7 +170,7 @@ public class BatterySaverUtilsTest { } @Test - public void testSetAutoBatterySaverTriggerLevel_setSuppressSuggestion() throws Exception { + public void testSetAutoBatterySaverTriggerLevel_setSuppressSuggestion() { Global.putString(mMockResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, "null"); Secure.putString(mMockResolver, Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, "null"); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java index 9b1fe5f6029d..bbf807d29402 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java @@ -31,7 +31,6 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.IDeviceIdleController; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager; import com.android.settingslib.testutils.shadow.ShadowSmsApplication; @@ -40,12 +39,13 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowPackageManager; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowDefaultDialerManager.class, ShadowSmsApplication.class}) public class PowerWhitelistBackendTest { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java index 49dde0e6fcfa..35743c219129 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java @@ -16,8 +16,8 @@ package com.android.settingslib.graph; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -25,17 +25,16 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class BatteryMeterDrawableBaseTest { private static final int CRITICAL_LEVEL = 5; private static final int PADDING = 5; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java index 5dbb5caf60eb..1b350cc83285 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java @@ -22,14 +22,14 @@ import android.content.Context; import android.graphics.drawable.VectorDrawable; import com.android.settingslib.R; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class BluetoothDeviceLayerDrawableTest { private static final int RES_ID = R.drawable.ic_bt_cellphone; private static final int BATTERY_LEVEL = 15; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java index fa64afec0461..b930aa6ee1bd 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java @@ -25,26 +25,21 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class InputMethodAndSubtypeUtilCompatTest { private static final HashSet<String> EMPTY_STRING_SET = new HashSet<>(); private static HashSet<String> asHashSet(String... strings) { - HashSet<String> hashSet = new HashSet<>(); - for (String s : strings) { - hashSet.add(s); - } - return hashSet; + return new HashSet<>(Arrays.asList(strings)); } @Test @@ -105,7 +100,6 @@ public class InputMethodAndSubtypeUtilCompatTest { "ime0;subtype0;subtype1:ime1;subtype1;subtype2")) .containsExactly("ime0", asHashSet("subtype0", "subtype1"), "ime1", asHashSet("subtype1", "subtype2")); - } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java index 03ab261aa75a..84606b4e4502 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java @@ -25,26 +25,21 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class InputMethodAndSubtypeUtilTest { private static final HashSet<String> EMPTY_STRING_SET = new HashSet<>(); private static HashSet<String> asHashSet(String... strings) { - HashSet<String> hashSet = new HashSet<>(); - for (String s : strings) { - hashSet.add(s); - } - return hashSet; + return new HashSet<>(Arrays.asList(strings)); } @Test @@ -103,7 +98,6 @@ public class InputMethodAndSubtypeUtilTest { "ime0;subtype0;subtype1:ime1;subtype1;subtype2")) .containsExactly("ime0", asHashSet("subtype0", "subtype1"), "ime1", asHashSet("subtype1", "subtype2")); - } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java index b00476b24921..4b5e9097b3fe 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java @@ -18,10 +18,9 @@ package com.android.settingslib.license; import static com.google.common.truth.Truth.assertThat; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayInputStream; @@ -32,7 +31,7 @@ import java.io.StringWriter; import java.util.HashMap; import java.util.Map; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class LicenseHtmlGeneratorFromXmlTest { private static final String VALILD_XML_STRING = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" @@ -92,8 +91,8 @@ public class LicenseHtmlGeneratorFromXmlTest { @Test public void testParseValidXmlStream() throws XmlPullParserException, IOException { - Map<String, String> fileNameToContentIdMap = new HashMap<String, String>(); - Map<String, String> contentIdToFileContentMap = new HashMap<String, String>(); + Map<String, String> fileNameToContentIdMap = new HashMap<>(); + Map<String, String> contentIdToFileContentMap = new HashMap<>(); LicenseHtmlGeneratorFromXml.parse( new InputStreamReader(new ByteArrayInputStream(VALILD_XML_STRING.getBytes())), @@ -107,8 +106,8 @@ public class LicenseHtmlGeneratorFromXmlTest { @Test(expected = XmlPullParserException.class) public void testParseInvalidXmlStream() throws XmlPullParserException, IOException { - Map<String, String> fileNameToContentIdMap = new HashMap<String, String>(); - Map<String, String> contentIdToFileContentMap = new HashMap<String, String>(); + Map<String, String> fileNameToContentIdMap = new HashMap<>(); + Map<String, String> contentIdToFileContentMap = new HashMap<>(); LicenseHtmlGeneratorFromXml.parse( new InputStreamReader(new ByteArrayInputStream(INVALILD_XML_STRING.getBytes())), @@ -117,8 +116,8 @@ public class LicenseHtmlGeneratorFromXmlTest { @Test public void testGenerateHtml() { - Map<String, String> fileNameToContentIdMap = new HashMap<String, String>(); - Map<String, String> contentIdToFileContentMap = new HashMap<String, String>(); + Map<String, String> fileNameToContentIdMap = new HashMap<>(); + Map<String, String> contentIdToFileContentMap = new HashMap<>(); fileNameToContentIdMap.put("/file0", "0"); fileNameToContentIdMap.put("/file1", "0"); @@ -132,8 +131,8 @@ public class LicenseHtmlGeneratorFromXmlTest { @Test public void testGenerateHtmlWithCustomHeading() { - Map<String, String> fileNameToContentIdMap = new HashMap<String, String>(); - Map<String, String> contentIdToFileContentMap = new HashMap<String, String>(); + Map<String, String> fileNameToContentIdMap = new HashMap<>(); + Map<String, String> contentIdToFileContentMap = new HashMap<>(); fileNameToContentIdMap.put("/file0", "0"); fileNameToContentIdMap.put("/file1", "0"); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java index c90de5fe621e..e82bc0678108 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java @@ -20,14 +20,13 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -37,7 +36,7 @@ import java.io.File; import java.util.ArrayList; import java.util.List; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = LicenseHtmlLoaderCompatTest.ShadowLicenseHtmlLoaderCompat.class) public class LicenseHtmlLoaderCompatTest { @@ -58,7 +57,7 @@ public class LicenseHtmlLoaderCompatTest { @Test public void testLoadInBackground() { - ArrayList<File> xmlFiles = new ArrayList(); + ArrayList<File> xmlFiles = new ArrayList<>(); xmlFiles.add(new File("test.xml")); File cachedHtmlFile = new File("test.html"); @@ -69,7 +68,7 @@ public class LicenseHtmlLoaderCompatTest { @Test public void testLoadInBackgroundWithNoVaildXmlFiles() { - ArrayList<File> xmlFiles = new ArrayList(); + ArrayList<File> xmlFiles = new ArrayList<>(); File cachedHtmlFile = new File("test.html"); setupFakeData(xmlFiles, cachedHtmlFile, true, true); @@ -79,7 +78,7 @@ public class LicenseHtmlLoaderCompatTest { @Test public void testLoadInBackgroundWithNonOutdatedCachedHtmlFile() { - ArrayList<File> xmlFiles = new ArrayList(); + ArrayList<File> xmlFiles = new ArrayList<>(); xmlFiles.add(new File("test.xml")); File cachedHtmlFile = new File("test.html"); @@ -90,7 +89,7 @@ public class LicenseHtmlLoaderCompatTest { @Test public void testLoadInBackgroundWithGenerateHtmlFileFailed() { - ArrayList<File> xmlFiles = new ArrayList(); + ArrayList<File> xmlFiles = new ArrayList<>(); xmlFiles.add(new File("test.xml")); File cachedHtmlFile = new File("test.html"); @@ -112,10 +111,10 @@ public class LicenseHtmlLoaderCompatTest { @Implements(LicenseHtmlLoaderCompat.class) public static class ShadowLicenseHtmlLoaderCompat { - public static List<File> sValidXmlFiles; - public static File sCachedHtmlFile; - public static boolean sIsCachedHtmlFileOutdated; - public static boolean sGenerateHtmlFileSucceeded; + private static List<File> sValidXmlFiles; + private static File sCachedHtmlFile; + private static boolean sIsCachedHtmlFileOutdated; + private static boolean sGenerateHtmlFileSucceeded; @Resetter public static void reset() { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/InjectedSettingTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/InjectedSettingTest.java index c29481f633a4..8c2e8992fd6a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/InjectedSettingTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/InjectedSettingTest.java @@ -18,12 +18,11 @@ package com.android.settingslib.location; import static com.google.common.truth.Truth.assertThat; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public final class InjectedSettingTest { private static final String TEST_STRING = "test"; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java index 9c168f7b1a45..08d536720029 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java @@ -2,7 +2,7 @@ package com.android.settingslib.location; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.isA; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.when; import android.app.AppOpsManager; @@ -17,20 +17,19 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class RecentLocationAppsTest { private static final int TEST_UID = 1234; @@ -56,8 +55,6 @@ public class RecentLocationAppsTest { private int mTestUserId; private RecentLocationApps mRecentLocationApps; - - @Before public void setUp() throws NameNotFoundException { MockitoAnnotations.initMocks(this); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java index 50044f2cc0ea..72ed5e123add 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java @@ -42,16 +42,15 @@ import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.FeatureFlagUtils; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class DataUsageControllerTest { private static final String SUB_ID = "Test Subscriber"; @@ -85,7 +84,6 @@ public class DataUsageControllerTest { doReturn(null).when(mController).getSession(); assertThat(mController.getHistoricalUsageLevel(null /* template */)).isEqualTo(-1L); - } @Test @@ -95,7 +93,6 @@ public class DataUsageControllerTest { assertThat(mController.getHistoricalUsageLevel(NetworkTemplate.buildTemplateWifiWildcard())) .isEqualTo(0L); - } @Test @@ -113,7 +110,6 @@ public class DataUsageControllerTest { assertThat(mController.getHistoricalUsageLevel(NetworkTemplate.buildTemplateWifiWildcard())) .isEqualTo(receivedBytes + transmittedBytes); - } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java index 0a036317910e..011f234ab4f1 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java @@ -27,15 +27,14 @@ import android.net.NetworkPolicyManager; import android.os.RemoteException; import android.text.format.DateUtils; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class NetworkCycleChartDataLoaderTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java index 2314f272c8ea..d9159631e8a9 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java @@ -19,7 +19,7 @@ package com.android.settingslib.net; import static android.app.usage.NetworkStats.Bucket.STATE_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -33,15 +33,14 @@ import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.text.format.DateUtils; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class NetworkCycleDataForUidLoaderTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java index 9d60a97f8584..2d8ea125a97e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java @@ -16,8 +16,8 @@ package com.android.settingslib.net; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.nullable; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -37,20 +37,19 @@ import android.os.RemoteException; import android.text.format.DateUtils; import android.util.Range; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.util.ReflectionHelpers; import java.time.ZonedDateTime; import java.util.Iterator; import java.util.List; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class NetworkCycleDataLoaderTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java index 89c319a7e483..59d56747ec5d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java @@ -16,11 +16,10 @@ package com.android.settingslib.notification; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; - +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; @@ -38,16 +37,15 @@ import android.net.Uri; import android.service.notification.Condition; import android.view.LayoutInflater; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class EnableZenModeDialogTest { private EnableZenModeDialog mController; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java index 81476564f9b9..437c0d4f4469 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java @@ -25,27 +25,23 @@ import static org.mockito.Mockito.spy; import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; -import android.service.notification.Condition; import android.view.LayoutInflater; import android.view.View; import androidx.appcompat.app.AlertDialog; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class ZenDurationDialogTest { private ZenDurationDialog mController; private Context mContext; private LayoutInflater mLayoutInflater; - private Condition mCountdownCondition; - private Condition mAlarmCondition; private ContentResolver mContentResolver; private AlertDialog.Builder mBuilder; @@ -102,7 +98,6 @@ public class ZenDurationDialogTest { ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.isChecked()); } - @Test public void testChooseAlwaysPromptSetting() { Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_DURATION, diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java index 449451a63e2d..ffaa7443eb46 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java @@ -31,7 +31,6 @@ import android.content.Context; import androidx.lifecycle.LifecycleOwner; import androidx.loader.app.LoaderManager; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.After; @@ -40,10 +39,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = ShadowSuggestionController.class) public class SuggestionControllerMixinCompatTest { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java index aac582f9b3ac..4dc80f442649 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java @@ -31,7 +31,6 @@ import android.content.Context; import androidx.lifecycle.LifecycleOwner; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.After; @@ -40,10 +39,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = ShadowSuggestionController.class) public class SuggestionControllerMixinTest { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java index f4afdb11ff95..3e91641a69ae 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java @@ -26,19 +26,19 @@ import org.robolectric.annotation.Resetter; @Implements(DefaultDialerManager.class) public class ShadowDefaultDialerManager { - private static String sDefaultDailer; + private static String sDefaultDialer; @Resetter public void reset() { - sDefaultDailer = null; + sDefaultDialer = null; } @Implementation public static String getDefaultDialerApplication(Context context) { - return sDefaultDailer; + return sDefaultDialer; } public static void setDefaultDialerApplication(String dialer) { - sDefaultDailer = dialer; + sDefaultDialer = dialer; } }
\ No newline at end of file diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java index 4705cd2b183b..9a169d2663de 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java @@ -27,7 +27,6 @@ import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowActivityManager; import org.junit.After; @@ -36,6 +35,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; @@ -45,7 +45,7 @@ import org.robolectric.annotation.Resetter; import java.util.ArrayList; import java.util.List; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(shadows = { ShadowActivityManager.class, UserManagerHelperRoboTest.ShadowUserHandle.class}) public class UserManagerHelperRoboTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/IconCacheTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/IconCacheTest.java index 645dfa127626..026ad47f99a2 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/IconCacheTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/IconCacheTest.java @@ -30,14 +30,13 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class IconCacheTest { private Icon mIcon; private Context mContext; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java index 6a9579b770ce..7ef31df6ab26 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java @@ -22,31 +22,30 @@ import static org.mockito.Mockito.spy; import android.content.Context; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.time.Duration; import java.util.regex.Pattern; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class PowerUtilTest { - public static final String TEST_BATTERY_LEVEL_10 = "10%"; - public static final long SEVENTEEN_MIN_MILLIS = Duration.ofMinutes(17).toMillis(); - public static final long FIVE_MINUTES_MILLIS = Duration.ofMinutes(5).toMillis(); - public static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis(); - public static final long THREE_DAYS_MILLIS = Duration.ofDays(3).toMillis(); - public static final long THIRTY_HOURS_MILLIS = Duration.ofHours(30).toMillis(); - public static final String NORMAL_CASE_EXPECTED_PREFIX = "Should last until about"; - public static final String ENHANCED_SUFFIX = " based on your usage"; + private static final String TEST_BATTERY_LEVEL_10 = "10%"; + private static final long SEVENTEEN_MIN_MILLIS = Duration.ofMinutes(17).toMillis(); + private static final long FIVE_MINUTES_MILLIS = Duration.ofMinutes(5).toMillis(); + private static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis(); + private static final long THREE_DAYS_MILLIS = Duration.ofDays(3).toMillis(); + private static final long THIRTY_HOURS_MILLIS = Duration.ofHours(30).toMillis(); + private static final String NORMAL_CASE_EXPECTED_PREFIX = "Should last until about"; + private static final String ENHANCED_SUFFIX = " based on your usage"; // matches a time (ex: '1:15 PM', '2 AM', '23:00') - public static final String TIME_OF_DAY_REGEX = " (\\d)+:?(\\d)* ((AM)*)|((PM)*)"; + private static final String TIME_OF_DAY_REGEX = " (\\d)+:?(\\d)* ((AM)*)|((PM)*)"; // matches a percentage with parenthesis (ex: '(10%)') - public static final String PERCENTAGE_REGEX = " \\(\\d?\\d%\\)"; + private static final String PERCENTAGE_REGEX = " \\(\\d?\\d%\\)"; private Context mContext; @@ -108,7 +107,6 @@ public class PowerUtilTest { + "(" + PERCENTAGE_REGEX + "){0}")); // no percentage } - @Test public void testGetBatteryRemainingStringFormatted_lessThanSevenMinutes_usesCorrectString() { String info = PowerUtil.getBatteryRemainingStringFormatted(mContext, diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java index e4bbbcb0b207..8fbbfbbd5047 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java @@ -25,14 +25,13 @@ import android.text.SpannableStringBuilder; import android.text.format.DateUtils; import android.text.style.TtsSpan; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class StringUtilTest { private Context mContext; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java index 1e066b1b0f74..26db124c0041 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java @@ -15,28 +15,22 @@ */ package com.android.settingslib.utils; - import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowLooper; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class ThreadUtilsTest { @Test public void testMainThread() throws InterruptedException { assertThat(ThreadUtils.isMainThread()).isTrue(); - Thread background = new Thread(new Runnable() { - public void run() { - assertThat(ThreadUtils.isMainThread()).isFalse(); - } - }); + Thread background = new Thread(() -> assertThat(ThreadUtils.isMainThread()).isFalse()); background.start(); background.join(); } @@ -44,13 +38,11 @@ public class ThreadUtilsTest { @Test public void testEnsureMainThread() throws InterruptedException { ThreadUtils.ensureMainThread(); - Thread background = new Thread(new Runnable() { - public void run() { - try { - ThreadUtils.ensureMainThread(); - fail("Should not pass ensureMainThread in a background thread"); - } catch (RuntimeException e) { - } + Thread background = new Thread(() -> { + try { + ThreadUtils.ensureMainThread(); + fail("Should not pass ensureMainThread in a background thread"); + } catch (RuntimeException expected) { } }); background.start(); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java index a00f12d9a6d9..d41d5112e6b2 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java @@ -22,14 +22,13 @@ import android.app.Activity; import android.graphics.drawable.AnimatedRotateDrawable; import android.view.View; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class AnimatedImageViewTest { private AnimatedImageView mAnimatedImageView; @@ -47,5 +46,4 @@ public class AnimatedImageViewTest { AnimatedRotateDrawable drawable = (AnimatedRotateDrawable) mAnimatedImageView.getDrawable(); assertThat(drawable.isRunning()).isTrue(); } - } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java index e030005e2d09..601da0512c7c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java @@ -18,7 +18,7 @@ package com.android.settingslib.widget; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -29,7 +29,6 @@ import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; @@ -37,9 +36,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class FooterPreferenceMixinCompatTest { @Mock @@ -97,5 +97,4 @@ public class FooterPreferenceMixinCompatTest { verify(mScreen).removePreference(any(FooterPreference.class)); verify(mScreen, times(2)).addPreference(any(FooterPreference.class)); } - } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java index 8817ff7f65b3..7ae5d2d97cb8 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java @@ -18,7 +18,7 @@ package com.android.settingslib.widget; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -29,7 +29,6 @@ import androidx.preference.PreferenceFragment; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; @@ -37,10 +36,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.shadows.ShadowApplication; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class FooterPreferenceMixinTest { @Mock diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java index e0eceb418f27..0d2399e3dcab 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java @@ -26,14 +26,14 @@ import android.widget.TextView; import androidx.preference.PreferenceViewHolder; import com.android.settingslib.R; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class FooterPreferenceTest { private Context mContext; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/LayoutPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/LayoutPreferenceTest.java index 427a611d61da..99261a38f73b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/LayoutPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/LayoutPreferenceTest.java @@ -27,14 +27,13 @@ import android.view.LayoutInflater; import androidx.preference.Preference.OnPreferenceClickListener; import androidx.preference.PreferenceViewHolder; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class LayoutPreferenceTest { private LayoutPreference mPreference; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java index 10c9dfbe6067..da97cc8b74dd 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java @@ -23,14 +23,13 @@ import android.view.View; import androidx.preference.PreferenceViewHolder; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class AppPreferenceTest { private Context mContext; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java index 86443bde4667..c5cbea78120f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java @@ -25,16 +25,15 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.graphics.drawable.ColorDrawable; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class AccessPointPreferenceTest { private Context mContext = RuntimeEnvironment.application; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/TimestampedScoredNetworkTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/TimestampedScoredNetworkTest.java index f0e8c66e8544..b059df1fd8cb 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/TimestampedScoredNetworkTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/TimestampedScoredNetworkTest.java @@ -22,15 +22,14 @@ import android.net.ScoredNetwork; import android.net.WifiKey; import android.os.Parcel; -import com.android.settingslib.SettingsLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import java.util.Date; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class TimestampedScoredNetworkTest { private TimestampedScoredNetwork impl; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java index 07c50fde00fa..89960cba2bf5 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java @@ -37,19 +37,19 @@ import android.text.format.DateUtils; import android.util.ArraySet; import com.android.settingslib.R; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.Set; -@RunWith(SettingsLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class WifiUtilsTest { private static final String TEST_SSID = "\"test_ssid\""; private static final String TEST_BSSID = "00:00:00:00:00:00"; @@ -79,7 +79,7 @@ public class WifiUtilsTest { Bundle bundle = new Bundle(); ArrayList<ScanResult> scanResults = buildScanResultCache(); bundle.putParcelableArray(AccessPoint.KEY_SCANRESULTS, - scanResults.toArray(new Parcelable[scanResults.size()])); + scanResults.toArray(new Parcelable[0])); AccessPoint ap = new AccessPoint(mContext, bundle); when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class))) diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java index f4922088bb05..4891e5006279 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java @@ -30,6 +30,12 @@ public interface ActivityStarter { int VERSION = 1; void startPendingIntentDismissingKeyguard(PendingIntent intent); + + /** + * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but + * allow you to specify the callback that is executed after the intent is sent. + */ + void startPendingIntentDismissingKeyguard(PendingIntent intent, Runnable intentSentCallback); void startActivity(Intent intent, boolean dismissShade); void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade); void startActivity(Intent intent, boolean dismissShade, Callback callback); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java index 70258c20538d..2aba3fa607b7 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java @@ -20,7 +20,6 @@ import android.graphics.Matrix; import android.graphics.Rect; import android.os.IBinder; import android.view.Surface; -import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; public class TransactionCompat { @@ -53,7 +52,7 @@ public class TransactionCompat { } public TransactionCompat setSize(SurfaceControlCompat surfaceControl, int w, int h) { - mTransaction.setSize(surfaceControl.mSurfaceControl, w, h); + mTransaction.setBufferSize(surfaceControl.mSurfaceControl, w, h); return this; } diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java index e1b8dc839bde..9e7c5ba1d66c 100644 --- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java @@ -36,6 +36,15 @@ public class ActivityStarterDelegate implements ActivityStarter { } @Override + public void startPendingIntentDismissingKeyguard(PendingIntent intent, + Runnable intentSentCallback) { + if (mActualStarter == null) { + return; + } + mActualStarter.startPendingIntentDismissingKeyguard(intent, intentSentCallback); + } + + @Override public void startActivity(Intent intent, boolean dismissShade) { if (mActualStarter == null) { return; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index 01a234544c5b..1dd3101075b0 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -24,20 +24,21 @@ import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; -import android.os.Build; import android.os.Handler; +import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Dependency; /** * Controls the screen brightness when dozing. */ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachine.Part, SensorEventListener { + private static final boolean DEBUG_AOD_BRIGHTNESS = SystemProperties + .getBoolean("debug.aod_brightness", false); protected static final String ACTION_AOD_BRIGHTNESS = "com.android.systemui.doze.AOD_BRIGHTNESS"; protected static final String BRIGHTNESS_BUCKET = "brightness_bucket"; @@ -83,11 +84,9 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi mSensorToScrimOpacity = sensorToScrimOpacity; if (mDebuggable) { - Dependency.get(Dependency.BG_HANDLER).post(()-> { - IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_AOD_BRIGHTNESS); - mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, handler); - }); + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_AOD_BRIGHTNESS); + mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, handler); } } @@ -97,7 +96,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi this(context, service, sensorManager, lightSensor, host, handler, context.getResources().getInteger( com.android.internal.R.integer.config_screenBrightnessDoze), - policy.screenBrightnessArray, policy.dimmingScrimArray, Build.IS_DEBUGGABLE); + policy.screenBrightnessArray, policy.dimmingScrimArray, DEBUG_AOD_BRIGHTNESS); } @Override @@ -126,9 +125,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi private void onDestroy() { setLightSensorEnabled(false); if (mDebuggable) { - Dependency.get(Dependency.BG_HANDLER).post(()-> { - mContext.unregisterReceiver(this); - }); + mContext.unregisterReceiver(this); } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java index 9a5a5b855999..be504ef5eb9c 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java @@ -23,6 +23,7 @@ import android.os.ServiceManager; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.DozeParameters; import java.io.PrintWriter; @@ -80,11 +81,12 @@ public class DozeWallpaperState implements DozeMachine.Part { if (isAmbientMode != mIsAmbientMode) { mIsAmbientMode = isAmbientMode; try { + long duration = animated ? StackStateAnimator.ANIMATION_DURATION_WAKEUP : 0L; if (DEBUG) { Log.i(TAG, "AOD wallpaper state changed to: " + mIsAmbientMode - + ", animated: " + animated); + + ", animationDuration: " + duration); } - mWallpaperManagerService.setInAmbientMode(mIsAmbientMode, animated); + mWallpaperManagerService.setInAmbientMode(mIsAmbientMode, duration); } catch (RemoteException e) { // Cannot notify wallpaper manager service, but it's fine, let's just skip it. Log.w(TAG, "Cannot notify state to WallpaperManagerService: " + mIsAmbientMode); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java index 8b434a546504..496aa0e572ae 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java @@ -323,7 +323,9 @@ public class QSDetail extends LinearLayout { post(new Runnable() { @Override public void run() { - handleShowingDetail(detail, x, y, false /* toggleQs */); + if (isAttachedToWindow()) { + handleShowingDetail(detail, x, y, false /* toggleQs */); + } } }); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java index 0638998d8e67..3a96595dee06 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java @@ -198,7 +198,8 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { mIcon.setIcon(state, allowAnimations); setContentDescription(state.contentDescription); - mAccessibilityClass = state.expandedAccessibilityClassName; + mAccessibilityClass = + state.state == Tile.STATE_UNAVAILABLE ? null : state.expandedAccessibilityClassName; if (state instanceof QSTile.BooleanState) { boolean newState = ((BooleanState) state).value; if (mTileState != newState) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 2ee5443ab3aa..7be5461f0afa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -150,34 +150,42 @@ public class NotificationRemoteInputManager implements Dumpable { } private void logActionClick(View view) { + Integer actionIndex = (Integer) + view.getTag(com.android.internal.R.id.notification_action_index_tag); + if (actionIndex == null) { + Log.e(TAG, "Couldn't retrieve the actionIndex from the clicked button"); + return; + } ViewParent parent = view.getParent(); - String key = getNotificationKeyForParent(parent); - if (key == null) { + StatusBarNotification statusBarNotification = getNotificationForParent(parent); + if (statusBarNotification == null) { Log.w(TAG, "Couldn't determine notification for click."); return; } - int index = -1; + String key = statusBarNotification.getKey(); + int buttonIndex = -1; // If this is a default template, determine the index of the button. if (view.getId() == com.android.internal.R.id.action0 && parent != null && parent instanceof ViewGroup) { ViewGroup actionGroup = (ViewGroup) parent; - index = actionGroup.indexOfChild(view); + buttonIndex = actionGroup.indexOfChild(view); } final int count = mEntryManager.getNotificationData().getActiveNotifications().size(); final int rank = mEntryManager.getNotificationData().getRank(key); + final Notification.Action action = + statusBarNotification.getNotification().actions[actionIndex]; final NotificationVisibility nv = NotificationVisibility.obtain(key, rank, count, true); try { - mBarService.onNotificationActionClick(key, index, nv); + mBarService.onNotificationActionClick(key, buttonIndex, action, nv, false); } catch (RemoteException e) { // Ignore } } - private String getNotificationKeyForParent(ViewParent parent) { + private StatusBarNotification getNotificationForParent(ViewParent parent) { while (parent != null) { if (parent instanceof ExpandableNotificationRow) { - return ((ExpandableNotificationRow) parent) - .getStatusBarNotification().getKey(); + return ((ExpandableNotificationRow) parent).getStatusBarNotification(); } parent = parent.getParent(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java index 37bdc1ce7cb9..f5d6904a1543 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java @@ -15,12 +15,15 @@ */ package com.android.systemui.statusbar; +import android.app.Notification; import android.os.RemoteException; import android.util.ArraySet; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dependency; import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.NotificationEntryManager; import java.util.Set; @@ -32,6 +35,9 @@ public class SmartReplyController { private IStatusBarService mBarService; private Set<String> mSendingKeys = new ArraySet<>(); private Callback mCallback; + private final NotificationEntryManager mEntryManager = + Dependency.get(NotificationEntryManager.class); + public SmartReplyController() { mBarService = Dependency.get(IStatusBarService.class); @@ -57,6 +63,24 @@ public class SmartReplyController { } /** + * Notifies StatusBarService a smart action is clicked. + */ + public void smartActionClicked( + NotificationData.Entry entry, int actionIndex, Notification.Action action, + boolean generatedByAssistant) { + final int count = mEntryManager.getNotificationData().getActiveNotifications().size(); + final int rank = mEntryManager.getNotificationData().getRank(entry.key); + final NotificationVisibility nv = + NotificationVisibility.obtain(entry.key, rank, count, true); + try { + mBarService.onNotificationActionClick( + entry.key, actionIndex, action, nv, generatedByAssistant); + } catch (RemoteException e) { + // Nothing to do, system going down + } + } + + /** * Have we posted an intent to an app about sending a smart reply from the * notification with this key. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java index 314a31d336fd..0a2e04fd9430 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java @@ -250,23 +250,24 @@ public class MessagingLayoutTransformState extends TransformState { otherChild = null; } } - if (otherChild == null) { + if (otherChild == null && previousTranslation < 0) { + // Let's fade out as we approach the top of the screen. We can only do this if + // we're actually moving up float distanceToTop = child.getTop() + child.getHeight() + previousTranslation; transformationAmount = distanceToTop / child.getHeight(); transformationAmount = Math.max(0.0f, Math.min(1.0f, transformationAmount)); - if (to) { - transformationAmount = 1.0f - transformationAmount; - } } transformView(transformationAmount, to, child, otherChild, false, /* sameAsAny */ useLinearTransformation); - if (transformationAmount == 0.0f - && otherGroup.getIsolatedMessage() == otherChild) { + boolean otherIsIsolated = otherGroup.getIsolatedMessage() == otherChild; + if (transformationAmount == 0.0f && otherIsIsolated) { ownGroup.setTransformingImages(true); } if (otherChild == null) { child.setTranslationY(previousTranslation); setClippingDeactivated(child, true); + } else if (ownGroup.getIsolatedMessage() == child || otherIsIsolated) { + // We don't want to add any translation for the image that is transforming } else if (to) { float totalTranslation = child.getTop() + ownGroup.getTop() - otherChild.getTop() - otherChild.getTop(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 7970f166d8a6..1616b6dc53de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -176,9 +176,12 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } // Check if the notification is displaying the menu, if so slide notification back - if (row.getProvider() != null && row.getProvider().isMenuVisible()) { + if (isMenuVisible(row)) { row.animateTranslateNotification(0); return; + } else if (row.isChildInGroup() && isMenuVisible(row.getNotificationParent())) { + row.getNotificationParent().animateTranslateNotification(0); + return; } // Mark notification for one frame. @@ -193,6 +196,10 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. mCallback.onNotificationClicked(sbn, row); } + private boolean isMenuVisible(ExpandableNotificationRow row) { + return row.getProvider() != null && row.getProvider().isMenuVisible(); + } + public void register(ExpandableNotificationRow row, StatusBarNotification sbn) { Notification notification = sbn.getNotification(); if (notification.contentIntent != null || notification.fullScreenIntent != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java index 247c1ababc18..a194eef39b6d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java @@ -16,15 +16,13 @@ package com.android.systemui.statusbar.notification; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; - /** * An object that can determine the visibility of a Notification. */ public interface VisibilityLocationProvider { /** - * Returns whether an ExpandableNotificationRow is in a visible location or not. + * Returns whether an Entry is in a visible location or not. * * @param entry * @return true if row is in a visible location diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 0cd431f9d25b..d4d45ea52a85 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -2067,6 +2067,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private void setChildIsExpanding(boolean isExpanding) { mChildIsExpanding = isExpanding; + updateClipping(); + invalidate(); } @Override @@ -2968,7 +2970,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return true; } } else if (child == mChildrenContainer) { - if (!mChildIsExpanding && (isClippingNeeded() || !hasNoRounding())) { + if (isClippingNeeded() || !hasNoRounding()) { return true; } } else if (child instanceof NotificationGuts) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java index a7aed5fce2e1..0efb1308e83e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java @@ -115,12 +115,14 @@ public abstract class ExpandableOutlineView extends ExpandableView { if (!mCustomOutline) { int translation = mShouldTranslateContents && !ignoreTranslation ? (int) getTranslation() : 0; - left = Math.max(translation, 0); + int halfExtraWidth = (int) (mExtraWidthForClipping / 2.0f); + left = Math.max(translation, 0) - halfExtraWidth; top = mClipTopAmount + mBackgroundTop; - right = getWidth() + Math.min(translation, 0); + right = getWidth() + halfExtraWidth + Math.min(translation, 0); // If the top is rounded we want the bottom to be at most at the top roundness, in order // to avoid the shadow changing when scrolling up. - bottom = Math.max(getActualHeight() - mClipBottomAmount, (int) (top + topRoundness)); + bottom = Math.max(mMinimumHeightForClipping, + Math.max(getActualHeight() - mClipBottomAmount, (int) (top + topRoundness))); } else { left = mOutlineRect.left; top = mOutlineRect.top; @@ -219,10 +221,12 @@ public abstract class ExpandableOutlineView extends ExpandableView { public void setExtraWidthForClipping(float extraWidthForClipping) { mExtraWidthForClipping = extraWidthForClipping; + invalidate(); } public void setMinimumHeightForClipping(int minimumHeightForClipping) { mMinimumHeightForClipping = minimumHeightForClipping; + invalidate(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index a4fdc08d5579..92d1b452bf44 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -57,7 +57,6 @@ import com.android.systemui.statusbar.policy.SmartReplyView; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.Collections; import java.util.List; /** @@ -1520,7 +1519,8 @@ public class NotificationContentView extends FrameLayout { smartRepliesAndActions.smartReplies, mSmartReplyController, entry); } if (smartRepliesAndActions.smartActions != null) { - smartReplyView.addSmartActions(smartRepliesAndActions.smartActions); + smartReplyView.addSmartActions( + smartRepliesAndActions.smartActions, mSmartReplyController, entry); } smartReplyContainer.setVisibility(View.VISIBLE); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 82f9e0340490..408ab42a6f06 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -196,7 +196,6 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; @@ -722,7 +721,7 @@ public class StatusBar extends SystemUI implements DemoMode, IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface( ServiceManager.getService(Context.WALLPAPER_SERVICE)); try { - wallpaperManager.setInAmbientMode(false /* ambientMode */, false /* animated */); + wallpaperManager.setInAmbientMode(false /* ambientMode */, 0L /* duration */); } catch (RemoteException e) { // Just pass, nothing critical. } @@ -4324,7 +4323,14 @@ public class StatusBar extends SystemUI implements DemoMode, }, afterKeyguardGone); } + @Override public void startPendingIntentDismissingKeyguard(final PendingIntent intent) { + startPendingIntentDismissingKeyguard(intent, null); + } + + @Override + public void startPendingIntentDismissingKeyguard( + final PendingIntent intent, @Nullable final Runnable intentSentCallback) { final boolean afterKeyguardGone = intent.isActivity() && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(), mLockscreenUserManager.getCurrentUserId()); @@ -4343,6 +4349,9 @@ public class StatusBar extends SystemUI implements DemoMode, if (intent.isActivity()) { mAssistManager.hideAssist(); } + if (intentSentCallback != null) { + intentSentCallback.run(); + } }, afterKeyguardGone); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java index 88ff0780c974..f36066ce3794 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java @@ -208,12 +208,14 @@ public class SmartReplyView extends ViewGroup { * Add smart actions to be shown next to smart replies. Only the actions that fit into the * notification are shown. */ - public void addSmartActions(SmartActions smartActions) { + public void addSmartActions(SmartActions smartActions, + SmartReplyController smartReplyController, NotificationData.Entry entry) { int numSmartActions = smartActions.actions.size(); for (int n = 0; n < numSmartActions; n++) { Notification.Action action = smartActions.actions.get(n); if (action.actionIntent != null) { - Button actionButton = inflateActionButton(getContext(), this, action); + Button actionButton = inflateActionButton( + getContext(), this, n, smartActions, smartReplyController, entry); addView(actionButton); } } @@ -270,7 +272,10 @@ public class SmartReplyView extends ViewGroup { } @VisibleForTesting - Button inflateActionButton(Context context, ViewGroup root, Notification.Action action) { + Button inflateActionButton(Context context, ViewGroup root, int actionIndex, + SmartActions smartActions, SmartReplyController smartReplyController, + NotificationData.Entry entry) { + Notification.Action action = smartActions.actions.get(actionIndex); Button button = (Button) LayoutInflater.from(context).inflate( R.layout.smart_action_button, root, false); button.setText(action.title); @@ -283,7 +288,10 @@ public class SmartReplyView extends ViewGroup { button.setCompoundDrawables(iconDrawable, null, null, null); button.setOnClickListener(view -> - getActivityStarter().startPendingIntentDismissingKeyguard(action.actionIntent)); + getActivityStarter().startPendingIntentDismissingKeyguard( + action.actionIntent, + () -> smartReplyController.smartActionClicked( + entry, actionIndex, action, smartActions.fromAssistant))); // TODO(b/119010281): handle accessibility diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java index 6ac44628b52f..ec2319d80194 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java @@ -16,9 +16,8 @@ package com.android.systemui.doze; -import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -27,8 +26,8 @@ import android.app.IWallpaperManager; import android.os.RemoteException; import android.support.test.filters.SmallTest; -import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.DozeParameters; import org.junit.Before; @@ -59,14 +58,14 @@ public class DozeWallpaperStateTest extends SysuiTestCase { mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.DOZE_AOD); - verify(mIWallpaperManager).setInAmbientMode(eq(true), anyBoolean()); + verify(mIWallpaperManager).setInAmbientMode(eq(true), anyLong()); mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD, DozeMachine.State.FINISH); - verify(mIWallpaperManager).setInAmbientMode(eq(false), anyBoolean()); + verify(mIWallpaperManager).setInAmbientMode(eq(false), anyLong()); // Make sure we're sending false when AoD is off reset(mDozeParameters); mDozeWallpaperState.transitionTo(DozeMachine.State.FINISH, DozeMachine.State.DOZE_AOD); - verify(mIWallpaperManager).setInAmbientMode(eq(false), anyBoolean()); + verify(mIWallpaperManager).setInAmbientMode(eq(false), anyLong()); } @Test @@ -78,10 +77,12 @@ public class DozeWallpaperStateTest extends SysuiTestCase { mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.DOZE_AOD); - verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(true)); + verify(mIWallpaperManager).setInAmbientMode(eq(true), + eq((long) StackStateAnimator.ANIMATION_DURATION_WAKEUP)); mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD, DozeMachine.State.FINISH); - verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(true)); + verify(mIWallpaperManager).setInAmbientMode(eq(false), + eq((long) StackStateAnimator.ANIMATION_DURATION_WAKEUP)); } @Test @@ -93,24 +94,24 @@ public class DozeWallpaperStateTest extends SysuiTestCase { mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.DOZE_AOD); - verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(false)); + verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(0L)); mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD, DozeMachine.State.FINISH); - verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(false)); + verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(0L)); } @Test public void testTransitionTo_requestPulseIsAmbientMode() throws RemoteException { mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.DOZE_REQUEST_PULSE); - verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(false)); + verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(0L)); } @Test public void testTransitionTo_pulseIsAmbientMode() throws RemoteException { mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE, DozeMachine.State.DOZE_PULSING); - verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(false)); + verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(0L)); } @Test @@ -120,6 +121,7 @@ public class DozeWallpaperStateTest extends SysuiTestCase { reset(mIWallpaperManager); mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_PULSING, DozeMachine.State.FINISH); - verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(true)); + verify(mIWallpaperManager).setInAmbientMode(eq(false), + eq((long) StackStateAnimator.ANIMATION_DURATION_WAKEUP)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java index b3b45ebc94b4..f94ba95999bf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java @@ -121,9 +121,9 @@ public class NotificationDataTest extends SysuiTestCase { when(mEnvironment.isDeviceProvisioned()).thenReturn(true); when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); mNotificationData = new TestableNotificationData(); - Dependency.get(InitController.class).executePostInitTasks(); mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class)); mRow = new NotificationTestHelper(getContext()).createRow(); + Dependency.get(InitController.class).executePostInitTasks(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java index 7fee0ee8c664..f0fa7887a0f9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.row; import static com.google.common.truth.Truth.assertThat; -import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java index b6e3fc172c69..df7aeab2ed38 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java @@ -62,6 +62,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -430,12 +431,18 @@ public class SmartReplyViewTest extends SysuiTestCase { private void setSmartActions(String[] actionTitles) { mView.resetSmartSuggestions(mContainer); - mView.addSmartActions(new SmartReplyView.SmartActions(createActions(actionTitles), false)); + mView.addSmartActions( + new SmartReplyView.SmartActions(createActions(actionTitles), false), + mLogger, + mEntry); } private void setSmartRepliesAndActions(CharSequence[] choices, String[] actionTitles) { setSmartReplies(choices); - mView.addSmartActions(new SmartReplyView.SmartActions(createActions(actionTitles), false)); + mView.addSmartActions( + new SmartReplyView.SmartActions(createActions(actionTitles), false), + mLogger, + mEntry); } private ViewGroup buildExpectedView(CharSequence[] choices, int lineCount) { @@ -553,7 +560,7 @@ public class SmartReplyViewTest extends SysuiTestCase { mView.getChildAt(2).performClick(); - verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any()); + verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any()); } @Test @@ -738,7 +745,9 @@ public class SmartReplyViewTest extends SysuiTestCase { } private Button inflateActionButton(Notification.Action action) { - return mView.inflateActionButton(getContext(), mView, action); + return mView.inflateActionButton(getContext(), mView, 0, + new SmartReplyView.SmartActions(Collections.singletonList(action), false), + mLogger, mEntry); } @Test diff --git a/services/backup/OWNERS b/services/backup/OWNERS index 645723e655f8..d1dbbffc6708 100644 --- a/services/backup/OWNERS +++ b/services/backup/OWNERS @@ -1,7 +1,5 @@ anniemeng@google.com -artikz@google.com brufino@google.com bryanmawhinney@google.com ctate@google.com jorlow@google.com -mkarpinski@google.com diff --git a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java index ab639c3c9ce1..2bca34d9cef5 100644 --- a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java +++ b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java @@ -16,7 +16,7 @@ package com.android.server.backup; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG_SCHEDULING; +import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING; import android.content.ContentResolver; import android.os.Handler; diff --git a/services/backup/java/com/android/server/backup/BackupManagerConstants.java b/services/backup/java/com/android/server/backup/BackupManagerConstants.java index e3fa0dc3c509..785d3ca8a4a2 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerConstants.java +++ b/services/backup/java/com/android/server/backup/BackupManagerConstants.java @@ -16,7 +16,7 @@ package com.android.server.backup; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG_SCHEDULING; +import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING; import android.app.AlarmManager; import android.content.ContentResolver; diff --git a/services/backup/java/com/android/server/backup/GlobalBackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 9a1662e702ae..0b06f286441a 100644 --- a/services/backup/java/com/android/server/backup/GlobalBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -62,7 +62,7 @@ import java.util.Set; * incoming calls to the appropriate per-user {@link UserBackupManagerService} to handle the * corresponding backup/restore operation. */ -public class GlobalBackupManagerService { +public class BackupManagerService { public static final String TAG = "BackupManagerService"; public static final boolean DEBUG = true; public static final boolean MORE_DEBUG = false; @@ -82,8 +82,8 @@ public class GlobalBackupManagerService { return sInstance; } - /** Helper to create the {@link GlobalBackupManagerService} instance. */ - public static GlobalBackupManagerService create( + /** Helper to create the {@link BackupManagerService} instance. */ + public static BackupManagerService create( Context context, Trampoline parent, HandlerThread backupThread) { @@ -116,7 +116,7 @@ public class GlobalBackupManagerService { // This dir on /cache is managed directly in init.rc File dataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage"); - return new GlobalBackupManagerService( + return new BackupManagerService( context, parent, backupThread, @@ -127,8 +127,8 @@ public class GlobalBackupManagerService { private UserBackupManagerService mUserBackupManagerService; - /** Instantiate a new instance of {@link GlobalBackupManagerService}. */ - public GlobalBackupManagerService( + /** Instantiate a new instance of {@link BackupManagerService}. */ + public BackupManagerService( Context context, Trampoline trampoline, HandlerThread backupThread, diff --git a/services/backup/java/com/android/server/backup/FileMetadata.java b/services/backup/java/com/android/server/backup/FileMetadata.java index 84d987de3b22..fe75041eeaca 100644 --- a/services/backup/java/com/android/server/backup/FileMetadata.java +++ b/services/backup/java/com/android/server/backup/FileMetadata.java @@ -16,7 +16,7 @@ package com.android.server.backup; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.TAG; import android.app.backup.BackupAgent; import android.util.Slog; diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java index ce024765b4db..82638b4ecee4 100644 --- a/services/backup/java/com/android/server/backup/FullBackupJob.java +++ b/services/backup/java/com/android/server/backup/FullBackupJob.java @@ -61,7 +61,7 @@ public class FullBackupJob extends JobService { @Override public boolean onStartJob(JobParameters params) { mParams = params; - Trampoline service = GlobalBackupManagerService.getInstance(); + Trampoline service = BackupManagerService.getInstance(); return service.beginFullBackup(this); } @@ -69,7 +69,7 @@ public class FullBackupJob extends JobService { public boolean onStopJob(JobParameters params) { if (mParams != null) { mParams = null; - Trampoline service = GlobalBackupManagerService.getInstance(); + Trampoline service = BackupManagerService.getInstance(); service.endFullBackup(); } return false; diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java index 8156095cf576..f2e74352b004 100644 --- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java +++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java @@ -16,7 +16,7 @@ package com.android.server.backup; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG_SCHEDULING; +import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING; import android.app.AlarmManager; import android.app.job.JobInfo; @@ -118,7 +118,7 @@ public class KeyValueBackupJob extends JobService { } // Time to run a key/value backup! - Trampoline service = GlobalBackupManagerService.getInstance(); + Trampoline service = BackupManagerService.getInstance(); try { service.backupNow(); } catch (RemoteException e) {} diff --git a/services/backup/java/com/android/server/backup/ProcessedPackagesJournal.java b/services/backup/java/com/android/server/backup/ProcessedPackagesJournal.java index dd91381779e4..edc2379ff641 100644 --- a/services/backup/java/com/android/server/backup/ProcessedPackagesJournal.java +++ b/services/backup/java/com/android/server/backup/ProcessedPackagesJournal.java @@ -46,7 +46,7 @@ import java.util.Set; final class ProcessedPackagesJournal { private static final String TAG = "ProcessedPackagesJournal"; private static final String JOURNAL_FILE_NAME = "processed"; - private static final boolean DEBUG = GlobalBackupManagerService.DEBUG; + private static final boolean DEBUG = BackupManagerService.DEBUG; // using HashSet instead of ArraySet since we expect 100-500 elements range @GuardedBy("mProcessedPackages") diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java index 22edebc982dd..59629aac7b4d 100644 --- a/services/backup/java/com/android/server/backup/Trampoline.java +++ b/services/backup/java/com/android/server/backup/Trampoline.java @@ -16,7 +16,7 @@ package com.android.server.backup; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.TAG; import android.annotation.Nullable; import android.app.admin.DevicePolicyManager; @@ -52,12 +52,12 @@ import java.io.IOException; import java.io.PrintWriter; /** - * A proxy to the {@link GlobalBackupManagerService} implementation. + * A proxy to the {@link BackupManagerService} implementation. * - * <p>This is an external interface to the {@link GlobalBackupManagerService} which is being - * accessed via published binder {@link GlobalBackupManagerService.Lifecycle}. This lets us turn - * down the heavy implementation object on the fly without disturbing binders that have been cached - * somewhere in the system. + * <p>This is an external interface to the {@link BackupManagerService} which is being accessed via + * published binder {@link BackupManagerService.Lifecycle}. This lets us turn down the heavy + * implementation object on the fly without disturbing binders that have been cached somewhere in + * the system. * * <p>Trampoline determines whether the backup service is available. It can be disabled in the * following two ways: @@ -89,7 +89,7 @@ public class Trampoline extends IBackupManager.Stub { private final boolean mGlobalDisable; private final Object mStateLock = new Object(); - private volatile GlobalBackupManagerService mService; + private volatile BackupManagerService mService; private HandlerThread mHandlerThread; public Trampoline(Context context) { @@ -116,12 +116,12 @@ public class Trampoline extends IBackupManager.Stub { return mContext; } - protected GlobalBackupManagerService createBackupManagerService() { - return GlobalBackupManagerService.create(mContext, this, mHandlerThread); + protected BackupManagerService createBackupManagerService() { + return BackupManagerService.create(mContext, this, mHandlerThread); } /** - * Initialize {@link GlobalBackupManagerService} if the backup service is not disabled. Only the + * Initialize {@link BackupManagerService} if the backup service is not disabled. Only the * system user can initialize the service. */ /* package */ void initializeService(int userId) { @@ -145,11 +145,10 @@ public class Trampoline extends IBackupManager.Stub { } /** - * Called from {@link GlobalBackupManagerService.Lifecycle} when the system user is unlocked. - * Attempts to initialize {@link GlobalBackupManagerService} and set backup state for the system - * user. + * Called from {@link BackupManagerService.Lifecycle} when the system user is unlocked. Attempts + * to initialize {@link BackupManagerService} and set backup state for the system user. * - * @see GlobalBackupManagerService#unlockSystemUser() + * @see BackupManagerService#unlockSystemUser() */ void unlockSystemUser() { mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND); @@ -162,7 +161,7 @@ public class Trampoline extends IBackupManager.Stub { initializeService(UserHandle.USER_SYSTEM); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - GlobalBackupManagerService service = mService; + BackupManagerService service = mService; if (service != null) { Slog.i(TAG, "Unlocking system user"); service.unlockSystemUser(); @@ -234,7 +233,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void dataChanged(String packageName) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.dataChanged(packageName); } @@ -243,7 +242,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void initializeTransports(String[] transportNames, IBackupObserver observer) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.initializeTransports(transportNames, observer); } @@ -252,7 +251,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void clearBackupData(String transportName, String packageName) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.clearBackupData(transportName, packageName); } @@ -260,7 +259,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void agentConnected(String packageName, IBinder agent) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.agentConnected(packageName, agent); } @@ -268,7 +267,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void agentDisconnected(String packageName) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.agentDisconnected(packageName); } @@ -276,7 +275,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void restoreAtInstall(String packageName, int token) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.restoreAtInstall(packageName, token); } @@ -284,7 +283,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void setBackupEnabled(boolean isEnabled) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.setBackupEnabled(isEnabled); } @@ -292,7 +291,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void setAutoRestore(boolean doAutoRestore) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.setAutoRestore(doAutoRestore); } @@ -300,7 +299,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void setBackupProvisioned(boolean isProvisioned) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.setBackupProvisioned(isProvisioned); } @@ -308,25 +307,25 @@ public class Trampoline extends IBackupManager.Stub { @Override public boolean isBackupEnabled() throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.isBackupEnabled() : false; } @Override public boolean setBackupPassword(String currentPw, String newPw) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.setBackupPassword(currentPw, newPw) : false; } @Override public boolean hasBackupPassword() throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.hasBackupPassword() : false; } @Override public void backupNow() throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.backupNow(); } @@ -337,7 +336,7 @@ public class Trampoline extends IBackupManager.Stub { boolean includeShared, boolean doWidgets, boolean allApps, boolean allIncludesSystem, boolean doCompress, boolean doKeyValue, String[] packageNames) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.adbBackup(fd, includeApks, includeObbs, includeShared, doWidgets, allApps, allIncludesSystem, doCompress, doKeyValue, packageNames); @@ -346,7 +345,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void fullTransportBackup(String[] packageNames) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.fullTransportBackup(packageNames); } @@ -354,7 +353,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void adbRestore(ParcelFileDescriptor fd) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.adbRestore(fd); } @@ -364,7 +363,7 @@ public class Trampoline extends IBackupManager.Stub { public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword, String encryptionPassword, IFullBackupRestoreObserver observer) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.acknowledgeAdbBackupOrRestore(token, allow, curPassword, encryptionPassword, observer); @@ -373,7 +372,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public String getCurrentTransport() throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.getCurrentTransport() : null; } @@ -384,25 +383,25 @@ public class Trampoline extends IBackupManager.Stub { @Override @Nullable public ComponentName getCurrentTransportComponent() { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.getCurrentTransportComponent() : null; } @Override public String[] listAllTransports() throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.listAllTransports() : null; } @Override public ComponentName[] listAllTransportComponents() throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.listAllTransportComponents() : null; } @Override public String[] getTransportWhitelist() { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.getTransportWhitelist() : null; } @@ -414,7 +413,7 @@ public class Trampoline extends IBackupManager.Stub { String currentDestinationString, @Nullable Intent dataManagementIntent, String dataManagementLabel) { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.updateTransportAttributes( transportComponent, @@ -428,14 +427,14 @@ public class Trampoline extends IBackupManager.Stub { @Override public String selectBackupTransport(String transport) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.selectBackupTransport(transport) : null; } @Override public void selectBackupTransportAsync(ComponentName transport, ISelectBackupTransportCallback listener) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.selectBackupTransportAsync(transport, listener); } else { @@ -451,38 +450,38 @@ public class Trampoline extends IBackupManager.Stub { @Override public Intent getConfigurationIntent(String transport) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.getConfigurationIntent(transport) : null; } @Override public String getDestinationString(String transport) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.getDestinationString(transport) : null; } @Override public Intent getDataManagementIntent(String transport) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.getDataManagementIntent(transport) : null; } @Override public String getDataManagementLabel(String transport) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.getDataManagementLabel(transport) : null; } @Override public IRestoreSession beginRestoreSession(String packageName, String transportID) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.beginRestoreSession(packageName, transportID) : null; } @Override public void opComplete(int token, long result) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.opComplete(token, result); } @@ -490,26 +489,26 @@ public class Trampoline extends IBackupManager.Stub { @Override public long getAvailableRestoreToken(String packageName) { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.getAvailableRestoreToken(packageName) : 0; } @Override public boolean isAppEligibleForBackup(String packageName) { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.isAppEligibleForBackup(packageName) : false; } @Override public String[] filterAppsEligibleForBackup(String[] packages) { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.filterAppsEligibleForBackup(packages) : null; } @Override public int requestBackup(String[] packages, IBackupObserver observer, IBackupManagerMonitor monitor, int flags) throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc == null) { return BackupManager.ERROR_BACKUP_NOT_ALLOWED; } @@ -518,7 +517,7 @@ public class Trampoline extends IBackupManager.Stub { @Override public void cancelBackups() throws RemoteException { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.cancelBackups(); } @@ -528,7 +527,7 @@ public class Trampoline extends IBackupManager.Stub { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.dump(fd, pw, args); } else { @@ -539,12 +538,12 @@ public class Trampoline extends IBackupManager.Stub { // Full backup/restore entry points - non-Binder; called directly // by the full-backup scheduled job /* package */ boolean beginFullBackup(FullBackupJob scheduledJob) { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; return (svc != null) ? svc.beginFullBackup(scheduledJob) : false; } /* package */ void endFullBackup() { - GlobalBackupManagerService svc = mService; + BackupManagerService svc = mService; if (svc != null) { svc.endFullBackup(); } diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 4855ae0358bc..fe16afe864ac 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -18,10 +18,10 @@ package com.android.server.backup; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG_SCHEDULING; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_FULL_CONFIRMATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_OP_COMPLETE; @@ -2665,7 +2665,7 @@ public class UserBackupManagerService { boolean wasEnabled = mEnabled; synchronized (this) { // TODO(b/118520567): Clean up writing backup enabled logic. - GlobalBackupManagerService.writeBackupEnableState(enable, UserHandle.USER_SYSTEM); + BackupManagerService.writeBackupEnableState(enable, UserHandle.USER_SYSTEM); mEnabled = enable; } diff --git a/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java b/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java index 725bc74a66c6..bace1aa638ec 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java +++ b/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java @@ -1,7 +1,7 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_VERSION; import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_VERSION; import static com.android.server.backup.UserBackupManagerService.BACKUP_WIDGET_METADATA_TOKEN; diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java index 9b484bc3ca29..5e923393843e 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java @@ -16,9 +16,9 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java index 24784ea92c73..e14253702d55 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java @@ -16,8 +16,8 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; import android.app.backup.IBackupManager; diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupTask.java index 0ed75bb4a1b4..8f6923b6c05b 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupTask.java @@ -16,7 +16,7 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.TAG; import android.app.backup.IFullBackupRestoreObserver; import android.os.RemoteException; diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java index 2f7687fc7009..43a80c45d6f7 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java @@ -16,10 +16,10 @@ package com.android.server.backup.fullbackup; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEADER_MAGIC; import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION; import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index 0d14e7ef3e55..5b449c5b400e 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -16,9 +16,9 @@ package com.android.server.backup.fullbackup; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG_SCHEDULING; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.UserBackupManagerService.OP_PENDING; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT; diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java index fd0946679655..ba153bf90ebe 100644 --- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java +++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java @@ -16,9 +16,9 @@ package com.android.server.backup.internal; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import android.app.backup.RestoreSet; import android.content.Intent; diff --git a/services/backup/java/com/android/server/backup/internal/PerformClearTask.java b/services/backup/java/com/android/server/backup/internal/PerformClearTask.java index 2bad5fe7ae1e..5ffa795d87f0 100644 --- a/services/backup/java/com/android/server/backup/internal/PerformClearTask.java +++ b/services/backup/java/com/android/server/backup/internal/PerformClearTask.java @@ -16,7 +16,7 @@ package com.android.server.backup.internal; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.TAG; import android.content.pm.PackageInfo; import android.util.Slog; diff --git a/services/backup/java/com/android/server/backup/internal/PerformInitializeTask.java b/services/backup/java/com/android/server/backup/internal/PerformInitializeTask.java index 1637e559acb7..6b78fbf60899 100644 --- a/services/backup/java/com/android/server/backup/internal/PerformInitializeTask.java +++ b/services/backup/java/com/android/server/backup/internal/PerformInitializeTask.java @@ -16,7 +16,7 @@ package com.android.server.backup.internal; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.TAG; import android.annotation.Nullable; import android.app.AlarmManager; diff --git a/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java b/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java index eab86629e75b..7e2ac796d343 100644 --- a/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java +++ b/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java @@ -16,8 +16,8 @@ package com.android.server.backup.internal; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import android.database.ContentObserver; import android.os.Handler; diff --git a/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java b/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java index d869f044f5a4..2a5d913226b9 100644 --- a/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java +++ b/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java @@ -16,9 +16,9 @@ package com.android.server.backup.internal; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.RUN_BACKUP_ACTION; import static com.android.server.backup.internal.BackupHandler.MSG_RUN_BACKUP; diff --git a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java index 880e608a2fdb..38870cba4812 100644 --- a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java +++ b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java @@ -16,8 +16,8 @@ package com.android.server.backup.internal; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.RUN_INITIALIZE_ACTION; import android.content.BroadcastReceiver; diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java index 437abd22d249..535c7cb29980 100644 --- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java @@ -28,8 +28,8 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.EventLogTags; +import com.android.server.backup.BackupManagerService; import com.android.server.backup.DataChangedJournal; -import com.android.server.backup.GlobalBackupManagerService; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.remote.RemoteResult; import com.android.server.backup.utils.BackupManagerMonitorUtils; @@ -54,8 +54,8 @@ import java.util.List; @VisibleForTesting public class KeyValueBackupReporter { @VisibleForTesting static final String TAG = "KeyValueBackupTask"; - private static final boolean DEBUG = GlobalBackupManagerService.DEBUG; - @VisibleForTesting static final boolean MORE_DEBUG = GlobalBackupManagerService.MORE_DEBUG; + private static final boolean DEBUG = BackupManagerService.DEBUG; + @VisibleForTesting static final boolean MORE_DEBUG = BackupManagerService.MORE_DEBUG; static void onNewThread(String threadName) { if (DEBUG) { diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java index 5c05371aedda..e273b329d51a 100644 --- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java +++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java @@ -16,8 +16,8 @@ package com.android.server.backup.restore; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_RUN_GET_RESTORE_SETS; import static com.android.server.backup.internal.BackupHandler.MSG_RUN_RESTORE; diff --git a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java index 8196e709f2ee..e4890e009abb 100644 --- a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java +++ b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java @@ -16,8 +16,8 @@ package com.android.server.backup.restore; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import android.util.Slog; diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index ee08902aca05..0d26ea56faa2 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -16,9 +16,9 @@ package com.android.server.backup.restore; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_RESTORE_WAIT; diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java index 381252dafe07..c9042566cf67 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java @@ -16,11 +16,11 @@ package com.android.server.backup.restore; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT; import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEADER_MAGIC; import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION; import static com.android.server.backup.UserBackupManagerService.SETTINGS_PACKAGE; diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 7530356fff4d..f7efad604e35 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -16,9 +16,9 @@ package com.android.server.backup.restore; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.KEY_WIDGET_STATE; import static com.android.server.backup.UserBackupManagerService.OP_TYPE_RESTORE_WAIT; import static com.android.server.backup.UserBackupManagerService.PACKAGE_MANAGER_SENTINEL; diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java index 2452e4868c80..e465c7e5264f 100644 --- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java @@ -16,8 +16,8 @@ package com.android.server.backup.utils; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import android.annotation.Nullable; diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java index 8b931d43dfe0..6f083760980d 100644 --- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java +++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java @@ -18,8 +18,8 @@ package com.android.server.backup.utils; import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import android.annotation.Nullable; import android.app.backup.BackupManagerMonitor; diff --git a/services/backup/java/com/android/server/backup/utils/BackupObserverUtils.java b/services/backup/java/com/android/server/backup/utils/BackupObserverUtils.java index 9674c3db9c75..c0cf2ef86920 100644 --- a/services/backup/java/com/android/server/backup/utils/BackupObserverUtils.java +++ b/services/backup/java/com/android/server/backup/utils/BackupObserverUtils.java @@ -16,8 +16,8 @@ package com.android.server.backup.utils; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import android.app.backup.BackupProgress; import android.app.backup.IBackupObserver; diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupRestoreObserverUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupRestoreObserverUtils.java index 92cdf0de48c7..fa856ce2c6de 100644 --- a/services/backup/java/com/android/server/backup/utils/FullBackupRestoreObserverUtils.java +++ b/services/backup/java/com/android/server/backup/utils/FullBackupRestoreObserverUtils.java @@ -16,7 +16,7 @@ package com.android.server.backup.utils; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.TAG; import android.app.backup.IFullBackupRestoreObserver; import android.os.RemoteException; diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java index a6fdbf004726..dbe3cd9225b5 100644 --- a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java @@ -16,7 +16,7 @@ package com.android.server.backup.utils; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.TAG; import android.os.ParcelFileDescriptor; import android.util.Slog; diff --git a/services/backup/java/com/android/server/backup/utils/PasswordUtils.java b/services/backup/java/com/android/server/backup/utils/PasswordUtils.java index 65adf4ee267d..a7eb644713ba 100644 --- a/services/backup/java/com/android/server/backup/utils/PasswordUtils.java +++ b/services/backup/java/com/android/server/backup/utils/PasswordUtils.java @@ -16,7 +16,7 @@ package com.android.server.backup.utils; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.TAG; import android.util.Slog; diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java index 91567d7aa0e5..df7e6d45ba0f 100644 --- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java +++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java @@ -16,8 +16,8 @@ package com.android.server.backup.utils; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import android.content.Context; import android.content.IIntentReceiver; diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java index c295684d0732..0f4b6810f15b 100644 --- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java +++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java @@ -34,9 +34,9 @@ import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH; import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER; -import static com.android.server.backup.GlobalBackupManagerService.DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.MORE_DEBUG; -import static com.android.server.backup.GlobalBackupManagerService.TAG; +import static com.android.server.backup.BackupManagerService.DEBUG; +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_FILENAME; import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_VERSION; import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_FILENAME; diff --git a/services/core/Android.bp b/services/core/Android.bp index 617430090998..784d398a2b3f 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -32,6 +32,10 @@ java_library_static { "android.hardware.tv.cec-V1.0-java", ], + required: [ + "gps_debug.conf", + ], + static_libs: [ "time_zone_distro", "time_zone_distro_installer", @@ -69,3 +73,9 @@ java_library { name: "services.core", static_libs: ["services.core.priorityboosted"], } + + +prebuilt_etc { + name: "gps_debug.conf", + src: "java/com/android/server/location/gps_debug.conf", +} diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 60bbca833925..bb3b9f72d55e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2099,14 +2099,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return new MockableSystemProperties(); } - // TODO: Replace nai and newLp with TcpBufferSizes and check default network before calling - // this method. - private void updateTcpBufferSizes(NetworkAgentInfo nai, LinkProperties newLp) { - if (isDefaultNetwork(nai) == false) { - return; - } - - String tcpBufferSizes = newLp.getTcpBufferSizes(); + private void updateTcpBufferSizes(String tcpBufferSizes) { String[] values = null; if (tcpBufferSizes != null) { values = tcpBufferSizes.split(","); @@ -4798,7 +4791,9 @@ public class ConnectivityService extends IConnectivityManager.Stub // for (LinkProperties lp : newLp.getStackedLinks()) { // updateMtu(lp, null); // } - updateTcpBufferSizes(networkAgent, newLp); + if (isDefaultNetwork(networkAgent)) { + updateTcpBufferSizes(newLp.getTcpBufferSizes()); + } updateRoutes(newLp, oldLp, netId); updateDnses(newLp, oldLp, netId); @@ -5289,7 +5284,7 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyLockdownVpn(newNetwork); handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy()); - updateTcpBufferSizes(newNetwork, new LinkProperties(newNetwork.linkProperties)); + updateTcpBufferSizes(newNetwork.linkProperties.getTcpBufferSizes()); mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); notifyIfacesChangedForNetworkStats(); } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 923ac0063baf..0e6f8dda44f6 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -2686,24 +2686,35 @@ class StorageManagerService extends IStorageManager.Stub class AppFuseMountScope extends AppFuseBridge.MountScope { boolean opened = false; - public AppFuseMountScope(int uid, int pid, int mountId) { - super(uid, pid, mountId); + public AppFuseMountScope(int uid, int mountId) { + super(uid, mountId); } @Override public ParcelFileDescriptor open() throws NativeDaemonConnectorException { try { return new ParcelFileDescriptor( - mVold.mountAppFuse(uid, Process.myPid(), mountId)); + mVold.mountAppFuse(uid, mountId)); } catch (Exception e) { throw new NativeDaemonConnectorException("Failed to mount", e); } } @Override + public ParcelFileDescriptor openFile(int mountId, int fileId, int flags) + throws NativeDaemonConnectorException { + try { + return new ParcelFileDescriptor( + mVold.openAppFuseFile(uid, mountId, fileId, flags)); + } catch (Exception e) { + throw new NativeDaemonConnectorException("Failed to open", e); + } + } + + @Override public void close() throws Exception { if (opened) { - mVold.unmountAppFuse(uid, Process.myPid(), mountId); + mVold.unmountAppFuse(uid, mountId); opened = false; } } @@ -2713,7 +2724,6 @@ class StorageManagerService extends IStorageManager.Stub public @Nullable AppFuseMount mountProxyFileDescriptorBridge() { Slog.v(TAG, "mountProxyFileDescriptorBridge"); final int uid = Binder.getCallingUid(); - final int pid = Binder.getCallingPid(); while (true) { synchronized (mAppFuseLock) { @@ -2727,7 +2737,7 @@ class StorageManagerService extends IStorageManager.Stub final int name = mNextAppFuseName++; try { return new AppFuseMount( - name, mAppFuseBridge.addBridge(new AppFuseMountScope(uid, pid, name))); + name, mAppFuseBridge.addBridge(new AppFuseMountScope(uid, name))); } catch (FuseUnavailableMountException e) { if (newlyCreated) { // If newly created bridge fails, it's a real error. @@ -2748,14 +2758,13 @@ class StorageManagerService extends IStorageManager.Stub public @Nullable ParcelFileDescriptor openProxyFileDescriptor( int mountId, int fileId, int mode) { Slog.v(TAG, "mountProxyFileDescriptor"); - final int pid = Binder.getCallingPid(); try { synchronized (mAppFuseLock) { if (mAppFuseBridge == null) { Slog.e(TAG, "FuseBridge has not been created"); return null; } - return mAppFuseBridge.openFile(pid, mountId, fileId, mode); + return mAppFuseBridge.openFile(mountId, fileId, mode); } } catch (FuseUnavailableMountException | InterruptedException error) { Slog.v(TAG, "The mount point has already been invalid", error); diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java index 33525fdc52d2..f2c539cb257c 100644 --- a/services/core/java/com/android/server/display/ColorFade.java +++ b/services/core/java/com/android/server/display/ColorFade.java @@ -16,16 +16,7 @@ package com.android.server.display; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; - import android.content.Context; -import android.graphics.PixelFormat; import android.graphics.SurfaceTexture; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener; @@ -34,20 +25,29 @@ import android.opengl.EGLConfig; import android.opengl.EGLContext; import android.opengl.EGLDisplay; import android.opengl.EGLSurface; -import android.opengl.GLES20; import android.opengl.GLES11Ext; +import android.opengl.GLES20; import android.util.Slog; import android.view.DisplayInfo; -import android.view.Surface.OutOfResourcesException; import android.view.Surface; +import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; +import android.view.SurfaceControl.Transaction; import android.view.SurfaceSession; -import libcore.io.Streams; - import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; +import libcore.io.Streams; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + /** * <p> * Animates a screen transition from on to off or off to on by applying @@ -569,37 +569,31 @@ final class ColorFade { mSurfaceSession = new SurfaceSession(); } - SurfaceControl.openTransaction(); - try { - if (mSurfaceControl == null) { - try { - int flags; - if (mMode == MODE_FADE) { - flags = SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN; - } else { - flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN; - } - mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) - .setName("ColorFade") - .setSize(mDisplayWidth, mDisplayHeight) - .setFlags(flags) - .build(); - } catch (OutOfResourcesException ex) { - Slog.e(TAG, "Unable to create surface.", ex); - return false; + if (mSurfaceControl == null) { + Transaction t = new Transaction(); + try { + final SurfaceControl.Builder builder = + new SurfaceControl.Builder(mSurfaceSession).setName("ColorFade"); + if (mMode == MODE_FADE) { + builder.setColorLayer(true); + } else { + builder.setBufferSize(mDisplayWidth, mDisplayHeight); } + mSurfaceControl = builder.build(); + } catch (OutOfResourcesException ex) { + Slog.e(TAG, "Unable to create surface.", ex); + return false; + } - mSurfaceControl.setLayerStack(mDisplayLayerStack); - mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight); - mSurface = new Surface(); - mSurface.copyFrom(mSurfaceControl); + t.setLayerStack(mSurfaceControl, mDisplayLayerStack); + t.setWindowCrop(mSurfaceControl, mDisplayWidth, mDisplayHeight); + mSurface = new Surface(); + mSurface.copyFrom(mSurfaceControl); - mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, - mDisplayId, mSurfaceControl); - mSurfaceLayout.onDisplayTransaction(); - } - } finally { - SurfaceControl.closeTransaction(); + mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, + mDisplayId, mSurfaceControl); + mSurfaceLayout.onDisplayTransaction(t); + t.apply(); } return true; } @@ -746,7 +740,7 @@ final class ColorFade { } @Override - public void onDisplayTransaction() { + public void onDisplayTransaction(Transaction t) { synchronized (this) { if (mSurfaceControl == null) { return; @@ -755,21 +749,21 @@ final class ColorFade { DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId); switch (displayInfo.rotation) { case Surface.ROTATION_0: - mSurfaceControl.setPosition(0, 0); - mSurfaceControl.setMatrix(1, 0, 0, 1); + t.setPosition(mSurfaceControl, 0, 0); + t.setMatrix(mSurfaceControl, 1, 0, 0, 1); break; case Surface.ROTATION_90: - mSurfaceControl.setPosition(0, displayInfo.logicalHeight); - mSurfaceControl.setMatrix(0, -1, 1, 0); + t.setPosition(mSurfaceControl, 0, displayInfo.logicalHeight); + t.setMatrix(mSurfaceControl, 0, -1, 1, 0); break; case Surface.ROTATION_180: - mSurfaceControl.setPosition(displayInfo.logicalWidth, + t.setPosition(mSurfaceControl, displayInfo.logicalWidth, displayInfo.logicalHeight); - mSurfaceControl.setMatrix(-1, 0, 0, -1); + t.setMatrix(mSurfaceControl, -1, 0, 0, -1); break; case Surface.ROTATION_270: - mSurfaceControl.setPosition(displayInfo.logicalWidth, 0); - mSurfaceControl.setMatrix(0, 1, -1, 0); + t.setPosition(mSurfaceControl, displayInfo.logicalWidth, 0); + t.setMatrix(mSurfaceControl, 0, 1, -1, 0); break; } } diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index 7bfe9ce7017c..6ee5665b9e42 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -225,6 +225,8 @@ abstract class DisplayDevice { viewport.deviceHeight = isRotated ? info.width : info.height; viewport.uniqueId = info.uniqueId; + // TODO(b/112898898) Use an actual port here. + viewport.physicalPort = null; } /** diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index d04fa237a599..360a7d105cce 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -497,7 +497,7 @@ public final class DisplayManagerService extends SystemService { // List is self-synchronized copy-on-write. for (DisplayTransactionListener listener : mDisplayTransactionListeners) { - listener.onDisplayTransaction(); + listener.onDisplayTransaction(t); } } diff --git a/services/core/java/com/android/server/input/ConfigurationProcessor.java b/services/core/java/com/android/server/input/ConfigurationProcessor.java new file mode 100644 index 000000000000..970e86acf8b8 --- /dev/null +++ b/services/core/java/com/android/server/input/ConfigurationProcessor.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018 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.input; + +import android.text.TextUtils; +import android.util.Pair; +import android.util.Slog; +import android.util.Xml; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + + +class ConfigurationProcessor { + private static final String TAG = "ConfigurationProcessor"; + + static List<String> processExcludedDeviceNames(InputStream xml) throws Exception { + List<String> names = new ArrayList<>(); + try (InputStreamReader confReader = new InputStreamReader(xml)) { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(confReader); + XmlUtils.beginDocument(parser, "devices"); + while (true) { + XmlUtils.nextElement(parser); + if (!"device".equals(parser.getName())) { + break; + } + String name = parser.getAttributeValue(null, "name"); + if (name != null) { + names.add(name); + } + } + } + return names; + } + + /** + * Parse the configuration for input port associations. + * + * Configuration format: + * <code> + * <ports> + * <port display="0" input="usb-xhci-hcd.0.auto-1.4.3/input0" /> + * <port display="1" input="usb-xhci-hcd.0.auto-1.4.2/input0" /> + * </ports> + * </code> + * + * In this example, any input device that has physical port of + * "usb-xhci-hcd.0.auto-1.4.3/input0" will be associated with a display + * that has the physical port "0". If such a display does not exist, the input device + * will be disabled and no input events will be dispatched from that input device until a + * matching display appears. Likewise, an input device that has port "..1.4.2.." will have + * its input events forwarded to a display that has physical port of "1". + * + * Note: display port must be a numeric value, and this is checked at runtime for validity. + * At the same time, it is specified as a string for simplicity. + * + * Note: do not confuse "display id" with "display port". + * The "display port" is the physical port on which the display is connected. This could + * be something like HDMI0, HDMI1, etc. For virtual displays, "display port" will be null. + * The "display id" is a way to identify a particular display, and is not a stable API. + * All displays, including virtual ones, will have a display id. + * + * Return the pairs of associations. The first item in the pair is the input port, + * the second item in the pair is the display port. + */ + @VisibleForTesting + static List<Pair<String, String>> processInputPortAssociations(InputStream xml) + throws Exception { + List<Pair<String, String>> associations = new ArrayList<>(); + try (InputStreamReader confReader = new InputStreamReader(xml)) { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(confReader); + XmlUtils.beginDocument(parser, "ports"); + + while (true) { + XmlUtils.nextElement(parser); + String entryName = parser.getName(); + if (!"port".equals(entryName)) { + break; + } + String inputPort = parser.getAttributeValue(null, "input"); + String displayPort = parser.getAttributeValue(null, "display"); + if (TextUtils.isEmpty(inputPort) || TextUtils.isEmpty(displayPort)) { + // This is likely an error by an OEM during device configuration + Slog.wtf(TAG, "Ignoring incomplete entry"); + continue; + } + try { + Integer.parseUnsignedInt(displayPort); + } catch (NumberFormatException e) { + Slog.wtf(TAG, "Display port should be an integer"); + continue; + } + associations.add(new Pair<>(inputPort, displayPort)); + } + } + return associations; + } +} diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 3339a49c5ed0..d96b6cba119b 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -64,18 +64,18 @@ import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; -import android.util.Xml; import android.view.Display; import android.view.IInputFilter; import android.view.IInputFilterHost; import android.view.IWindow; -import android.view.InputChannel; import android.view.InputApplicationHandle; -import android.view.InputWindowHandle; +import android.view.InputChannel; import android.view.InputDevice; import android.view.InputEvent; +import android.view.InputWindowHandle; import android.view.KeyEvent; import android.view.PointerIcon; import android.view.Surface; @@ -97,14 +97,13 @@ import com.android.server.policy.WindowManagerPolicy; import libcore.io.IoUtils; import libcore.io.Streams; -import org.xmlpull.v1.XmlPullParser; - import java.io.File; import java.io.FileDescriptor; +import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.ArrayList; @@ -124,6 +123,7 @@ public class InputManagerService extends IInputManager.Stub static final boolean DEBUG = false; private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; + private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml"; private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1; private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2; @@ -1852,11 +1852,9 @@ public class InputManagerService extends IInputManager.Stub } // Native callback. - private String[] getExcludedDeviceNames() { - ArrayList<String> names = new ArrayList<String>(); - + private static String[] getExcludedDeviceNames() { + List<String> names = new ArrayList<>(); // Read partner-provided list of excluded input devices - XmlPullParser parser = null; // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". final File[] baseDirs = { Environment.getRootDirectory(), @@ -1864,33 +1862,52 @@ public class InputManagerService extends IInputManager.Stub }; for (File baseDir: baseDirs) { File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH); - FileReader confreader = null; try { - confreader = new FileReader(confFile); - parser = Xml.newPullParser(); - parser.setInput(confreader); - XmlUtils.beginDocument(parser, "devices"); - - while (true) { - XmlUtils.nextElement(parser); - if (!"device".equals(parser.getName())) { - break; - } - String name = parser.getAttributeValue(null, "name"); - if (name != null) { - names.add(name); - } - } + InputStream stream = new FileInputStream(confFile); + names.addAll(ConfigurationProcessor.processExcludedDeviceNames(stream)); } catch (FileNotFoundException e) { // It's ok if the file does not exist. } catch (Exception e) { - Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e); - } finally { - try { if (confreader != null) confreader.close(); } catch (IOException e) { } + Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e); } } + return names.toArray(new String[0]); + } + + /** + * Flatten a list of pairs into a list, with value positioned directly next to the key + * @return Flattened list + */ + private static <T> List<T> flatten(@NonNull List<Pair<T, T>> pairs) { + List<T> list = new ArrayList<>(pairs.size() * 2); + for (Pair<T, T> pair : pairs) { + list.add(pair.first); + list.add(pair.second); + } + return list; + } + + /** + * Ports are highly platform-specific, so only allow these to be specified in the vendor + * directory. + */ + // Native callback + private static String[] getInputPortAssociations() { + File baseDir = Environment.getVendorDirectory(); + File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH); - return names.toArray(new String[names.size()]); + try { + InputStream stream = new FileInputStream(confFile); + List<Pair<String, String>> associations = + ConfigurationProcessor.processInputPortAssociations(stream); + List<String> associationList = flatten(associations); + return associationList.toArray(new String[0]); + } catch (FileNotFoundException e) { + // Most of the time, file will not exist, which is expected. + } catch (Exception e) { + Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e); + } + return new String[0]; } // Native callback. diff --git a/services/core/java/com/android/server/location/gps_debug.conf b/services/core/java/com/android/server/location/gps_debug.conf new file mode 100644 index 000000000000..34ce96f3c8b3 --- /dev/null +++ b/services/core/java/com/android/server/location/gps_debug.conf @@ -0,0 +1,52 @@ +# Sample file for use for on device debug override only +# Prefer frameworks/base/core/res/res/values/config.xml and +# frameworks/base/core/res/res/values-mcc*-mnc*/config.xml + +################################ +##### AGPS server settings ##### +################################ +# FOR SUPL SUPPORT, set the following +# SUPL_HOST=supl.google.com or IP +# SUPL_PORT=7275 + +# supl version 2.0 +# SUPL_VER=0x20000 + +#SUPL_MODE is a bit mask set in config.xml per carrier by default. +#If it is uncommented here, this value will overwrite the value from +#config.xml. +#MSA=0X2 +#MSB=0X1 +#SUPL_MODE=1 + +# Emergency SUPL, 1=enable, 0=disable +#SUPL_ES=0 + +#Choose PDN for Emergency SUPL +#1 - Use emergency PDN +#0 - Use regular SUPL PDN for Emergency SUPL +#USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=0 + +#################################### +# LTE Positioning Profile Settings +#################################### +# 0: Enable RRLP on LTE(Default) +# 1: Enable LPP_User_Plane on LTE +# 2: Enable LPP_Control_Plane +# 3: Enable both LPP_User_Plane and LPP_Control_Plane +#LPP_PROFILE = 2 + +################################################## +# Select Positioning Protocol on A-GLONASS system +################################################## +# 0x1: RRC CPlane +# 0x2: RRLP UPlane +# 0x4: LLP Uplane +#A_GLONASS_POS_PROTOCOL_SELECT = 0 + +# Below bit mask configures how GPS functionalities +# should be locked when user turns off GPS on Settings +# Set bit 0x1 if MO GPS functionalities are to be locked +# Set bit 0x2 if NI GPS functionalities are to be locked +# default - non is locked for backward compatibility +#GPS_LOCK = 0 diff --git a/services/core/java/com/android/server/locksettings/SP800Derive.java b/services/core/java/com/android/server/locksettings/SP800Derive.java new file mode 100644 index 000000000000..77561fc30db9 --- /dev/null +++ b/services/core/java/com/android/server/locksettings/SP800Derive.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 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.locksettings; + +import java.nio.ByteBuffer; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +/** + * Implementation of NIST SP800-108 + * "Recommendation for Key Derivation Using Pseudorandom Functions" + * Hardcoded: + * [PRF=HMAC_SHA256] + * [CTRLOCATION=BEFORE_FIXED] + * [RLEN=32_BITS] + * L = 256 + * L suffix: 32 bits + */ +class SP800Derive { + private final byte[] mKeyBytes; + + SP800Derive(byte[] keyBytes) { + mKeyBytes = keyBytes; + } + + private Mac getMac() { + try { + final Mac m = Mac.getInstance("HmacSHA256"); + m.init(new SecretKeySpec(mKeyBytes, m.getAlgorithm())); + return m; + } catch (InvalidKeyException | NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + private static void update32(Mac m, int v) { + m.update(ByteBuffer.allocate(Integer.BYTES).putInt(v).array()); + } + + /** + * Generate output from a single, fixed input. + */ + public byte[] fixedInput(byte[] fixedInput) { + final Mac m = getMac(); + update32(m, 1); // Hardwired counter value + m.update(fixedInput); + return m.doFinal(); + } + + /** + * Generate output from a label and context. We add a length field at the end of the context to + * disambiguate it from the length even in the presence of zero bytes. + */ + public byte[] withContext(byte[] label, byte[] context) { + final Mac m = getMac(); + // Hardwired counter value: 1 + update32(m, 1); // Hardwired counter value + m.update(label); + m.update((byte) 0); + m.update(context); + update32(m, context.length * 8); // Disambiguate context + update32(m, 256); // Hardwired output length + return m.doFinal(); + } +} diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 596daeb1427b..d32c299074a9 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -26,9 +26,9 @@ import android.hardware.weaver.V1_0.WeaverConfig; import android.hardware.weaver.V1_0.WeaverReadResponse; import android.hardware.weaver.V1_0.WeaverReadStatus; import android.hardware.weaver.V1_0.WeaverStatus; -import android.security.GateKeeper; import android.os.RemoteException; import android.os.UserManager; +import android.security.GateKeeper; import android.service.gatekeeper.GateKeeperResponse; import android.service.gatekeeper.IGateKeeperService; import android.util.ArrayMap; @@ -102,7 +102,8 @@ public class SyntheticPasswordManager { private static final int INVALID_WEAVER_SLOT = -1; private static final byte SYNTHETIC_PASSWORD_VERSION_V1 = 1; - private static final byte SYNTHETIC_PASSWORD_VERSION = 2; + private static final byte SYNTHETIC_PASSWORD_VERSION_V2 = 2; + private static final byte SYNTHETIC_PASSWORD_VERSION_V3 = 3; private static final byte SYNTHETIC_PASSWORD_PASSWORD_BASED = 0; private static final byte SYNTHETIC_PASSWORD_TOKEN_BASED = 1; @@ -128,6 +129,8 @@ public class SyntheticPasswordManager { private static final byte[] PERSONALISATION_WEAVER_PASSWORD = "weaver-pwd".getBytes(); private static final byte[] PERSONALISATION_WEAVER_KEY = "weaver-key".getBytes(); private static final byte[] PERSONALISATION_WEAVER_TOKEN = "weaver-token".getBytes(); + private static final byte[] PERSONALISATION_CONTEXT = + "android-synthetic-password-personalization-context".getBytes(); static class AuthenticationResult { public AuthenticationToken authToken; @@ -136,6 +139,7 @@ public class SyntheticPasswordManager { } static class AuthenticationToken { + private final byte mVersion; /* * Here is the relationship between all three fields: * P0 and P1 are two randomly-generated blocks. P1 is stored on disk but P0 is not. @@ -146,29 +150,38 @@ public class SyntheticPasswordManager { private @Nullable byte[] P1; private @NonNull String syntheticPassword; + AuthenticationToken(byte version) { + mVersion = version; + } + + private byte[] derivePassword(byte[] personalization) { + if (mVersion == SYNTHETIC_PASSWORD_VERSION_V3) { + return (new SP800Derive(syntheticPassword.getBytes())) + .withContext(personalization, PERSONALISATION_CONTEXT); + } else { + return SyntheticPasswordCrypto.personalisedHash(personalization, + syntheticPassword.getBytes()); + } + } + public String deriveKeyStorePassword() { - return bytesToHex(SyntheticPasswordCrypto.personalisedHash( - PERSONALIZATION_KEY_STORE_PASSWORD, syntheticPassword.getBytes())); + return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD)); } public byte[] deriveGkPassword() { - return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_SP_GK_AUTH, - syntheticPassword.getBytes()); + return derivePassword(PERSONALIZATION_SP_GK_AUTH); } public byte[] deriveDiskEncryptionKey() { - return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_FBE_KEY, - syntheticPassword.getBytes()); + return derivePassword(PERSONALIZATION_FBE_KEY); } public byte[] deriveVendorAuthSecret() { - return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_AUTHSECRET_KEY, - syntheticPassword.getBytes()); + return derivePassword(PERSONALIZATION_AUTHSECRET_KEY); } public byte[] derivePasswordHashFactor() { - return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_PASSWORD_HASH, - syntheticPassword.getBytes()); + return derivePassword(PERSONALIZATION_PASSWORD_HASH); } private void initialize(byte[] P0, byte[] P1) { @@ -185,7 +198,7 @@ public class SyntheticPasswordManager { } protected static AuthenticationToken create() { - AuthenticationToken result = new AuthenticationToken(); + AuthenticationToken result = new AuthenticationToken(SYNTHETIC_PASSWORD_VERSION_V3); result.initialize(secureRandom(SYNTHETIC_PASSWORD_LENGTH), secureRandom(SYNTHETIC_PASSWORD_LENGTH)); return result; @@ -802,7 +815,16 @@ public class SyntheticPasswordManager { } byte[] content = createSPBlob(getHandleName(handle), secret, applicationId, sid); byte[] blob = new byte[content.length + 1 + 1]; - blob[0] = SYNTHETIC_PASSWORD_VERSION; + /* + * We can upgrade from v1 to v2 because that's just a change in the way that + * the SP is stored. However, we can't upgrade to v3 because that is a change + * in the way that passwords are derived from the SP. + */ + if (authToken.mVersion == SYNTHETIC_PASSWORD_VERSION_V3) { + blob[0] = SYNTHETIC_PASSWORD_VERSION_V3; + } else { + blob[0] = SYNTHETIC_PASSWORD_VERSION_V2; + } blob[1] = type; System.arraycopy(content, 0, blob, 2, content.length); saveState(SP_BLOB_NAME, blob, handle, userId); @@ -940,7 +962,9 @@ public class SyntheticPasswordManager { return null; } final byte version = blob[0]; - if (version != SYNTHETIC_PASSWORD_VERSION && version != SYNTHETIC_PASSWORD_VERSION_V1) { + if (version != SYNTHETIC_PASSWORD_VERSION_V3 + && version != SYNTHETIC_PASSWORD_VERSION_V2 + && version != SYNTHETIC_PASSWORD_VERSION_V1) { throw new RuntimeException("Unknown blob version"); } if (blob[1] != type) { @@ -958,7 +982,7 @@ public class SyntheticPasswordManager { Log.e(TAG, "Fail to decrypt SP for user " + userId); return null; } - AuthenticationToken result = new AuthenticationToken(); + AuthenticationToken result = new AuthenticationToken(version); if (type == SYNTHETIC_PASSWORD_TOKEN_BASED) { if (!loadEscrowData(result, userId)) { Log.e(TAG, "User is not escrowable: " + userId); diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 7750c3781067..0d6dadfb1ad8 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -554,7 +554,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final Handler mHandler; @VisibleForTesting - public final Handler mUidEventHandler; + final Handler mUidEventHandler; private final ServiceThread mUidEventThread; @@ -1465,7 +1465,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @VisibleForTesting - public void updateNetworks() throws InterruptedException { + void updateNetworks() throws InterruptedException { updateNetworksInternal(); final CountDownLatch latch = new CountDownLatch(1); mHandler.post(() -> { @@ -1510,7 +1510,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * @return cycleDay to use in the mobile NetworkPolicy. */ @VisibleForTesting - public int getCycleDayFromCarrierConfig(@Nullable PersistableBundle config, + int getCycleDayFromCarrierConfig(@Nullable PersistableBundle config, int fallbackCycleDay) { if (config == null) { return fallbackCycleDay; @@ -1542,7 +1542,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * @return warningBytes to use in the mobile NetworkPolicy. */ @VisibleForTesting - public long getWarningBytesFromCarrierConfig(@Nullable PersistableBundle config, + long getWarningBytesFromCarrierConfig(@Nullable PersistableBundle config, long fallbackWarningBytes) { if (config == null) { return fallbackWarningBytes; @@ -1575,7 +1575,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * @return limitBytes to use in the mobile NetworkPolicy. */ @VisibleForTesting - public long getLimitBytesFromCarrierConfig(@Nullable PersistableBundle config, + long getLimitBytesFromCarrierConfig(@Nullable PersistableBundle config, long fallbackLimitBytes) { if (config == null) { return fallbackLimitBytes; @@ -2039,7 +2039,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @VisibleForTesting - public NetworkPolicy buildDefaultMobilePolicy(int subId, String subscriberId) { + NetworkPolicy buildDefaultMobilePolicy(int subId, String subscriberId) { final NetworkTemplate template = buildTemplateMobileAll(subscriberId); final RecurrenceRule cycleRule = NetworkPolicy .buildRule(ZonedDateTime.now().getDayOfMonth(), ZoneId.systemDefault()); @@ -3489,7 +3489,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @VisibleForTesting - public boolean isUidForeground(int uid) { + boolean isUidForeground(int uid) { synchronized (mUidRulesFirstLock) { return isUidStateForeground( mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY)); @@ -3931,7 +3931,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * power saving restrictions may still apply. */ @VisibleForTesting - public void setAppIdleWhitelist(int uid, boolean shouldWhitelist) { + void setAppIdleWhitelist(int uid, boolean shouldWhitelist) { + mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); + synchronized (mUidRulesFirstLock) { if (mAppIdleTempWhitelistAppIds.get(uid) == shouldWhitelist) { // No change. @@ -3956,7 +3958,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Return the list of UIDs currently in the app idle whitelist. */ @VisibleForTesting - public int[] getAppIdleWhitelist() { + int[] getAppIdleWhitelist() { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); synchronized (mUidRulesFirstLock) { @@ -3971,7 +3973,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Returns if the UID is currently considered idle. */ @VisibleForTesting - public boolean isUidIdle(int uid) { + boolean isUidIdle(int uid) { synchronized (mUidRulesFirstLock) { if (mAppIdleTempWhitelistAppIds.get(uid)) { // UID is temporarily whitelisted. @@ -4844,13 +4846,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @VisibleForTesting - public void addIdleHandler(IdleHandler handler) { + void addIdleHandler(IdleHandler handler) { mHandler.getLooper().getQueue().addIdleHandler(handler); } @GuardedBy("mUidRulesFirstLock") @VisibleForTesting - public void updateRestrictBackgroundByLowPowerModeUL(final PowerSaveState result) { + void updateRestrictBackgroundByLowPowerModeUL(final PowerSaveState result) { mRestrictBackgroundPowerState = result; boolean restrictBackground = result.batterySaverEnabled; diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index 9222740e0506..84bb13ec92d3 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -16,6 +16,7 @@ package com.android.server.notification; +import android.app.Notification; import android.service.notification.NotificationStats; import com.android.internal.statusbar.NotificationVisibility; @@ -26,7 +27,7 @@ public interface NotificationDelegate { void onNotificationClick(int callingUid, int callingPid, String key, NotificationVisibility nv); void onNotificationActionClick(int callingUid, int callingPid, String key, int actionIndex, - NotificationVisibility nv); + Notification.Action action, NotificationVisibility nv, boolean generatedByAssistant); void onNotificationClear(int callingUid, int callingPid, String pkg, String tag, int id, int userId, String key, @NotificationStats.DismissalSurface int dismissalSurface, diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 60058724e9a7..ae27d0c07ea8 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -752,7 +752,8 @@ public class NotificationManagerService extends SystemService { @Override public void onNotificationActionClick(int callingUid, int callingPid, String key, - int actionIndex, NotificationVisibility nv) { + int actionIndex, Notification.Action action, NotificationVisibility nv, + boolean generatedByAssistant) { exitIdle(); synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); @@ -772,6 +773,8 @@ public class NotificationManagerService extends SystemService { nv.rank, nv.count); nv.recycle(); reportUserInteraction(r); + mAssistants.notifyAssistantActionClicked( + r.sbn, actionIndex, action, generatedByAssistant); } } @@ -6923,6 +6926,27 @@ public class NotificationManagerService extends SystemService { }); } + @GuardedBy("mNotificationLock") + void notifyAssistantActionClicked( + final StatusBarNotification sbn, int actionIndex, Notification.Action action, + boolean generatedByAssistant) { + final String key = sbn.getKey(); + notifyAssistantLocked( + sbn, + false /* sameUserOnly */, + (assistant, sbnHolder) -> { + try { + assistant.onActionClicked( + key, + action, + generatedByAssistant + ? NotificationAssistantService.SOURCE_FROM_ASSISTANT + : NotificationAssistantService.SOURCE_FROM_APP); + } catch (RemoteException ex) { + Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex); + } + }); + } /** * asynchronously notify the assistant that a notification has been snoozed until a diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index f279af03753e..94d276c8496d 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -309,6 +309,7 @@ public class ZenModeHelper { newConfig = mConfig.copy(); ZenRule rule = new ZenRule(); populateZenRule(automaticZenRule, rule, true); + newConfig.automaticRules.put(rule.id, rule); if (setConfigLocked(newConfig, reason, rule.component, true)) { return rule.id; } else { diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index b4903817f787..7f1fb6c97e39 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -310,7 +310,7 @@ public class LauncherAppsService extends SystemService { .setPackage(packageName), user); if (Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 0) == 0) { + Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 1) == 0) { return launcherActivities; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c708b0af321f..c125e9719ed0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -15246,7 +15246,8 @@ public class PackageManagerService extends IPackageManager.Stub "inputs not balanced; missing argument for " + installPackageName); } final DeletePackageAction deletePackageAction; - if (prepareResult.replace) { + // we only want to try to delete for non system apps + if (prepareResult.replace && !prepareResult.system) { deletePackageAction = mayDeletePackageLocked(res.removedInfo, prepareResult.originalPs, prepareResult.disabledPs, prepareResult.childPackageSettings); @@ -17818,7 +17819,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } if (isSystemApp(ps)) { - if (ps.parentPackageName == null) { + if (ps.parentPackageName != null) { Slog.w(TAG, "Attempt to delete child system package " + ps.pkg.packageName); return null; } @@ -23594,6 +23595,30 @@ public class PackageManagerService extends IPackageManager.Stub return mProtectedPackages.isPackageStateProtected(userId, packageName); } + @Override + public void sendDeviceCustomizationReadyBroadcast() { + mContext.enforceCallingPermission(Manifest.permission.SEND_DEVICE_CUSTOMIZATION_READY, + "sendDeviceCustomizationReadyBroadcast"); + + final long ident = Binder.clearCallingIdentity(); + try { + final Intent intent = new Intent(Intent.ACTION_DEVICE_CUSTOMIZATION_READY); + intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + final IActivityManager am = ActivityManager.getService(); + final String[] requiredPermissions = { + Manifest.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY, + }; + try { + am.broadcastIntent(null, intent, null, null, 0, null, null, requiredPermissions, + android.app.AppOpsManager.OP_NONE, null, false, false, UserHandle.USER_ALL); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + static class ActiveInstallSession { private final String mPackageName; private final File mStagedDir; diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index e194d1541ea7..2d583ca39adb 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -105,6 +105,8 @@ public final class BasePermission { */ private boolean perUser; + boolean usageInfoRequired; + public BasePermission(String _name, String _sourcePackageName, @PermissionType int _type) { name = _name; sourcePackageName = _sourcePackageName; @@ -351,6 +353,7 @@ public final class BasePermission { } if (bp.perm == p) { bp.protectionLevel = p.info.protectionLevel; + bp.usageInfoRequired = p.info.usageInfoRequired; } if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { Log.d(TAG, " Permissions: " + r); @@ -430,6 +433,7 @@ public final class BasePermission { permissionInfo.packageName = sourcePackageName; permissionInfo.nonLocalizedLabel = name; permissionInfo.protectionLevel = protectionLevel; + permissionInfo.usageInfoRequired = usageInfoRequired; return permissionInfo; } @@ -458,6 +462,7 @@ public final class BasePermission { bp.protectionLevel = readInt(parser, null, "protection", PermissionInfo.PROTECTION_NORMAL); bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel); + bp.usageInfoRequired = readInt(parser, null, "usageInfoRequired", 0) != 0; if (dynamic) { final PermissionInfo pi = new PermissionInfo(); pi.packageName = sourcePackage.intern(); @@ -465,6 +470,7 @@ public final class BasePermission { pi.icon = readInt(parser, null, "icon", 0); pi.nonLocalizedLabel = parser.getAttributeValue(null, "label"); pi.protectionLevel = bp.protectionLevel; + pi.usageInfoRequired = bp.usageInfoRequired; bp.pendingPermissionInfo = pi; } out.put(bp.name, bp); @@ -497,6 +503,7 @@ public final class BasePermission { if (protectionLevel != PermissionInfo.PROTECTION_NORMAL) { serializer.attribute(null, "protection", Integer.toString(protectionLevel)); } + serializer.attribute(null, "usageInfoRequired", usageInfoRequired ? "1" : "0"); if (type == BasePermission.TYPE_DYNAMIC) { final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo; if (pi != null) { @@ -533,6 +540,7 @@ public final class BasePermission { if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false; // We'll take care of setting this one. if (!compareStrings(pi1.packageName, pi2.packageName)) return false; + if (pi1.usageInfoRequired != pi2.usageInfoRequired) return false; // These are not currently stored in settings. //if (!compareStrings(pi1.group, pi2.group)) return false; //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false; @@ -580,6 +588,8 @@ public final class BasePermission { pw.print(" enforced="); pw.println(readEnforced); } + pw.print(" usageInfoRequired="); + pw.println(usageInfoRequired); return true; } } diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 21cc14e20bc7..e9b9930600a0 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -144,6 +144,11 @@ public final class DefaultPermissionGrantPolicy { LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION); } + private static final Set<String> ACTIVITY_RECOGNITION_PERMISSIONS = new ArraySet<>(); + static { + ACTIVITY_RECOGNITION_PERMISSIONS.add(Manifest.permission.ACTIVITY_RECOGNITION); + } + private static final Set<String> COARSE_LOCATION_PERMISSIONS = new ArraySet<>(); static { COARSE_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION); @@ -624,7 +629,7 @@ public final class DefaultPermissionGrantPolicy { PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS, SENSORS_PERMISSIONS, STORAGE_PERMISSIONS); grantSystemFixedPermissionsToSystemPackage(packageName, userId, - LOCATION_PERMISSIONS); + LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS); } } diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index 4124210b27cb..b390eebf3d7e 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -30,6 +30,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManagerInternal; import android.text.TextUtils; @@ -42,6 +44,7 @@ import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemService; +import java.io.FileDescriptor; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -334,5 +337,13 @@ public class RoleManagerService extends SystemService { return ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId, false, true, name, null); } + + @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { + (new RoleManagerShellCommand(this)).exec( + this, in, out, err, args, callback, resultReceiver); + } } } diff --git a/services/core/java/com/android/server/role/RoleManagerShellCommand.java b/services/core/java/com/android/server/role/RoleManagerShellCommand.java new file mode 100644 index 000000000000..e1977ef083b4 --- /dev/null +++ b/services/core/java/com/android/server/role/RoleManagerShellCommand.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 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.role; + +import android.app.role.IRoleManager; +import android.app.role.IRoleManagerCallback; +import android.os.RemoteException; +import android.os.ShellCommand; +import android.os.UserHandle; + +import java.io.PrintWriter; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +class RoleManagerShellCommand extends ShellCommand { + private final IRoleManager mRoleManager; + + RoleManagerShellCommand(IRoleManager roleManager) { + mRoleManager = roleManager; + } + + private class Callback extends IRoleManagerCallback.Stub { + private final CompletableFuture<Void> mResult = new CompletableFuture<>(); + + public int waitForResult() { + try { + mResult.get(5, TimeUnit.SECONDS); + return 0; + } catch (Exception e) { + getErrPrintWriter().println("Error: " + e.toString()); + return -1; + } + } + + @Override + public void onSuccess() { + mResult.complete(null); + } + + @Override + public void onFailure() { + mResult.completeExceptionally(new RuntimeException("Failed")); + } + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + + PrintWriter pw = getOutPrintWriter(); + try { + switch (cmd) { + case "add-role-holder": + return runAddRoleHolder(); + case "remove-role-holder": + return runRemoveRoleHolder(); + case "clear-role-holders": + return runClearRoleHolders(); + default: + return handleDefaultCommands(cmd); + } + } catch (RemoteException e) { + pw.println("Remote exception: " + e); + } + return -1; + } + + private int getUserIdMaybe() { + int userId = UserHandle.USER_SYSTEM; + String option = getNextOption(); + if (option != null && option.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } + return userId; + } + + private int runAddRoleHolder() throws RemoteException { + int userId = getUserIdMaybe(); + String roleName = getNextArgRequired(); + String packageName = getNextArgRequired(); + + Callback callback = new Callback(); + mRoleManager.addRoleHolderAsUser(roleName, packageName, userId, callback); + return callback.waitForResult(); + } + + private int runRemoveRoleHolder() throws RemoteException { + int userId = getUserIdMaybe(); + String roleName = getNextArgRequired(); + String packageName = getNextArgRequired(); + + Callback callback = new Callback(); + mRoleManager.removeRoleHolderAsUser(roleName, packageName, userId, callback); + return callback.waitForResult(); + } + + private int runClearRoleHolders() throws RemoteException { + int userId = getUserIdMaybe(); + String roleName = getNextArgRequired(); + + Callback callback = new Callback(); + mRoleManager.clearRoleHoldersAsUser(roleName, userId, callback); + return callback.waitForResult(); + } + + @Override + public void onHelp() { + PrintWriter pw = getOutPrintWriter(); + pw.println("Role manager (role) commands:"); + pw.println(" help"); + pw.println(" Print this help text."); + pw.println(); + pw.println(" add-role-holder [--user USER_ID] ROLE PACKAGE"); + pw.println(" remove-role-holder [--user USER_ID] ROLE PACKAGE"); + pw.println(" clear-role-holders [--user USER_ID] ROLE"); + pw.println(); + } +} diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 361622fd2934..0d66a2c8b442 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -19,6 +19,7 @@ package com.android.server.statusbar; import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS; import android.app.ActivityThread; +import android.app.Notification; import android.app.StatusBarManager; import android.content.ComponentName; import android.content.Context; @@ -1080,14 +1081,16 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override - public void onNotificationActionClick(String key, int actionIndex, NotificationVisibility nv) { + public void onNotificationActionClick( + String key, int actionIndex, Notification.Action action, NotificationVisibility nv, + boolean generatedByAssistant) { enforceStatusBarService(); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key, - actionIndex, nv); + actionIndex, action, nv, generatedByAssistant); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java index 6a0b6489f470..9d6a64701e85 100644 --- a/services/core/java/com/android/server/storage/AppFuseBridge.java +++ b/services/core/java/com/android/server/storage/AppFuseBridge.java @@ -16,6 +16,7 @@ package com.android.server.storage; +import android.os.FileUtils; import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import android.system.Os; @@ -25,8 +26,6 @@ import com.android.internal.os.FuseUnavailableMountException; import com.android.internal.util.Preconditions; import com.android.server.NativeDaemonConnectorException; import libcore.io.IoUtils; -import java.io.File; -import java.io.FileNotFoundException; import java.util.concurrent.CountDownLatch; /** @@ -87,7 +86,7 @@ public class AppFuseBridge implements Runnable { } } - public ParcelFileDescriptor openFile(int pid, int mountId, int fileId, int mode) + public ParcelFileDescriptor openFile(int mountId, int fileId, int mode) throws FuseUnavailableMountException, InterruptedException { final MountScope scope; synchronized (this) { @@ -96,17 +95,14 @@ public class AppFuseBridge implements Runnable { throw new FuseUnavailableMountException(mountId); } } - if (scope.pid != pid) { - throw new SecurityException("PID does not match"); - } final boolean result = scope.waitForMount(); if (result == false) { throw new FuseUnavailableMountException(mountId); } try { - return ParcelFileDescriptor.open( - new File(scope.mountPoint, String.valueOf(fileId)), mode); - } catch (FileNotFoundException error) { + int flags = FileUtils.translateModePfdToPosix(mode); + return scope.openFile(mountId, fileId, flags); + } catch (NativeDaemonConnectorException error) { throw new FuseUnavailableMountException(mountId); } } @@ -131,17 +127,13 @@ public class AppFuseBridge implements Runnable { public static abstract class MountScope implements AutoCloseable { public final int uid; - public final int pid; public final int mountId; - public final File mountPoint; private final CountDownLatch mMounted = new CountDownLatch(1); private boolean mMountResult = false; - public MountScope(int uid, int pid, int mountId) { + public MountScope(int uid, int mountId) { this.uid = uid; - this.pid = pid; this.mountId = mountId; - this.mountPoint = new File(String.format(APPFUSE_MOUNT_NAME_TEMPLATE, uid, mountId)); } @GuardedBy("AppFuseBridge.this") @@ -159,6 +151,8 @@ public class AppFuseBridge implements Runnable { } public abstract ParcelFileDescriptor open() throws NativeDaemonConnectorException; + public abstract ParcelFileDescriptor openFile(int mountId, int fileId, int flags) + throws NativeDaemonConnectorException; } private native long native_new(); diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index 8d27d1e043a7..c8a68b44c796 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -402,7 +402,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { try { final int uid = context.getPackageManager() - .getPackageUid(packageName, 0); + .getPackageUidAsUser(packageName, UserHandle.getCallingUserId()); Preconditions.checkArgument(Binder.getCallingUid() == uid); } catch (IllegalArgumentException | NullPointerException | PackageManager.NameNotFoundException e) { diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 6ede423f63c8..cfec8effeede 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1181,7 +1181,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // TODO(multi-display) TBD. if (mInfo != null && mInfo.supportsAmbientMode() && displayId == DEFAULT_DISPLAY) { try { - connector.mEngine.setInAmbientMode(mInAmbientMode, false /* animated */); + connector.mEngine.setInAmbientMode(mInAmbientMode, 0L /* duration */); } catch (RemoteException e) { Slog.w(TAG, "Failed to set ambient mode state", e); } @@ -2023,11 +2023,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - // TODO(b/115486823) Extends this method with specific display. - public void setInAmbientMode(boolean inAmbienMode, boolean animated) { + /** + * TODO(b/115486823) Extends this method with specific display. + * Propagate ambient state to wallpaper engine. + * + * @param inAmbientMode {@code true} when in ambient mode, {@code false} otherwise. + * @param animationDuration Duration of the animation, or 0 when immediate. + */ + public void setInAmbientMode(boolean inAmbientMode, long animationDuration) { final IWallpaperEngine engine; synchronized (mLock) { - mInAmbientMode = inAmbienMode; + mInAmbientMode = inAmbientMode; final WallpaperData data = mWallpaperMap.get(mCurrentUserId); if (data != null && data.connection != null && data.connection.mInfo != null && data.connection.mInfo.supportsAmbientMode()) { @@ -2040,7 +2046,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (engine != null) { try { - engine.setInAmbientMode(inAmbienMode, animated); + engine.setInAmbientMode(inAmbientMode, animationDuration); } catch (RemoteException e) { // Cannot talk to wallpaper engine. } @@ -2344,7 +2350,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return false; } if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) { - String msg = "Selected service does not require " + String msg = "Selected service does not have " + android.Manifest.permission.BIND_WALLPAPER + ": " + componentName; if (fromUser) { @@ -2396,6 +2402,22 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + if (wi != null && wi.supportsAmbientMode()) { + final int hasPrivilege = mIPackageManager.checkPermission( + android.Manifest.permission.AMBIENT_WALLPAPER, wi.getPackageName(), + serviceUserId); + if (hasPrivilege != PackageManager.PERMISSION_GRANTED) { + String msg = "Selected service does not have " + + android.Manifest.permission.AMBIENT_WALLPAPER + + ": " + componentName; + if (fromUser) { + throw new SecurityException(msg); + } + Slog.w(TAG, msg); + return false; + } + } + // Bind the service! if (DEBUG) Slog.v(TAG, "Binding to:" + componentName); final int componentUid = mIPackageManager.getPackageUid(componentName.getPackageName(), diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index e4d1cfe943a8..fe0b5c250da8 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -16,9 +16,9 @@ package com.android.server.wm; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -706,7 +706,7 @@ final class AccessibilityController { mWindowManager.getDefaultDisplay().getRealSize(mTempPoint); surfaceControl = mService.getDefaultDisplayContentLocked().makeOverlay() .setName(SURFACE_TITLE) - .setSize(mTempPoint.x, mTempPoint.y) // not a typo + .setBufferSize(mTempPoint.x, mTempPoint.y) // not a typo .setFormat(PixelFormat.TRANSLUCENT) .build(); } catch (OutOfResourcesException oore) { @@ -784,7 +784,7 @@ final class AccessibilityController { public void updateSize() { synchronized (mService.mGlobalLock) { mWindowManager.getDefaultDisplay().getRealSize(mTempPoint); - mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y); + mSurfaceControl.setBufferSize(mTempPoint.x, mTempPoint.y); invalidate(mDirtyRect); } } diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index 33584d4a1710..84750b385d97 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -181,6 +181,11 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> mWindowContainerController.onDisplayChanged(); } + @Override + public void onInitializeOverrideConfiguration(Configuration config) { + getOverrideConfiguration().updateFrom(config); + } + void addChild(ActivityStack stack, int position) { if (position == POSITION_BOTTOM) { position = 0; diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java index e3133efb890c..eff0f75466d9 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java @@ -42,7 +42,7 @@ import java.lang.annotation.RetentionPolicy; * It must then transition to either {@code CANCELLED} with {@link #onActivityLaunchCancelled} * or into {@code FINISHED} with {@link #onActivityLaunchFinished}. These are terminal states. * - * Note that the {@link ActivityRecord} provided as a parameter to some state transitions isn't + * Note that the {@code ActivityRecordProto} provided as a parameter to some state transitions isn't * necessarily the same within a single launch sequence: it is only the top-most activity at the * time (if any). Trampoline activities coalesce several activity starts into a single launch * sequence. @@ -94,6 +94,14 @@ public interface ActivityMetricsLaunchObserver { public static final int TEMPERATURE_HOT = 3; /** + * Typedef marker that a {@code byte[]} actually contains an + * <a href="proto/android/server/activitymanagerservice.proto">ActivityRecordProto</a> + * in the protobuf format. + */ + @Retention(RetentionPolicy.SOURCE) + @interface ActivityRecordProto {} + + /** * Notifies the observer that a new launch sequence has begun as a result of a new intent. * * Once a launch sequence begins, the resolved activity will either subsequently start with @@ -135,7 +143,7 @@ public interface ActivityMetricsLaunchObserver { * Multiple calls to this method cannot occur without first terminating the current * launch sequence. */ - public void onActivityLaunched(@NonNull ActivityRecord activity, + public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity, @Temperature int temperature); /** @@ -157,7 +165,7 @@ public interface ActivityMetricsLaunchObserver { * in the case of a trampoline, multiple activities could've been started * and only the latest activity is reported here. */ - public void onActivityLaunchCancelled(@Nullable ActivityRecord abortingActivity); + public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] abortingActivity); /** * Notifies the observer that the current launch sequence has been successfully finished. @@ -178,5 +186,5 @@ public interface ActivityMetricsLaunchObserver { * and only the latest activity that was top-most during first-frame drawn * is reported here. */ - public void onActivityLaunchFinished(@NonNull ActivityRecord finalActivity); + public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] finalActivity); } diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserverRegistry.java b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserverRegistry.java new file mode 100644 index 000000000000..fa90dc5b83f4 --- /dev/null +++ b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserverRegistry.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 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.annotation.NonNull; + +/** + * Multi-cast delegate implementation for {@link ActivityMetricsLaunchObserver}. + * + * <br/><br/> + * This enables multiple launch observers to subscribe to {@link ActivityMetricsLogger} + * independently of each other. + * + * <br/><br/> + * Some callbacks in {@link ActivityMetricsLaunchObserver} have a {@code byte[]} + * parameter; this array is reused by all the registered observers, so it must not be written to + * (i.e. all observers must treat any array parameters as immutable). + * + * <br /><br /> + * Multi-cast invocations occurs sequentially in-order of registered observers. + */ +public interface ActivityMetricsLaunchObserverRegistry { + /** + * Register an extra launch observer to receive the multi-cast. + * + * <br /><br /> + * Multi-cast invocation happens in the same order the observers were registered. For example, + * <pre> + * registerLaunchObserver(A) + * registerLaunchObserver(B) + * + * obs.onIntentFailed() -> + * A.onIntentFailed() + * B.onIntentFailed() + * </pre> + */ + void registerLaunchObserver(@NonNull ActivityMetricsLaunchObserver launchObserver); + + /** + * Unregister an existing launch observer. It will not receive the multi-cast in the future. + * + * <br /><br /> + * This does nothing if this observer was not already registered. + */ + void unregisterLaunchObserver(@NonNull ActivityMetricsLaunchObserver launchObserver); +} diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 416e133ea14a..16df52d4ef65 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -99,10 +99,12 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.util.StatsLog; import android.util.TimeUtils; +import android.util.proto.ProtoOutputStream; import com.android.internal.logging.MetricsLogger; import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; /** @@ -168,7 +170,8 @@ class ActivityMetricsLogger { * Due to the global single concurrent launch sequence, all calls to this observer must be made * in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver. */ - private final ActivityMetricsLaunchObserver mLaunchObserver = null; + private final LaunchObserverRegistryImpl mLaunchObserver; + @VisibleForTesting static final int LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE = 512; private final class H extends Handler { @@ -263,6 +266,7 @@ class ActivityMetricsLogger { mSupervisor = supervisor; mContext = context; mHandler = new H(looper); + mLaunchObserver = new LaunchObserverRegistryImpl(looper); } void logWindowState() { @@ -1000,12 +1004,19 @@ class ActivityMetricsLogger { } } + public ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry() { + return mLaunchObserver; + } + /** Notify the {@link ActivityMetricsLaunchObserver} that a new launch sequence has begun. */ private void launchObserverNotifyIntentStarted(Intent intent) { - if (mLaunchObserver != null) { - // Beginning a launch is timing sensitive and so should be observed as soon as possible. - mLaunchObserver.onIntentStarted(intent); - } + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, + "MetricsLogger:launchObserverNotifyIntentStarted"); + + // Beginning a launch is timing sensitive and so should be observed as soon as possible. + mLaunchObserver.onIntentStarted(intent); + + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } /** @@ -1014,9 +1025,12 @@ class ActivityMetricsLogger { * intent being delivered to the top running activity. */ private void launchObserverNotifyIntentFailed() { - if (mLaunchObserver != null) { - mLaunchObserver.onIntentFailed(); - } + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, + "MetricsLogger:launchObserverNotifyIntentFailed"); + + mLaunchObserver.onIntentFailed(); + + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } /** @@ -1024,14 +1038,17 @@ class ActivityMetricsLogger { * has started. */ private void launchObserverNotifyActivityLaunched(WindowingModeTransitionInfo info) { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, + "MetricsLogger:launchObserverNotifyActivityLaunched"); + @ActivityMetricsLaunchObserver.Temperature int temperature = convertTransitionTypeToLaunchObserverTemperature(getTransitionType(info)); - if (mLaunchObserver != null) { - // Beginning a launch is timing sensitive and so should be observed as soon as possible. - mLaunchObserver.onActivityLaunched(info.launchedActivity, - temperature); - } + // Beginning a launch is timing sensitive and so should be observed as soon as possible. + mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.launchedActivity), + temperature); + + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } /** @@ -1039,11 +1056,15 @@ class ActivityMetricsLogger { * cancelled. */ private void launchObserverNotifyActivityLaunchCancelled(WindowingModeTransitionInfo info) { - final ActivityRecord launchedActivity = info != null ? info.launchedActivity : null; + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, + "MetricsLogger:launchObserverNotifyActivityLaunchCancelled"); - if (mLaunchObserver != null) { - mLaunchObserver.onActivityLaunchCancelled(launchedActivity); - } + final @ActivityMetricsLaunchObserver.ActivityRecordProto byte[] activityRecordProto = + info != null ? convertActivityRecordToProto(info.launchedActivity) : null; + + mLaunchObserver.onActivityLaunchCancelled(activityRecordProto); + + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } /** @@ -1051,11 +1072,34 @@ class ActivityMetricsLogger { * has fully finished (successfully). */ private void launchObserverNotifyActivityLaunchFinished(WindowingModeTransitionInfo info) { - final ActivityRecord launchedActivity = info.launchedActivity; + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, + "MetricsLogger:launchObserverNotifyActivityLaunchFinished"); - if (mLaunchObserver != null) { - mLaunchObserver.onActivityLaunchFinished(launchedActivity); - } + mLaunchObserver.onActivityLaunchFinished( + convertActivityRecordToProto(info.launchedActivity)); + + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + } + + @VisibleForTesting + static @ActivityMetricsLaunchObserver.ActivityRecordProto byte[] + convertActivityRecordToProto(ActivityRecord record) { + // May take non-negligible amount of time to convert ActivityRecord into a proto, + // so track the time. + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, + "MetricsLogger:convertActivityRecordToProto"); + + // There does not appear to be a way to 'reset' a ProtoOutputBuffer stream, + // so create a new one every time. + final ProtoOutputStream protoOutputStream = + new ProtoOutputStream(LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); + // Write this data out as the top-most ActivityRecordProto (i.e. it is not a sub-object). + record.writeToProto(protoOutputStream); + final byte[] bytes = protoOutputStream.getBytes(); + + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + + return bytes; } private static @ActivityMetricsLaunchObserver.Temperature int diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index eec22d5d1ee9..6f2461bd8489 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1105,6 +1105,8 @@ final class ActivityRecord extends ConfigurationContainer { } void removeWindowContainer() { + if (service.mWindowManager.mRoot == null) return; + final DisplayContent dc = service.mWindowManager.mRoot.getDisplayContent( getDisplayId()); if (dc == null) { @@ -3213,8 +3215,11 @@ final class ActivityRecord extends ConfigurationContainer { proto.end(token); } - public void writeToProto(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); + /** + * Write all fields to an {@code ActivityRecordProto}. This assumes the + * {@code ActivityRecordProto} is the outer-most proto data. + */ + void writeToProto(ProtoOutputStream proto) { super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */); writeIdentifierToProto(proto, IDENTIFIER); proto.write(STATE, mState.toString()); @@ -3224,6 +3229,11 @@ final class ActivityRecord extends ConfigurationContainer { proto.write(PROC_ID, app.getPid()); } proto.write(TRANSLUCENT, !fullscreen); + } + + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + writeToProto(proto); proto.end(token); } } diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 3162ee37276e..987c706b0c4e 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -434,7 +434,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mInitialized = true; mRunningTasks = createRunningTasks(); - mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext, mHandler.getLooper()); + + mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext, + mHandler.getLooper()); mKeyguardController = new KeyguardController(mService, this); mPersisterQueue = new PersisterQueue(); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index d6655928105e..0cdbedba7318 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -473,4 +473,6 @@ public abstract class ActivityTaskManagerInternal { public abstract void setProfileApp(String profileApp); public abstract void setProfileProc(WindowProcessController wpc); public abstract void setProfilerInfo(ProfilerInfo profilerInfo); + + public abstract ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry(); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 8f99dae89316..e1a1e6125104 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -4511,6 +4511,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mKeyguardController.isKeyguardLocked(); } + /** + * Clears launch params for the given package. + * @param packageNames the names of the packages of which the launch params are to be cleared + */ + @Override + public void clearLaunchParamsForPackages(List<String> packageNames) { + mAmInternal.enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS, + "clearLaunchParamsForPackages"); + synchronized (mGlobalLock) { + for (int i = 0; i < packageNames.size(); ++i) { + mStackSupervisor.mLaunchParamsPersister.removeRecordForPackage(packageNames.get(i)); + } + } + } + void dumpLastANRLocked(PrintWriter pw) { pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)"); if (mLastANRState == null) { @@ -6879,5 +6894,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mProfilerInfo = profilerInfo; } } + + @Override + public ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry() { + synchronized (mGlobalLock) { + return mStackSupervisor.getActivityMetricsLogger().getLaunchObserverRegistry(); + } + } } } diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java index 729f89bb2611..b9b9d31f5b71 100644 --- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java +++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java @@ -16,13 +16,13 @@ package com.android.server.wm; +import static com.android.server.wm.AppWindowThumbnailProto.HEIGHT; +import static com.android.server.wm.AppWindowThumbnailProto.SURFACE_ANIMATOR; +import static com.android.server.wm.AppWindowThumbnailProto.WIDTH; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION; -import static com.android.server.wm.AppWindowThumbnailProto.HEIGHT; -import static com.android.server.wm.AppWindowThumbnailProto.SURFACE_ANIMATOR; -import static com.android.server.wm.AppWindowThumbnailProto.WIDTH; import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; @@ -65,7 +65,7 @@ class AppWindowThumbnail implements Animatable { // this to the task. mSurfaceControl = appToken.makeSurface() .setName("thumbnail anim: " + appToken.toString()) - .setSize(mWidth, mHeight) + .setBufferSize(mWidth, mHeight) .setFormat(PixelFormat.TRANSLUCENT) .setMetadata(appToken.windowType, window != null ? window.mOwnerUid : Binder.getCallingUid()) diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index a7c9a4666af7..df81c07ba530 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -2161,10 +2161,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.i(TAG, "Creating animation bounds layer"); final SurfaceControl.Builder builder = makeAnimationLeash() .setParent(getAnimationLeashParent()) - .setName(getSurfaceControl() + " - animation-bounds") - .setSize(getSurfaceWidth(), getSurfaceHeight()); + .setName(getSurfaceControl() + " - animation-bounds"); final SurfaceControl boundsLayer = builder.build(); - t.setWindowCrop(boundsLayer, getSurfaceWidth(), getSurfaceHeight()); t.show(boundsLayer); return boundsLayer; } diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java index 9633864ed77e..c90f5bfb7ee0 100644 --- a/services/core/java/com/android/server/wm/BlackFrame.java +++ b/services/core/java/com/android/server/wm/BlackFrame.java @@ -48,7 +48,6 @@ public class BlackFrame { surface = dc.makeOverlay() .setName("BlackSurface") - .setSize(w, h) .setColorLayer(true) .setParent(null) // TODO: Work-around for b/69259549 .build(); diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java index 2a216abbe4ac..c3d621124afc 100644 --- a/services/core/java/com/android/server/wm/CircularDisplayMask.java +++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java @@ -69,7 +69,7 @@ class CircularDisplayMask { try { ctrl = dc.makeOverlay() .setName("CircularDisplayMask") - .setSize(mScreenSize.x, mScreenSize.y) // not a typo + .setBufferSize(mScreenSize.x, mScreenSize.y) // not a typo .setFormat(PixelFormat.TRANSLUCENT) .build(); diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index cc14afce7ff6..fa3c7ca29284 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -308,7 +308,6 @@ class Dimmer { return false; } else { // TODO: Once we use geometry from hierarchy this falls away. - t.setSize(mDimState.mDimLayer, bounds.width(), bounds.height()); t.setPosition(mDimState.mDimLayer, bounds.left, bounds.top); t.setWindowCrop(mDimState.mDimLayer, bounds.width(), bounds.height()); if (!mDimState.isVisible) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 478340d85d01..c0e983653b27 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -34,6 +34,7 @@ import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static android.view.View.GONE; +import static android.view.InsetsState.TYPE_IME; import static android.view.WindowManager.DOCKED_BOTTOM; import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.DOCKED_TOP; @@ -78,7 +79,6 @@ import static com.android.server.wm.DisplayContentProto.PINNED_STACK_CONTROLLER; import static com.android.server.wm.DisplayContentProto.ROTATION; import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION; import static com.android.server.wm.DisplayContentProto.STACKS; -import static com.android.server.wm.DisplayContentProto.SURFACE_SIZE; import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; @@ -124,6 +124,7 @@ import android.animation.AnimationHandler; import android.annotation.CallSuper; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; @@ -151,6 +152,7 @@ import android.view.DisplayInfo; import android.view.Gravity; import android.view.InputChannel; import android.view.InputDevice; +import android.view.InsetsState.InternalInsetType; import android.view.MagnificationSpec; import android.view.Surface; import android.view.SurfaceControl; @@ -162,6 +164,7 @@ import android.view.WindowManagerPolicyConstants.PointerEventListener; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ToBooleanFunction; +import com.android.internal.util.function.TriConsumer; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.utils.DisplayRotationUtil; import com.android.server.wm.utils.RotationCache; @@ -470,14 +473,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private SurfaceControl mWindowingLayer; /** - * Specifies the size of the surfaces in {@link #mOverlayLayer} and {@link #mWindowingLayer}. - * <p> - * For these surfaces currently we use a surface based on the larger of width or height so we - * don't have to resize when rotating the display. - */ - private int mSurfaceSize; - - /** * Sequence number for the current layout pass. */ int mLayoutSeq = 0; @@ -515,6 +510,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private final PointerEventDispatcher mPointerEventDispatcher; + private final InsetsStateController mInsetsStateController; + // Last systemUiVisibility we received from status bar. private int mLastStatusBarVisibility = 0; // Last systemUiVisibility we dispatched to windows. @@ -884,18 +881,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mDividerControllerLocked = new DockedStackDividerController(service, this); mPinnedStackControllerLocked = new PinnedStackController(service, this); - // We use this as our arbitrary surface size for buffer-less parents - // that don't impose cropping on their children. It may need to be larger - // than the display size because fullscreen windows can be shifted offscreen - // due to surfaceInsets. 2 times the largest display dimension feels like an - // appropriately arbitrary number. Eventually we would like to give SurfaceFlinger - // layers the ability to match their parent sizes and be able to skip - // such arbitrary size settings. - mSurfaceSize = Math.max(mBaseDisplayHeight, mBaseDisplayWidth) * 2; - - final SurfaceControl.Builder b = mService.makeSurfaceBuilder(mSession) - .setSize(mSurfaceSize, mSurfaceSize) - .setOpaque(true); + final SurfaceControl.Builder b = mService.makeSurfaceBuilder(mSession).setOpaque(true); mWindowingLayer = b.setName("Display Root").build(); mOverlayLayer = b.setName("Display Overlays").build(); @@ -922,6 +908,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mService.mAnimator.addDisplayLocked(mDisplayId); mInputMonitor = new InputMonitor(service, mDisplayId); + mInsetsStateController = new InsetsStateController(this); } boolean isReady() { @@ -1058,6 +1045,23 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mDisplayRotation; } + /** + * Marks a window as providing insets for the rest of the windows in the system. + * + * @param type The type of inset this window provides. + * @param win The window. + * @param frameProvider Function to compute the frame, or {@code null} if the just the frame of + * the window should be taken. + */ + void setInsetProvider(@InternalInsetType int type, WindowState win, + @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) { + mInsetsStateController.getSourceProvider(type).setWindow(win, frameProvider); + } + + InsetsStateController getInsetsStateController() { + return mInsetsStateController; + } + @VisibleForTesting void setDisplayRotation(DisplayRotation displayRotation) { mDisplayRotation = displayRotation; @@ -2612,7 +2616,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } mDisplayFrames.writeToProto(proto, DISPLAY_FRAMES); mAppTransition.writeToProto(proto, APP_TRANSITION); - proto.write(SURFACE_SIZE, mSurfaceSize); if (mFocusedApp != null) { mFocusedApp.writeNameToProto(proto, FOCUSED_APP); } @@ -2733,6 +2736,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mDisplayRotation.dump(prefix, pw); pw.println(); mInputMonitor.dump(pw, " "); + pw.println(); + mInsetsStateController.dump(prefix, pw); } @Override @@ -3015,6 +3020,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mInputMethodWindow.getDisplayId()); } computeImeTarget(true /* updateImeTarget */); + mInsetsStateController.getSourceProvider(TYPE_IME).setWindow(win, + null /* frameProvider */); } /** @@ -3470,6 +3477,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw(); if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats( "after finishPostLayoutPolicyLw", pendingLayoutChanges); + mInsetsStateController.onPostLayout(); } while (pendingLayoutChanges != 0); mTmpApplySurfaceChangesTransactionState.reset(); @@ -3537,10 +3545,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } - int getSurfaceSize() { - return mSurfaceSize; - } - void performLayout(boolean initial, boolean updateInputWindows) { if (!isLayoutNeeded()) { return; @@ -4483,8 +4487,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo SurfaceControl.Builder makeChildSurface(WindowContainer child) { SurfaceSession s = child != null ? child.getSession() : getSession(); final SurfaceControl.Builder b = mService.makeSurfaceBuilder(s); - b.setSize(mSurfaceSize, mSurfaceSize); - if (child == null) { return b; } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index c16f95ee1160..0e5947af0c61 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.res.Configuration.UI_MODE_TYPE_CAR; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; +import static android.view.InsetsState.TYPE_TOP_BAR; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; @@ -128,6 +129,7 @@ import android.view.InputChannel; import android.view.InputDevice; import android.view.InputEvent; import android.view.InputEventReceiver; +import android.view.InsetsState; import android.view.MotionEvent; import android.view.PointerIcon; import android.view.Surface; @@ -804,6 +806,11 @@ public class DisplayPolicy { if (mDisplayContent.isDefaultDisplay) { mService.mPolicy.setKeyguardCandidateLw(win); } + mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win, + (displayFrames, windowState, rect) -> { + rect.top = 0; + rect.bottom = getStatusBarHeight(displayFrames); + }); break; case TYPE_NAVIGATION_BAR: mContext.enforceCallingOrSelfPermission( @@ -818,6 +825,8 @@ public class DisplayPolicy { mNavigationBarController.setWindow(win); mNavigationBarController.setOnBarVisibilityChangedListener( mNavBarVisibilityListener, true); + mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, + win, null /* frameProvider */); if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar); break; case TYPE_NAVIGATION_BAR_PANEL: @@ -845,9 +854,11 @@ public class DisplayPolicy { if (mDisplayContent.isDefaultDisplay) { mService.mPolicy.setKeyguardCandidateLw(null); } + mDisplayContent.setInsetProvider(TYPE_TOP_BAR, null, null); } else if (mNavigationBar == win) { mNavigationBar = null; mNavigationBarController.setWindow(null); + mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, null, null); } if (mLastFocusedWindow == win) { mLastFocusedWindow = null; @@ -855,6 +866,11 @@ public class DisplayPolicy { mScreenDecorWindows.remove(win); } + private int getStatusBarHeight(DisplayFrames displayFrames) { + return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation], + displayFrames.mDisplayCutoutSafe.top); + } + /** * Control the animation to run when a window's state changes. Return a * non-0 number to force the animation to a specific resource ID, or 0 diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index f1d1e49c1004..7aabc15d9860 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -21,6 +21,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; @@ -30,6 +31,7 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.power.V1_0.PowerHint; +import android.net.Uri; import android.os.Handler; import android.os.SystemProperties; import android.os.UserHandle; @@ -57,6 +59,7 @@ public class DisplayRotation { private final WindowManagerService mService; private final DisplayContent mDisplayContent; private final DisplayPolicy mDisplayPolicy; + private final DisplayWindowSettings mDisplayWindowSettings; private final Context mContext; private final Object mLock; @@ -71,10 +74,6 @@ public class DisplayRotation { private StatusBarManagerInternal mStatusBarManagerInternal; private SettingsObserver mSettingsObserver; - // Default display does not rotate, apps that require non-default orientation will have to - // have the orientation emulated. - private boolean mForceDefaultOrientation; - private int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @VisibleForTesting @@ -93,6 +92,13 @@ public class DisplayRotation { private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; private int mUserRotation = Surface.ROTATION_0; + /** + * A flag to indicate if the display rotation should be fixed to user specified rotation + * regardless of all other states (including app requrested orientation). {@code true} the + * display rotation should be fixed to user specified rotation, {@code false} otherwise. + */ + private boolean mFixedToUserRotation; + private int mDemoHdmiRotation; private int mDemoRotation; private boolean mDemoHdmiRotationLock; @@ -100,15 +106,17 @@ public class DisplayRotation { DisplayRotation(WindowManagerService service, DisplayContent displayContent) { this(service, displayContent, displayContent.getDisplayPolicy(), - service.mContext, service.getWindowManagerLock()); + service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock()); } @VisibleForTesting DisplayRotation(WindowManagerService service, DisplayContent displayContent, - DisplayPolicy displayPolicy, Context context, Object lock) { + DisplayPolicy displayPolicy, DisplayWindowSettings displayWindowSettings, + Context context, Object lock) { mService = service; mDisplayContent = displayContent; mDisplayPolicy = displayPolicy; + mDisplayWindowSettings = displayWindowSettings; mContext = context; mLock = lock; isDefaultDisplay = displayContent.isDefaultDisplay; @@ -204,12 +212,19 @@ public class DisplayRotation { // so if the orientation is forced, we need to respect that no matter what. final boolean isTv = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_LEANBACK); - mForceDefaultOrientation = ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar || isTv) && - res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation) && - // For debug purposes the next line turns this feature off with: - // $ adb shell setprop config.override_forced_orient true - // $ adb shell wm size reset - !"true".equals(SystemProperties.get("config.override_forced_orient")); + final boolean forceDefaultOrientationInRes = + res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation); + final boolean forceDefaultOrienation = + ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar || isTv) + && forceDefaultOrientationInRes + // For debug purposes the next line turns this feature off with: + // $ adb shell setprop config.override_forced_orient true + // $ adb shell wm size reset + && !"true".equals(SystemProperties.get("config.override_forced_orient")); + // Configuration says we force to use the default orientation. We can fall back to fix + // rotation to only user rotation. As long as OEM doesn't change user rotation then the + // rotation of this display is effectively stuck at 0 deg. + setFixedToUserRotation(forceDefaultOrienation); } void setRotation(int rotation) { @@ -227,7 +242,14 @@ public class DisplayRotation { } } - void restoreUserRotation(int userRotationMode, int userRotation) { + void restoreSettings(int userRotationMode, int userRotation, + boolean fixedToUserRotation) { + mFixedToUserRotation = fixedToUserRotation; + + // We will retrieve user rotation and user rotation mode from settings for default display. + if (isDefaultDisplay) { + return; + } if (userRotationMode != WindowManagerPolicy.USER_ROTATION_FREE && userRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) { Slog.w(TAG, "Trying to restore an invalid user rotation mode " + userRotationMode @@ -243,6 +265,18 @@ public class DisplayRotation { mUserRotation = userRotation; } + void setFixedToUserRotation(boolean fixedToUserRotation) { + if (mFixedToUserRotation == fixedToUserRotation) { + return; + } + + mFixedToUserRotation = fixedToUserRotation; + mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent, + fixedToUserRotation); + mService.updateRotation(true /* alwaysSendConfiguration */, + false /* forceRelayout */); + } + private void setUserRotation(int userRotationMode, int userRotation) { if (isDefaultDisplay) { // We'll be notified via settings listener, so we don't need to update internal values. @@ -265,7 +299,7 @@ public class DisplayRotation { mUserRotation = userRotation; changed = true; } - mService.mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode, + mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode, userRotation); if (changed) { mService.updateRotation(true /* alwaysSendConfiguration */, @@ -291,9 +325,8 @@ public class DisplayRotation { Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0; } - /** @return true if com.android.internal.R.bool#config_forceDefaultOrientation is true. */ - boolean isDefaultOrientationForced() { - return mForceDefaultOrientation; + boolean isFixedToUserRotation() { + return mFixedToUserRotation; } public int getLandscapeRotation() { @@ -399,6 +432,12 @@ public class DisplayRotation { * screen is switched off. */ private boolean needSensorRunning() { + if (mFixedToUserRotation) { + // We are sure we only respect user rotation settings, so we are sure we will not + // support sensor rotation. + return false; + } + if (mSupportAutoRotation) { if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR @@ -459,8 +498,8 @@ public class DisplayRotation { ); } - if (mForceDefaultOrientation) { - return Surface.ROTATION_0; + if (mFixedToUserRotation) { + return mUserRotation; } int sensorRotation = mOrientationListener != null @@ -701,8 +740,8 @@ public class DisplayRotation { // demo, hdmi, vr, etc mode. // Determine if the rotation is currently forced. - if (mForceDefaultOrientation) { - return false; // Rotation is forced to default orientation. + if (mFixedToUserRotation) { + return false; // Rotation is forced to user settings. } final int lidState = mDisplayPolicy.getLidState(); @@ -861,6 +900,7 @@ public class DisplayRotation { pw.print(" mDemoHdmiRotationLock=" + mDemoHdmiRotationLock); pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation)); pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation)); + pw.println(prefix + " mFixedToUserRotation=" + mFixedToUserRotation); } private class OrientationListener extends WindowOrientationListener { @@ -945,4 +985,10 @@ public class DisplayRotation { } } } + + @VisibleForTesting + interface ContentObserverRegister { + void registerContentObserver(Uri uri, boolean notifyForDescendants, + ContentObserver observer, @UserIdInt int userHandle); + } } diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index f7dfd3ffc8bf..45d77dee1851 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -80,6 +80,7 @@ class DisplayWindowSettings { private boolean mShouldShowWithInsecureKeyguard = false; private boolean mShouldShowSystemDecors = false; private boolean mShouldShowIme = false; + private boolean mFixedToUserRotation; private Entry(String name) { mName = name; @@ -97,7 +98,8 @@ class DisplayWindowSettings { && mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED && !mShouldShowWithInsecureKeyguard && !mShouldShowSystemDecors - && !mShouldShowIme; + && !mShouldShowIme + && !mFixedToUserRotation; } } @@ -186,6 +188,13 @@ class DisplayWindowSettings { writeSettingsIfNeeded(entry, displayInfo); } + void setFixedToUserRotation(DisplayContent displayContent, boolean fixedToUserRotation) { + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); + final Entry entry = getOrCreateEntry(displayInfo); + entry.mFixedToUserRotation = fixedToUserRotation; + writeSettingsIfNeeded(entry, displayInfo); + } + private int getWindowingModeLocked(Entry entry, int displayId) { int windowingMode = entry != null ? entry.mWindowingMode : WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -331,7 +340,8 @@ class DisplayWindowSettings { displayInfo.overscanRight = entry.mOverscanRight; displayInfo.overscanBottom = entry.mOverscanBottom; - dc.getDisplayRotation().restoreUserRotation(entry.mUserRotationMode, entry.mUserRotation); + dc.getDisplayRotation().restoreSettings(entry.mUserRotationMode, + entry.mUserRotation, entry.mFixedToUserRotation); if (entry.mForcedDensity != 0) { dc.mBaseDisplayDensity = entry.mForcedDensity; @@ -458,6 +468,8 @@ class DisplayWindowSettings { "shouldShowWithInsecureKeyguard"); entry.mShouldShowSystemDecors = getBooleanAttribute(parser, "shouldShowSystemDecors"); entry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme"); + entry.mFixedToUserRotation = getBooleanAttribute(parser, + "fixedToUserRotation"); mEntries.put(name, entry); } XmlUtils.skipCurrentTag(parser); @@ -541,6 +553,10 @@ class DisplayWindowSettings { if (entry.mShouldShowIme) { out.attribute(null, "shouldShowIme", Boolean.toString(entry.mShouldShowIme)); } + if (entry.mFixedToUserRotation) { + out.attribute(null, "fixedToUserRotation", + Boolean.toString(entry.mFixedToUserRotation)); + } out.endTag(null, "display"); } diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 7279fe018055..8f6ed85d122d 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -155,7 +155,7 @@ class DragState { if (mInputSurface == null) { mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId) .getSession()).setContainerLayer(true) - .setName("Drag and Drop Input Consumer").setSize(1, 1).build(); + .setName("Drag and Drop Input Consumer").build(); } final InputWindowHandle h = getInputWindowHandle(); if (h == null) { diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java index fddf6ca2a698..7cb4a43a9ede 100644 --- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java +++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java @@ -16,7 +16,6 @@ package com.android.server.wm; - import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -32,7 +31,6 @@ import android.view.Display; import android.view.Surface; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; -import android.view.SurfaceSession; class EmulatorDisplayOverlay { private static final String TAG = TAG_WITH_CLASS_NAME ? "EmulatorDisplayOverlay" : TAG_WM; @@ -59,7 +57,7 @@ class EmulatorDisplayOverlay { try { ctrl = dc.makeOverlay() .setName("EmulatorDisplayOverlay") - .setSize(mScreenSize.x, mScreenSize.y) + .setBufferSize(mScreenSize.x, mScreenSize.y) .setFormat(PixelFormat.TRANSLUCENT) .build(); ctrl.setLayer(zOrder); diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index 8140820871da..4df5a0b5ad9e 100644 --- a/services/core/java/com/android/server/wm/InputConsumerImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -90,7 +90,6 @@ class InputConsumerImpl implements IBinder.DeathRecipient { mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId) .getSession()).setContainerLayer(true).setName("Input Consumer " + name) - .setSize(1, 1) .build(); } diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java new file mode 100644 index 000000000000..e96f0b1c4416 --- /dev/null +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2018 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.annotation.NonNull; +import android.annotation.Nullable; +import android.graphics.Rect; +import android.view.InsetsSource; + +import com.android.internal.util.function.TriConsumer; +import com.android.server.policy.WindowManagerPolicy; + +/** + * Controller for a specific inset source on the server. It's called provider as it provides the + * {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}. + */ +class InsetsSourceProvider { + + private final Rect mTmpRect = new Rect(); + private final @NonNull InsetsSource mSource; + private WindowState mWin; + private TriConsumer<DisplayFrames, WindowState, Rect> mFrameProvider; + + InsetsSourceProvider(InsetsSource source) { + mSource = source; + } + + InsetsSource getSource() { + return mSource; + } + + /** + * Updates the window that currently backs this source. + * + * @param win The window that links to this source. + * @param frameProvider Based on display frame state and the window, calculates the resulting + * frame that should be reported to clients. + */ + void setWindow(@Nullable WindowState win, + @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) { + if (mWin != null) { + mWin.setInsetProvider(null); + } + mWin = win; + mFrameProvider = frameProvider; + if (win == null) { + mSource.setVisible(false); + mSource.setFrame(new Rect()); + } else { + mSource.setVisible(true); + mWin.setInsetProvider(this); + } + } + + /** + * Called when a layout pass has occurred. + */ + void onPostLayout() { + if (mWin == null) { + return; + } + + mTmpRect.set(mWin.getFrameLw()); + if (mFrameProvider != null) { + mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect); + } else { + mTmpRect.inset(mWin.mGivenContentInsets); + } + mSource.setFrame(mTmpRect); + mSource.setVisible(mWin.isVisible() && !mWin.mGivenInsetsPending); + + } +} diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java new file mode 100644 index 000000000000..1189ee660605 --- /dev/null +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 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 android.view.InsetsState.TYPE_IME; +import static android.view.InsetsState.TYPE_NAVIGATION_BAR; +import static android.view.InsetsState.TYPE_TOP_BAR; + +import android.util.ArrayMap; +import android.view.InsetsState; + +import java.io.PrintWriter; +import java.util.function.Consumer; + +/** + * Manages global window inset state in the system represented by {@link InsetsState}. + */ +class InsetsStateController { + + private final InsetsState mLastState = new InsetsState(); + private final InsetsState mState = new InsetsState(); + private final DisplayContent mDisplayContent; + private ArrayMap<Integer, InsetsSourceProvider> mControllers = new ArrayMap<>(); + + private final Consumer<WindowState> mDispatchInsetsChanged = w -> { + if (w.isVisible()) { + w.notifyInsetsChanged(); + } + }; + + InsetsStateController(DisplayContent displayContent) { + mDisplayContent = displayContent; + } + + /** + * When dispatching window state to the client, we'll need to exclude the source that represents + * the window that is being dispatched. + * + * @param target The client we dispatch the state to. + * @return The state stripped of the necessary information. + */ + InsetsState getInsetsForDispatch(WindowState target) { + final InsetsSourceProvider provider = target.getInsetProvider(); + if (provider == null) { + return mState; + } + + final InsetsState state = new InsetsState(); + state.set(mState); + final int type = provider.getSource().getType(); + state.removeSource(type); + + // Navigation bar doesn't get influenced by anything else + if (type == TYPE_NAVIGATION_BAR) { + state.removeSource(TYPE_IME); + state.removeSource(TYPE_TOP_BAR); + } + return state; + } + + /** + * @return The provider of a specific type. + */ + InsetsSourceProvider getSourceProvider(int type) { + return mControllers.computeIfAbsent(type, + key -> new InsetsSourceProvider(mState.getSource(key))); + } + + /** + * Called when a layout pass has occurred. + */ + void onPostLayout() { + for (int i = mControllers.size() - 1; i>= 0; i--) { + mControllers.valueAt(i).onPostLayout(); + } + if (!mLastState.equals(mState)) { + mLastState.set(mState, true /* copySources */); + notifyInsetsChanged(); + } + } + + private void notifyInsetsChanged() { + mDisplayContent.forAllWindows(mDispatchInsetsChanged, true /* traverseTopToBottom */); + } + + void dump(String prefix, PrintWriter pw) { + pw.println(prefix + "WindowInsetsStateController"); + mState.dump(prefix + " ", pw); + } +} diff --git a/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java b/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java new file mode 100644 index 000000000000..93e2d8d6fba4 --- /dev/null +++ b/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2018 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.content.Intent; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import com.android.internal.os.BackgroundThread; +import com.android.internal.util.function.pooled.PooledLambda; + +import java.util.ArrayList; + +/** + * Multi-cast implementation of {@link ActivityMetricsLaunchObserver}. + * + * <br /><br /> + * If this class is called through the {@link ActivityMetricsLaunchObserver} interface, + * then the call is forwarded to all registered observers at the time. + * + * <br /><br /> + * All calls are invoked asynchronously in-order on a background thread. This fulfills the + * sequential ordering guarantee in {@link ActivityMetricsLaunchObserverRegistry}. + * + * @see ActivityTaskManagerInternal#getLaunchObserverRegistry() + */ +class LaunchObserverRegistryImpl implements + ActivityMetricsLaunchObserverRegistry, ActivityMetricsLaunchObserver { + private final ArrayList<ActivityMetricsLaunchObserver> mList = new ArrayList<>(); + + /** + * All calls are posted to a handler because: + * + * 1. We don't know how long the observer will take to handle this call and we don't want + * to block the WM critical section on it. + * 2. We don't know the lock ordering of the observer so we don't want to expose a chance + * of deadlock. + */ + private final Handler mHandler; + + public LaunchObserverRegistryImpl(Looper looper) { + mHandler = new Handler(looper); + } + + @Override + public void registerLaunchObserver(ActivityMetricsLaunchObserver launchObserver) { + mHandler.sendMessage(PooledLambda.obtainMessage( + LaunchObserverRegistryImpl::handleRegisterLaunchObserver, this, launchObserver)); + } + + @Override + public void unregisterLaunchObserver(ActivityMetricsLaunchObserver launchObserver) { + mHandler.sendMessage(PooledLambda.obtainMessage( + LaunchObserverRegistryImpl::handleUnregisterLaunchObserver, this, launchObserver)); + } + + @Override + public void onIntentStarted(Intent intent) { + mHandler.sendMessage(PooledLambda.obtainMessage( + LaunchObserverRegistryImpl::handleOnIntentStarted, this, intent)); + } + + @Override + public void onIntentFailed() { + mHandler.sendMessage(PooledLambda.obtainMessage( + LaunchObserverRegistryImpl::handleOnIntentFailed, this)); + } + + @Override + public void onActivityLaunched( + @ActivityRecordProto byte[] activity, + int temperature) { + mHandler.sendMessage(PooledLambda.obtainMessage( + LaunchObserverRegistryImpl::handleOnActivityLaunched, + this, activity, temperature)); + } + + @Override + public void onActivityLaunchCancelled( + @ActivityRecordProto byte[] activity) { + mHandler.sendMessage(PooledLambda.obtainMessage( + LaunchObserverRegistryImpl::handleOnActivityLaunchCancelled, this, activity)); + } + + @Override + public void onActivityLaunchFinished( + @ActivityRecordProto byte[] activity) { + mHandler.sendMessage(PooledLambda.obtainMessage( + LaunchObserverRegistryImpl::handleOnActivityLaunchFinished, this, activity)); + } + + // Use PooledLambda.obtainMessage to invoke below methods. Every method reference must be + // unbound (i.e. not capture any variables explicitly or implicitly) to fulfill the + // singleton-lambda requirement. + + private void handleRegisterLaunchObserver(ActivityMetricsLaunchObserver observer) { + mList.add(observer); + } + + private void handleUnregisterLaunchObserver(ActivityMetricsLaunchObserver observer) { + mList.remove(observer); + } + + private void handleOnIntentStarted(Intent intent) { + // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee. + for (int i = 0; i < mList.size(); i++) { + ActivityMetricsLaunchObserver o = mList.get(i); + o.onIntentStarted(intent); + } + } + + private void handleOnIntentFailed() { + // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee. + for (int i = 0; i < mList.size(); i++) { + ActivityMetricsLaunchObserver o = mList.get(i); + o.onIntentFailed(); + } + } + + private void handleOnActivityLaunched( + @ActivityRecordProto byte[] activity, + @Temperature int temperature) { + // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee. + for (int i = 0; i < mList.size(); i++) { + ActivityMetricsLaunchObserver o = mList.get(i); + o.onActivityLaunched(activity, temperature); + } + } + + private void handleOnActivityLaunchCancelled( + @ActivityRecordProto byte[] activity) { + // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee. + for (int i = 0; i < mList.size(); i++) { + ActivityMetricsLaunchObserver o = mList.get(i); + o.onActivityLaunchCancelled(activity); + } + } + + private void handleOnActivityLaunchFinished( + @ActivityRecordProto byte[] activity) { + // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee. + for (int i = 0; i < mList.size(); i++) { + ActivityMetricsLaunchObserver o = mList.get(i); + o.onActivityLaunchFinished(activity); + } + } +} diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java index da9a5071b100..bc6a690b6e74 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java +++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java @@ -269,7 +269,7 @@ class LaunchParamsPersister { outParams.mBounds.set(persistableParams.mBounds); } - private void onPackageRemoved(String packageName) { + void removeRecordForPackage(String packageName) { final List<File> fileToDelete = new ArrayList<>(); for (int i = 0; i < mMap.size(); ++i) { int userId = mMap.keyAt(i); @@ -310,7 +310,7 @@ class LaunchParamsPersister { @Override public void onPackageRemoved(String packageName) { - LaunchParamsPersister.this.onPackageRemoved(packageName); + removeRecordForPackage(packageName); } } diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index b49d304cf9a8..1a2aa2f252e6 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -186,7 +186,6 @@ public class Letterbox { createSurface(); } t.setPosition(mSurface, mSurfaceFrame.left, mSurfaceFrame.top); - t.setSize(mSurface, mSurfaceFrame.width(), mSurfaceFrame.height()); t.setWindowCrop(mSurface, mSurfaceFrame.width(), mSurfaceFrame.height()); t.show(mSurface); } else if (mSurface != null) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index c2bc677f5e39..80d1368427a3 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -233,6 +233,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final DisplayContent existing = getDisplayContent(displayId); if (existing != null) { + initializeDisplayOverrideConfiguration(controller, existing); existing.setController(controller); return existing; } @@ -242,6 +243,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display); mService.mDisplayWindowSettings.applySettingsToDisplayLocked(dc); + initializeDisplayOverrideConfiguration(controller, dc); if (mService.mDisplayManagerInternal != null) { mService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager( @@ -254,6 +256,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return dc; } + /** + * The display content may have configuration set from {@link #DisplayWindowSettings}. This + * callback let the owner of container know there is existing configuration to prevent the + * values from being replaced by the initializing {@link #ActivityDisplay}. + */ + private void initializeDisplayOverrideConfiguration(DisplayWindowController controller, + DisplayContent displayContent) { + if (controller != null && controller.mListener != null) { + controller.mListener.onInitializeOverrideConfiguration( + displayContent.getOverrideConfiguration()); + } + } + boolean isLayoutNeeded() { final int numDisplays = mChildren.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index df97027da64f..3947bd47b588 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -222,7 +222,7 @@ class ScreenRotationAnimation { } public ScreenRotationAnimation(Context context, DisplayContent displayContent, - boolean forceDefaultOrientation, boolean isSecure, WindowManagerService service) { + boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) { mService = service; mContext = context; mDisplayContent = displayContent; @@ -234,7 +234,7 @@ class ScreenRotationAnimation { final int originalWidth; final int originalHeight; DisplayInfo displayInfo = displayContent.getDisplayInfo(); - if (forceDefaultOrientation) { + if (fixedToUserRotation) { // Emulated orientation. mForceDefaultOrientation = true; originalWidth = displayContent.mBaseDisplayWidth; @@ -261,7 +261,7 @@ class ScreenRotationAnimation { try { mSurfaceControl = displayContent.makeOverlay() .setName("ScreenshotSurface") - .setSize(mWidth, mHeight) + .setBufferSize(mWidth, mHeight) .setSecure(isSecure) .build(); diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 6838c55100e8..37b5a7c30218 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -50,6 +50,7 @@ import android.view.InputChannel; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; +import android.view.InsetsState; import android.view.WindowManager; import com.android.internal.os.logging.MetricsLoggerWrapper; @@ -153,17 +154,21 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, - DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) { + DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, + InsetsState outInsetsState) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, - outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel); + outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel, + outInsetsState); } @Override public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs, - int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets) { + int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, + InsetsState outInsetsState) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, new Rect() /* outFrame */, outContentInsets, outStableInsets, null /* outOutsets */, - new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */); + new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */, + outInsetsState); } @Override @@ -182,7 +187,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, - Surface outSurface) { + Surface outSurface, InsetsState outInsetsState) { if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag); @@ -190,7 +195,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { requestedWidth, requestedHeight, viewFlags, flags, frameNumber, outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, outStableInsets, outsets, outBackdropFrame, cutout, - mergedConfiguration, outSurface); + mergedConfiguration, outSurface, outInsetsState); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java index e97b36683362..82f2ad89d407 100644 --- a/services/core/java/com/android/server/wm/StrictModeFlash.java +++ b/services/core/java/com/android/server/wm/StrictModeFlash.java @@ -16,7 +16,6 @@ package com.android.server.wm; - import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -24,12 +23,9 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; -import android.graphics.Region; -import android.view.Display; -import android.view.Surface.OutOfResourcesException; import android.view.Surface; +import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; -import android.view.SurfaceSession; class StrictModeFlash { private static final String TAG = TAG_WITH_CLASS_NAME ? "StrictModeFlash" : TAG_WM; @@ -46,7 +42,7 @@ class StrictModeFlash { try { ctrl = dc.makeOverlay() .setName("StrictModeFlash") - .setSize(1, 1) + .setBufferSize(1, 1) .setFormat(PixelFormat.TRANSLUCENT) .build(); ctrl.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER * 101); // one more than Watermark? arbitrary. @@ -122,7 +118,7 @@ class StrictModeFlash { } mLastDW = dw; mLastDH = dh; - mSurfaceControl.setSize(dw, dh); + mSurfaceControl.setBufferSize(dw, dh); mDrawNeeded = true; } diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 31c0c7f588c3..11068ce8bace 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -302,8 +302,7 @@ class SurfaceAnimator { if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash"); final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash() .setParent(mAnimatable.getAnimationLeashParent()) - .setName(surface + " - animation-leash") - .setSize(width, height); + .setName(surface + " - animation-leash"); final SurfaceControl leash = builder.build(); t.setWindowCrop(leash, width, height); if (!hidden) { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index c9800f85cb22..6904ef58dc24 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -302,7 +302,6 @@ class Task extends WindowContainer<AppWindowToken> { @Override void onDisplayChanged(DisplayContent dc) { - updateSurfaceSize(dc); adjustBoundsForDisplayChangeIfNeeded(dc); super.onDisplayChanged(dc); } diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 28bc039d6ee4..5a70325fbd87 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -82,7 +82,7 @@ class TaskPositioningController { if (mInputSurface == null) { mInputSurface = mService.makeSurfaceBuilder(dc.getSession()) .setContainerLayer(true) - .setName("Drag and Drop Input Consumer").setSize(1, 1).build(); + .setName("Drag and Drop Input Consumer").build(); } final InputWindowHandle h = getDragWindowHandleLocked(); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index a7b0272d4b0d..9a56606aee7f 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -32,6 +32,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; + import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.getColorViewLeftInset; @@ -65,6 +66,7 @@ import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; import android.view.ViewGroup.LayoutParams; +import android.view.InsetsState; import android.view.WindowManager; import android.view.WindowManagerGlobal; @@ -141,6 +143,7 @@ class TaskSnapshotSurface implements StartingSurface { final Rect taskBounds; final Rect tmpContentInsets = new Rect(); final Rect tmpStableInsets = new Rect(); + final InsetsState mTmpInsetsState = new InsetsState(); final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration(); int backgroundColor = WHITE; int statusBarColor = 0; @@ -201,7 +204,7 @@ class TaskSnapshotSurface implements StartingSurface { try { final int res = session.addToDisplay(window, window.mSeq, layoutParams, View.GONE, token.getDisplayContent().getDisplayId(), tmpFrame, tmpRect, tmpRect, - tmpRect, tmpCutout, null); + tmpRect, tmpCutout, null, mTmpInsetsState); if (res < 0) { Slog.w(TAG, "Failed to add snapshot starting window res=" + res); return null; @@ -217,7 +220,7 @@ class TaskSnapshotSurface implements StartingSurface { try { session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1, tmpFrame, tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect, - tmpCutout, tmpMergedConfiguration, surface); + tmpCutout, tmpMergedConfiguration, surface, mTmpInsetsState); } catch (RemoteException e) { // Local call. } @@ -312,7 +315,7 @@ class TaskSnapshotSurface implements StartingSurface { // Keep a reference to it such that it doesn't get destroyed when finalized. mChildSurfaceControl = new SurfaceControl.Builder(session) .setName(mTitle + " - task-snapshot-surface") - .setSize(buffer.getWidth(), buffer.getHeight()) + .setBufferSize(buffer.getWidth(), buffer.getHeight()) .setFormat(buffer.getFormat()) .build(); Surface surface = new Surface(); diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 64f4ba5e24ab..5deb4f1ab7d4 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -248,7 +248,6 @@ public class TaskStack extends WindowContainer<Task> implements getRawBounds(mTmpRect); final Rect stackBounds = getBounds(); getPendingTransaction() - .setSize(mAnimationBackgroundSurface, mTmpRect.width(), mTmpRect.height()) .setWindowCrop(mAnimationBackgroundSurface, mTmpRect.width(), mTmpRect.height()) .setPosition(mAnimationBackgroundSurface, mTmpRect.left - stackBounds.left, mTmpRect.top - stackBounds.top); @@ -751,7 +750,6 @@ public class TaskStack extends WindowContainer<Task> implements if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) { return; } - transaction.setSize(mSurfaceControl, width, height); transaction.setWindowCrop(mSurfaceControl, width, height); mLastSurfaceSize.set(width, height); } diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java index 9216b66e5088..e6ac059d5e02 100644 --- a/services/core/java/com/android/server/wm/Watermark.java +++ b/services/core/java/com/android/server/wm/Watermark.java @@ -20,19 +20,18 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Paint.FontMetricsInt; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Typeface; -import android.graphics.Paint.FontMetricsInt; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.Display; -import android.view.Surface.OutOfResourcesException; import android.view.Surface; +import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; -import android.view.SurfaceSession; /** * Displays a watermark on top of the window manager's windows. @@ -116,7 +115,7 @@ class Watermark { try { ctrl = dc.makeOverlay() .setName("WatermarkSurface") - .setSize(1, 1) + .setBufferSize(1, 1) .setFormat(PixelFormat.TRANSLUCENT) .build(); ctrl.setLayerStack(mDisplay.getLayerStack()); @@ -133,7 +132,7 @@ class Watermark { if (mLastDW != dw || mLastDH != dh) { mLastDW = dw; mLastDH = dh; - mSurfaceControl.setSize(dw, dh); + mSurfaceControl.setBufferSize(dw, dh); mDrawNeeded = true; } } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 266006db9987..7e4c62935e05 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -515,24 +515,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } } - /** - * Update the surface size when display changed in order to avoid children being bound by the - * old display size. - * - * Note that we don't want to apply this to all layers, but only limiting this to layers that - * don't set their own size ({@link Task}, {@link WindowState} and {@link WindowToken}). - */ - void updateSurfaceSize(DisplayContent dc) { - if (mSurfaceControl == null) { - return; - } - - final int newSurfaceSize = dc.getSurfaceSize(); - if (mSurfaceControl.getWidth() != newSurfaceSize) { - getPendingTransaction().setSize(mSurfaceControl, newSurfaceSize, newSurfaceSize); - } - } - void setWaitingForDrawnIfResizingChanged() { for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowContainer wc = mChildren.get(i); diff --git a/services/core/java/com/android/server/wm/WindowContainerListener.java b/services/core/java/com/android/server/wm/WindowContainerListener.java index 4b3cd36040c6..3d3d2e02693c 100644 --- a/services/core/java/com/android/server/wm/WindowContainerListener.java +++ b/services/core/java/com/android/server/wm/WindowContainerListener.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import android.content.res.Configuration; + /** * Interface used by the owner/creator of the container to listen to changes with the container. * @see WindowContainerController @@ -23,4 +25,5 @@ package com.android.server.wm; public interface WindowContainerListener { void registerConfigurationChangeListener(ConfigurationContainerListener listener); void unregisterConfigurationChangeListener(ConfigurationContainerListener listener); + default void onInitializeOverrideConfiguration(Configuration config) {} } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 5df34517956a..4085f3d8062a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -218,6 +218,7 @@ import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; import android.view.WindowContentFrameStats; +import android.view.InsetsState; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.RemoveContentMode; @@ -1111,7 +1112,8 @@ public class WindowManagerService extends IWindowManager.Stub public int addWindow(Session session, IWindow client, int seq, LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, - DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) { + DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, + InsetsState outInsetsState) { int[] appOp = new int[1]; int res = mPolicy.checkAddPermission(attrs, appOp); if (res != WindowManagerGlobal.ADD_OKAY) { @@ -1459,6 +1461,7 @@ public class WindowManagerService extends IWindowManager.Stub outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) { res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR; } + outInsetsState.set(displayContent.getInsetsStateController().getInsetsForDispatch(win)); if (mInTouchMode) { res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE; @@ -1856,7 +1859,7 @@ public class WindowManagerService extends IWindowManager.Stub long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration, - Surface outSurface) { + Surface outSurface, InsetsState outInsetsState) { int result = 0; boolean configChanged; final boolean hasStatusBarPermission = @@ -2157,6 +2160,7 @@ public class WindowManagerService extends IWindowManager.Stub outStableInsets, outOutsets); outCutout.set(win.getWmDisplayCutout().getDisplayCutout()); outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw())); + outInsetsState.set(displayContent.getInsetsStateController().getInsetsForDispatch(win)); if (localLOGV) Slog.v( TAG_WM, "Relayout given client " + client.asBinder() + ", requestedWidth=" + requestedWidth @@ -3587,6 +3591,17 @@ public class WindowManagerService extends IWindowManager.Stub } } + void setRotateForApp(int displayId, boolean enabled) { + synchronized (mGlobalLock) { + final DisplayContent display = mRoot.getDisplayContent(displayId); + if (display == null) { + Slog.w(TAG, "Trying to set rotate for app for a missing display."); + return; + } + display.getDisplayRotation().setFixedToUserRotation(enabled); + } + } + @Override public void freezeRotation(int rotation) { freezeDisplayRotation(Display.DEFAULT_DISPLAY, rotation); @@ -5393,7 +5408,7 @@ public class WindowManagerService extends IWindowManager.Stub displayContent.updateDisplayInfo(); screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent, - displayContent.getDisplayRotation().isDefaultOrientationForced(), isSecure, + displayContent.getDisplayRotation().isFixedToUserRotation(), isSecure, this); mAnimator.setScreenRotationAnimationLocked(mFrozenDisplayId, screenRotationAnimation); diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index bf77ba86075d..6865ce305442 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -76,6 +76,8 @@ public class WindowManagerShellCommand extends ShellCommand { getNextArgRequired()); case "set-user-rotation": return runSetDisplayUserRotation(pw); + case "set-fix-to-user-rotation": + return runSetFixToUserRotation(pw); default: return handleDefaultCommands(cmd); } @@ -297,6 +299,32 @@ public class WindowManagerShellCommand extends ShellCommand { } } + private int runSetFixToUserRotation(PrintWriter pw) { + int displayId = Display.DEFAULT_DISPLAY; + String arg = getNextArgRequired(); + if ("-d".equals(arg)) { + displayId = Integer.parseInt(getNextArgRequired()); + arg = getNextArgRequired(); + } + + final boolean enabled; + switch (arg) { + case "enabled": + enabled = true; + break; + case "disabled": + enabled = false; + break; + default: + getErrPrintWriter().println("Error: expecting enabled or disabled, but we get " + + arg); + return -1; + } + + mInternal.setRotateForApp(displayId, enabled); + return 0; + } + @Override public void onHelp() { PrintWriter pw = getOutPrintWriter(); @@ -316,6 +344,8 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" Dismiss the keyguard, prompting user for auth if necessary."); pw.println(" set-user-rotation [free|lock] [-d DISPLAY_ID] [rotation]"); pw.println(" Set user rotation mode and user rotation."); + pw.println(" set-fix-to-user-rotation [-d DISPLAY_ID] [enabled|disabled]"); + pw.println(" Enable or disable rotating display for app requested orientation."); if (!IS_USER) { pw.println(" tracing (start | stop)"); pw.println(" Start or stop window tracing."); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 9efaefefb192..cfd1f86cdeaa 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -143,6 +143,7 @@ import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES; import android.annotation.CallSuper; +import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.content.res.Configuration; @@ -194,6 +195,7 @@ import android.view.animation.Interpolator; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ToBooleanFunction; import com.android.server.policy.WindowManagerPolicy; +import com.android.server.policy.WindowManagerPolicy.DisplayContentInfo; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; import com.android.server.wm.utils.InsetUtils; import com.android.server.wm.utils.WmDisplayCutout; @@ -578,6 +580,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ private boolean mIsDimming = false; + private @Nullable InsetsSourceProvider mInsetProvider; + private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f; void seamlesslyRotateIfAllowed(Transaction transaction, @Rotation int oldRotation, @@ -1261,7 +1265,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override void onDisplayChanged(DisplayContent dc) { - updateSurfaceSize(dc); super.onDisplayChanged(dc); // Window was not laid out for this display yet, so make sure mLayoutSeq does not match. if (dc != null) { @@ -2956,6 +2959,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } + /** + * Called when the insets state changed. + */ + void notifyInsetsChanged() { + try { + mClient.insetsChanged( + getDisplayContent().getInsetsStateController().getInsetsForDispatch(this)); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to deliver inset state change", e); + } + } + Rect getBackdropFrame(Rect frame) { // When the task is docked, we send fullscreen sized backDropFrame as soon as resizing // start even if we haven't received the relayout window, so that the client requests @@ -4777,6 +4792,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWindowFrames.setContentChanged(false); } + void setInsetProvider(InsetsSourceProvider insetProvider) { + mInsetProvider = insetProvider; + } + + InsetsSourceProvider getInsetProvider() { + return mInsetProvider; + } + private final class MoveAnimationSpec implements AnimationSpec { private final long mDuration; diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index e090cc5177ba..78a3fe5ac4ca 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -861,7 +861,7 @@ class WindowStateAnimator { // to find the surface size changed underneath it. final boolean relayout = !w.mRelayoutCalled || w.mInRelayout; if (relayout) { - mSurfaceResized = mSurfaceController.setSizeInTransaction( + mSurfaceResized = mSurfaceController.setBufferSizeInTransaction( mTmpSize.width(), mTmpSize.height(), recoveringMemory); } else { mSurfaceResized = false; diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index 6821e9486a78..ce627e23e6ee 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -19,34 +19,28 @@ package com.android.server.wm; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; +import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowSurfaceControllerProto.LAYER; import static com.android.server.wm.WindowSurfaceControllerProto.SHOWN; -import android.graphics.Point; -import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; -import android.os.IBinder; import android.os.Debug; +import android.os.IBinder; import android.os.Trace; +import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.WindowContentFrameStats; -import android.view.Surface.OutOfResourcesException; - -import android.util.Slog; -import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.ArrayList; class WindowSurfaceController { static final String TAG = TAG_WITH_CLASS_NAME ? "WindowSurfaceController" : TAG_WM; @@ -106,7 +100,7 @@ class WindowSurfaceController { final SurfaceControl.Builder b = win.makeSurface() .setParent(win.getSurfaceControl()) .setName(name) - .setSize(w, h) + .setBufferSize(w, h) .setFormat(format) .setFlags(flags) .setMetadata(windowType, ownerUid); @@ -303,7 +297,7 @@ class WindowSurfaceController { } } - boolean setSizeInTransaction(int width, int height, boolean recoveringMemory) { + boolean setBufferSizeInTransaction(int width, int height, boolean recoveringMemory) { final boolean surfaceResized = mSurfaceW != width || mSurfaceH != height; if (surfaceResized) { mSurfaceW = width; @@ -312,7 +306,7 @@ class WindowSurfaceController { try { if (SHOW_TRANSACTIONS) logSurface( "SIZE " + width + "x" + height, null); - mSurfaceControl.setSize(width, height); + mSurfaceControl.setBufferSize(width, height); } catch (RuntimeException e) { // If something goes wrong with the surface (such // as running out of memory), don't take down the diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 0cf79b63e9dc..d8242f8a6daa 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -265,7 +265,6 @@ class WindowToken extends WindowContainer<WindowState> { // to another display before the window behind // it is ready. - updateSurfaceSize(dc); super.onDisplayChanged(dc); } diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index bf83ac13fd93..8b873e3f9ad7 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -108,6 +108,7 @@ cc_defaults { "android.hardware.contexthub@1.0", "android.hardware.gnss@1.0", "android.hardware.gnss@1.1", + "android.hardware.gnss@2.0", "android.hardware.ir@1.0", "android.hardware.light@2.0", "android.hardware.power@1.0", diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index fcd9335874e1..b36a8a7cdf19 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -32,6 +32,7 @@ #include <atomic> #include <cinttypes> #include <limits.h> +#include <android-base/parseint.h> #include <android-base/stringprintf.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> @@ -71,6 +72,7 @@ #define INDENT " " +using android::base::ParseUint; using android::base::StringPrintf; namespace android { @@ -81,6 +83,7 @@ namespace android { static const float POINTER_SPEED_EXPONENT = 1.0f / 4; static struct { + jclass clazz; jmethodID notifyConfigurationChanged; jmethodID notifyInputDevicesChanged; jmethodID notifySwitch; @@ -95,6 +98,7 @@ static struct { jmethodID checkInjectEventsPermission; jmethodID getVirtualKeyQuietTimeMillis; jmethodID getExcludedDeviceNames; + jmethodID getInputPortAssociations; jmethodID getKeyRepeatTimeout; jmethodID getKeyRepeatDelay; jmethodID getHoverTapTimeout; @@ -183,6 +187,13 @@ enum { WM_ACTION_PASS_TO_USER = 1, }; +static std::string getStringElementFromJavaArray(JNIEnv* env, jobjectArray array, jsize index) { + jstring item = jstring(env->GetObjectArrayElement(array, index)); + ScopedUtfChars chars(env, item); + std::string result(chars.c_str()); + return result; +} + // --- NativeInputManager --- @@ -452,20 +463,44 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon } outConfig->excludedDeviceNames.clear(); - jobjectArray excludedDeviceNames = jobjectArray(env->CallObjectMethod(mServiceObj, - gServiceClassInfo.getExcludedDeviceNames)); + jobjectArray excludedDeviceNames = jobjectArray(env->CallStaticObjectMethod( + gServiceClassInfo.clazz, gServiceClassInfo.getExcludedDeviceNames)); if (!checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && excludedDeviceNames) { jsize length = env->GetArrayLength(excludedDeviceNames); for (jsize i = 0; i < length; i++) { - jstring item = jstring(env->GetObjectArrayElement(excludedDeviceNames, i)); - const char* deviceNameChars = env->GetStringUTFChars(item, nullptr); - outConfig->excludedDeviceNames.push_back(deviceNameChars); - env->ReleaseStringUTFChars(item, deviceNameChars); - env->DeleteLocalRef(item); + std::string deviceName = getStringElementFromJavaArray(env, excludedDeviceNames, i); + outConfig->excludedDeviceNames.push_back(deviceName); } env->DeleteLocalRef(excludedDeviceNames); } + // Associations between input ports and display ports + // The java method packs the information in the following manner: + // Original data: [{'inputPort1': '1'}, {'inputPort2': '2'}] + // Received data: ['inputPort1', '1', 'inputPort2', '2'] + // So we unpack accordingly here. + outConfig->portAssociations.clear(); + jobjectArray portAssociations = jobjectArray(env->CallStaticObjectMethod( + gServiceClassInfo.clazz, gServiceClassInfo.getInputPortAssociations)); + if (!checkAndClearExceptionFromCallback(env, "getInputPortAssociations") && portAssociations) { + jsize length = env->GetArrayLength(portAssociations); + for (jsize i = 0; i < length / 2; i++) { + std::string inputPort = getStringElementFromJavaArray(env, portAssociations, 2 * i); + std::string displayPortStr = + getStringElementFromJavaArray(env, portAssociations, 2 * i + 1); + uint8_t displayPort; + // Should already have been validated earlier, but do it here for safety. + bool success = ParseUint(displayPortStr, &displayPort); + if (!success) { + ALOGE("Could not parse entry in port configuration file, received: %s", + displayPortStr.c_str()); + continue; + } + outConfig->portAssociations.insert({inputPort, displayPort}); + } + env->DeleteLocalRef(portAssociations); + } + jint hoverTapTimeout = env->CallIntMethod(mServiceObj, gServiceClassInfo.getHoverTapTimeout); if (!checkAndClearExceptionFromCallback(env, "getHoverTapTimeout")) { @@ -1697,6 +1732,10 @@ static const JNINativeMethod gInputManagerMethods[] = { var = env->GetMethodID(clazz, methodName, methodDescriptor); \ LOG_FATAL_IF(! (var), "Unable to find method " methodName); +#define GET_STATIC_METHOD_ID(var, clazz, methodName, methodDescriptor) \ + var = env->GetStaticMethodID(clazz, methodName, methodDescriptor); \ + LOG_FATAL_IF(! (var), "Unable to find static method " methodName); + #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ LOG_FATAL_IF(! (var), "Unable to find field " fieldName); @@ -1711,6 +1750,7 @@ int register_android_server_InputManager(JNIEnv* env) { jclass clazz; FIND_CLASS(clazz, "com/android/server/input/InputManagerService"); + gServiceClassInfo.clazz = clazz; GET_METHOD_ID(gServiceClassInfo.notifyConfigurationChanged, clazz, "notifyConfigurationChanged", "(J)V"); @@ -1754,9 +1794,12 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.getVirtualKeyQuietTimeMillis, clazz, "getVirtualKeyQuietTimeMillis", "()I"); - GET_METHOD_ID(gServiceClassInfo.getExcludedDeviceNames, clazz, + GET_STATIC_METHOD_ID(gServiceClassInfo.getExcludedDeviceNames, clazz, "getExcludedDeviceNames", "()[Ljava/lang/String;"); + GET_STATIC_METHOD_ID(gServiceClassInfo.getInputPortAssociations, clazz, + "getInputPortAssociations", "()[Ljava/lang/String;"); + GET_METHOD_ID(gServiceClassInfo.getKeyRepeatTimeout, clazz, "getKeyRepeatTimeout", "()I"); diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 92160053804d..4d0556c7507a 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -20,9 +20,11 @@ #include <android/hardware/gnss/1.0/IGnss.h> #include <android/hardware/gnss/1.1/IGnss.h> +#include <android/hardware/gnss/2.0/IGnss.h> #include <android/hardware/gnss/1.0/IGnssMeasurement.h> #include <android/hardware/gnss/1.1/IGnssMeasurement.h> +#include <android/hardware/gnss/2.0/IGnssMeasurement.h> #include <nativehelper/JNIHelp.h> #include "jni.h" #include "hardware_legacy/power.h" @@ -110,13 +112,15 @@ using android::hidl::base::V1_0::IBase; using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss; using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss; +using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss; using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration; using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration; using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement; using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement; +using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement; using IGnssMeasurementCallback_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback; using IGnssMeasurementCallback_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback; - +using IGnssMeasurementCallback_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback; struct GnssDeathRecipient : virtual public hidl_death_recipient { @@ -135,6 +139,7 @@ static const uint32_t ADR_STATE_HALF_CYCLE_REPORTED = (1<<4); sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr; sp<IGnss_V1_0> gnssHal = nullptr; sp<IGnss_V1_1> gnssHal_V1_1 = nullptr; +sp<IGnss_V2_0> gnssHal_V2_0 = nullptr; sp<IGnssXtra> gnssXtraIface = nullptr; sp<IAGnssRil> agnssRilIface = nullptr; sp<IGnssGeofencing> gnssGeofencingIface = nullptr; @@ -146,6 +151,7 @@ sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr; sp<IGnssNi> gnssNiIface = nullptr; sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr; sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr; +sp<IGnssMeasurement_V2_0> gnssMeasurementIface_V2_0 = nullptr; sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr; #define WAKE_LOCK_NAME "GPS" @@ -744,7 +750,9 @@ Return<void> GnssNavigationMessageCallback::gnssNavigationMessageCb( * GnssMeasurementCallback implements the callback methods required for the * GnssMeasurement interface. */ -struct GnssMeasurementCallback : public IGnssMeasurementCallback_V1_1 { +struct GnssMeasurementCallback : public IGnssMeasurementCallback_V2_0 { + Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_V2_0::GnssData& data) + override; Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_V1_1::GnssData& data) override; Return<void> GnssMeasurementCb(const IGnssMeasurementCallback_V1_0::GnssData& data) override; private: @@ -761,6 +769,11 @@ struct GnssMeasurementCallback : public IGnssMeasurementCallback_V1_1 { void setMeasurementData(JNIEnv* env, jobject clock, jobjectArray measurementArray); }; +Return<void> GnssMeasurementCallback::gnssMeasurementCb_2_0( + const IGnssMeasurementCallback_V2_0::GnssData& data) { + // TODO(b/119571122): implement gnssMeasurementCb_2_0 + return Void(); +} Return<void> GnssMeasurementCallback::gnssMeasurementCb( const IGnssMeasurementCallback_V1_1::GnssData& data) { @@ -1126,13 +1139,22 @@ Return<void> GnssBatchingCallback::gnssLocationBatchCb(const hidl_vec<GnssLocati } static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { + gnssHal_V2_0 = IGnss_V2_0::getService(); + if (gnssHal_V2_0 != nullptr) { + gnssHal = gnssHal_V2_0; + gnssHal_V1_1 = gnssHal_V2_0; + return; + } + + ALOGD("gnssHal 2.0 was null, trying 1.1"); gnssHal_V1_1 = IGnss_V1_1::getService(); - if (gnssHal_V1_1 == nullptr) { - ALOGD("gnssHal 1.1 was null, trying 1.0"); - gnssHal = IGnss_V1_0::getService(); - } else { + if (gnssHal_V1_1 != nullptr) { gnssHal = gnssHal_V1_1; + return; } + + ALOGD("gnssHal 1.1 was null, trying 1.0"); + gnssHal = IGnss_V1_0::getService(); } static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass clazz) { @@ -1187,110 +1209,120 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass LOG_ALWAYS_FATAL("Unable to get Java VM. Error: %d", jvmStatus); } - if (gnssHal != nullptr) { - gnssHalDeathRecipient = new GnssDeathRecipient(); - hardware::Return<bool> linked = gnssHal->linkToDeath( - gnssHalDeathRecipient, /*cookie*/ 0); - if (!linked.isOk()) { - ALOGE("Transaction error in linking to GnssHAL death: %s", - linked.description().c_str()); - } else if (!linked) { - ALOGW("Unable to link to GnssHal death notifications"); - } else { - ALOGD("Link to death notification successful"); - } + if (gnssHal == nullptr) { + ALOGE("Unable to get GPS service\n"); + return; + } - auto gnssXtra = gnssHal->getExtensionXtra(); - if (!gnssXtra.isOk()) { - ALOGD("Unable to get a handle to Xtra"); - } else { - gnssXtraIface = gnssXtra; - } + gnssHalDeathRecipient = new GnssDeathRecipient(); + hardware::Return<bool> linked = gnssHal->linkToDeath(gnssHalDeathRecipient, /*cookie*/ 0); + if (!linked.isOk()) { + ALOGE("Transaction error in linking to GnssHAL death: %s", + linked.description().c_str()); + } else if (!linked) { + ALOGW("Unable to link to GnssHal death notifications"); + } else { + ALOGD("Link to death notification successful"); + } - auto gnssRil = gnssHal->getExtensionAGnssRil(); - if (!gnssRil.isOk()) { - ALOGD("Unable to get a handle to AGnssRil"); - } else { - agnssRilIface = gnssRil; - } + auto gnssXtra = gnssHal->getExtensionXtra(); + if (!gnssXtra.isOk()) { + ALOGD("Unable to get a handle to Xtra"); + } else { + gnssXtraIface = gnssXtra; + } - auto gnssAgnss = gnssHal->getExtensionAGnss(); - if (!gnssAgnss.isOk()) { - ALOGD("Unable to get a handle to AGnss"); - } else { - agnssIface = gnssAgnss; - } + auto gnssRil = gnssHal->getExtensionAGnssRil(); + if (!gnssRil.isOk()) { + ALOGD("Unable to get a handle to AGnssRil"); + } else { + agnssRilIface = gnssRil; + } - auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage(); - if (!gnssNavigationMessage.isOk()) { - ALOGD("Unable to get a handle to GnssNavigationMessage"); - } else { - gnssNavigationMessageIface = gnssNavigationMessage; - } + auto gnssAgnss = gnssHal->getExtensionAGnss(); + if (!gnssAgnss.isOk()) { + ALOGD("Unable to get a handle to AGnss"); + } else { + agnssIface = gnssAgnss; + } - if (gnssHal_V1_1 != nullptr) { - auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1(); - if (!gnssMeasurement.isOk()) { - ALOGD("Unable to get a handle to GnssMeasurement"); - } else { - gnssMeasurementIface_V1_1 = gnssMeasurement; - gnssMeasurementIface = gnssMeasurementIface_V1_1; - } - } else { - auto gnssMeasurement_V1_0 = gnssHal->getExtensionGnssMeasurement(); - if (!gnssMeasurement_V1_0.isOk()) { - ALOGD("Unable to get a handle to GnssMeasurement"); - } else { - gnssMeasurementIface = gnssMeasurement_V1_0; - } - } + auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage(); + if (!gnssNavigationMessage.isOk()) { + ALOGD("Unable to get a handle to GnssNavigationMessage"); + } else { + gnssNavigationMessageIface = gnssNavigationMessage; + } - auto gnssDebug = gnssHal->getExtensionGnssDebug(); - if (!gnssDebug.isOk()) { - ALOGD("Unable to get a handle to GnssDebug"); + if (gnssHal_V2_0 != nullptr) { + // TODO(b/119638366): getExtensionGnssMeasurement_1_1 from gnssHal_V2_0 + auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0(); + if (!gnssMeasurement.isOk()) { + ALOGD("Unable to get a handle to GnssMeasurement_V2_0"); } else { - gnssDebugIface = gnssDebug; + gnssMeasurementIface_V2_0 = gnssMeasurement; + gnssMeasurementIface_V1_1 = gnssMeasurementIface_V2_0; + gnssMeasurementIface = gnssMeasurementIface_V2_0; } + } else if (gnssHal_V1_1 != nullptr) { + auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1(); + if (!gnssMeasurement.isOk()) { + ALOGD("Unable to get a handle to GnssMeasurement_V1_1"); + } else { + gnssMeasurementIface_V1_1 = gnssMeasurement; + gnssMeasurementIface = gnssMeasurementIface_V1_1; + } + } else { + auto gnssMeasurement_V1_0 = gnssHal->getExtensionGnssMeasurement(); + if (!gnssMeasurement_V1_0.isOk()) { + ALOGD("Unable to get a handle to GnssMeasurement"); + } else { + gnssMeasurementIface = gnssMeasurement_V1_0; + } + } - auto gnssNi = gnssHal->getExtensionGnssNi(); - if (!gnssNi.isOk()) { - ALOGD("Unable to get a handle to GnssNi"); - } else { - gnssNiIface = gnssNi; - } + auto gnssDebug = gnssHal->getExtensionGnssDebug(); + if (!gnssDebug.isOk()) { + ALOGD("Unable to get a handle to GnssDebug"); + } else { + gnssDebugIface = gnssDebug; + } - if (gnssHal_V1_1 != nullptr) { - auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1(); - if (!gnssConfiguration.isOk()) { - ALOGD("Unable to get a handle to GnssConfiguration"); - } else { - gnssConfigurationIface_V1_1 = gnssConfiguration; - gnssConfigurationIface = gnssConfigurationIface_V1_1; - } - } else { - auto gnssConfiguration_V1_0 = gnssHal->getExtensionGnssConfiguration(); - if (!gnssConfiguration_V1_0.isOk()) { - ALOGD("Unable to get a handle to GnssConfiguration"); - } else { - gnssConfigurationIface = gnssConfiguration_V1_0; - } - } + auto gnssNi = gnssHal->getExtensionGnssNi(); + if (!gnssNi.isOk()) { + ALOGD("Unable to get a handle to GnssNi"); + } else { + gnssNiIface = gnssNi; + } - auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing(); - if (!gnssGeofencing.isOk()) { - ALOGD("Unable to get a handle to GnssGeofencing"); + if (gnssHal_V1_1 != nullptr) { + auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1(); + if (!gnssConfiguration.isOk()) { + ALOGD("Unable to get a handle to GnssConfiguration"); } else { - gnssGeofencingIface = gnssGeofencing; + gnssConfigurationIface_V1_1 = gnssConfiguration; + gnssConfigurationIface = gnssConfigurationIface_V1_1; } - - auto gnssBatching = gnssHal->getExtensionGnssBatching(); - if (!gnssBatching.isOk()) { - ALOGD("Unable to get a handle to gnssBatching"); + } else { + auto gnssConfiguration_V1_0 = gnssHal->getExtensionGnssConfiguration(); + if (!gnssConfiguration_V1_0.isOk()) { + ALOGD("Unable to get a handle to GnssConfiguration"); } else { - gnssBatchingIface = gnssBatching; + gnssConfigurationIface = gnssConfiguration_V1_0; } + } + + auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing(); + if (!gnssGeofencing.isOk()) { + ALOGD("Unable to get a handle to GnssGeofencing"); + } else { + gnssGeofencingIface = gnssGeofencing; + } + + auto gnssBatching = gnssHal->getExtensionGnssBatching(); + if (!gnssBatching.isOk()) { + ALOGD("Unable to get a handle to gnssBatching"); } else { - ALOGE("Unable to get GPS service\n"); + gnssBatchingIface = gnssBatching; } } @@ -1820,10 +1852,11 @@ static jboolean android_location_GnssMeasurementsProvider_start_measurement_coll sp<GnssMeasurementCallback> cbIface = new GnssMeasurementCallback(); IGnssMeasurement_V1_0::GnssMeasurementStatus result = - IGnssMeasurement_V1_0::GnssMeasurementStatus::ERROR_GENERIC;; - if (gnssMeasurementIface_V1_1 != nullptr) { - result = gnssMeasurementIface_V1_1->setCallback_1_1(cbIface, - enableFullTracking); + IGnssMeasurement_V1_0::GnssMeasurementStatus::ERROR_GENERIC; + if (gnssMeasurementIface_V2_0 != nullptr) { + result = gnssMeasurementIface_V2_0->setCallback_2_0(cbIface, enableFullTracking); + } else if (gnssMeasurementIface_V1_1 != nullptr) { + result = gnssMeasurementIface_V1_1->setCallback_1_1(cbIface, enableFullTracking); } else { if (enableFullTracking == JNI_TRUE) { // full tracking mode not supported in 1.0 HAL @@ -1837,7 +1870,7 @@ static jboolean android_location_GnssMeasurementsProvider_start_measurement_coll static_cast<int32_t>(result)); return JNI_FALSE; } else { - ALOGD("gnss measurement infc has been enabled"); + ALOGD("gnss measurement infc has been enabled"); } return JNI_TRUE; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index d6e62087f277..56f7cff565af 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -177,7 +177,7 @@ public final class SystemServer { * them from the build system somehow. */ private static final String BACKUP_MANAGER_SERVICE_CLASS = - "com.android.server.backup.GlobalBackupManagerService$Lifecycle"; + "com.android.server.backup.BackupManagerService$Lifecycle"; private static final String APPWIDGET_SERVICE_CLASS = "com.android.server.appwidget.AppWidgetService"; private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS = diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index dc55179bdc9e..c9b9f3e6bd48 100644 --- a/services/print/java/com/android/server/print/PrintManagerService.java +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -146,13 +146,14 @@ public final class PrintManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { disabledMessage = dpmi.getPrintingDisabledReasonForUser(callingUserId); + + if (disabledMessage != null) { + Toast.makeText(mContext, Looper.getMainLooper(), disabledMessage, + Toast.LENGTH_LONG).show(); + } } finally { Binder.restoreCallingIdentity(identity); } - if (disabledMessage != null) { - Toast.makeText(mContext, Looper.getMainLooper(), disabledMessage, - Toast.LENGTH_LONG).show(); - } try { adapter.start(); } catch (RemoteException re) { diff --git a/services/robotests/src/com/android/server/backup/GlobalBackupManagerServiceTest.java b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java index 3108c804b6f4..ba4caf44024b 100644 --- a/services/robotests/src/com/android/server/backup/GlobalBackupManagerServiceTest.java +++ b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java @@ -49,43 +49,43 @@ import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; -/** Tests for the user-aware backup/restore system service {@link GlobalBackupManagerService}. */ +/** Tests for the user-aware backup/restore system service {@link BackupManagerService}. */ @RunWith(RobolectricTestRunner.class) @Presubmit -public class GlobalBackupManagerServiceTest { +public class BackupManagerServiceTest { private static final String TEST_PACKAGE = "package"; private static final String TEST_TRANSPORT = "transport"; @Mock private UserBackupManagerService mUserBackupManagerService; @Mock private TransportManager mTransportManager; - private GlobalBackupManagerService mGlobalBackupManagerService; + private BackupManagerService mBackupManagerService; private Context mContext; - /** Initialize {@link GlobalBackupManagerService}. */ + /** Initialize {@link BackupManagerService}. */ @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); Application application = RuntimeEnvironment.application; mContext = application; - mGlobalBackupManagerService = - new GlobalBackupManagerService( + mBackupManagerService = + new BackupManagerService( application, new Trampoline(application), BackupManagerServiceTestUtils.startBackupThread(null), new File(application.getCacheDir(), "base_state"), new File(application.getCacheDir(), "data"), mTransportManager); - mGlobalBackupManagerService.setUserBackupManagerService(mUserBackupManagerService); + mBackupManagerService.setUserBackupManagerService(mUserBackupManagerService); } /** - * Test verifying that {@link GlobalBackupManagerService#MORE_DEBUG} is set to {@code false}. + * Test verifying that {@link BackupManagerService#MORE_DEBUG} is set to {@code false}. * This is specifically to prevent overloading the logs in production. */ @Test public void testMoreDebug_isFalse() throws Exception { - boolean moreDebug = GlobalBackupManagerService.MORE_DEBUG; + boolean moreDebug = BackupManagerService.MORE_DEBUG; assertThat(moreDebug).isFalse(); } @@ -101,7 +101,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testDataChanged_callsDataChangedForUser() throws Exception { - mGlobalBackupManagerService.dataChanged(TEST_PACKAGE); + mBackupManagerService.dataChanged(TEST_PACKAGE); verify(mUserBackupManagerService).dataChanged(TEST_PACKAGE); } @@ -111,7 +111,7 @@ public class GlobalBackupManagerServiceTest { public void testAgentConnected_callsAgentConnectedForUser() throws Exception { IBinder agentBinder = mock(IBinder.class); - mGlobalBackupManagerService.agentConnected(TEST_PACKAGE, agentBinder); + mBackupManagerService.agentConnected(TEST_PACKAGE, agentBinder); verify(mUserBackupManagerService).agentConnected(TEST_PACKAGE, agentBinder); } @@ -119,7 +119,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testAgentDisconnected_callsAgentDisconnectedForUser() throws Exception { - mGlobalBackupManagerService.agentDisconnected(TEST_PACKAGE); + mBackupManagerService.agentDisconnected(TEST_PACKAGE); verify(mUserBackupManagerService).agentDisconnected(TEST_PACKAGE); } @@ -127,7 +127,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testOpComplete_callsOpCompleteForUser() throws Exception { - mGlobalBackupManagerService.opComplete(/* token */ 0, /* result */ 0L); + mBackupManagerService.opComplete(/* token */ 0, /* result */ 0L); verify(mUserBackupManagerService).opComplete(/* token */ 0, /* result */ 0L); } @@ -141,7 +141,7 @@ public class GlobalBackupManagerServiceTest { public void testInitializeTransports_callsInitializeTransportsForUser() throws Exception { String[] transports = {TEST_TRANSPORT}; - mGlobalBackupManagerService.initializeTransports(transports, /* observer */ null); + mBackupManagerService.initializeTransports(transports, /* observer */ null); verify(mUserBackupManagerService).initializeTransports(transports, /* observer */ null); } @@ -149,7 +149,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testClearBackupData_callsClearBackupDataForUser() throws Exception { - mGlobalBackupManagerService.clearBackupData(TEST_TRANSPORT, TEST_PACKAGE); + mBackupManagerService.clearBackupData(TEST_TRANSPORT, TEST_PACKAGE); verify(mUserBackupManagerService).clearBackupData(TEST_TRANSPORT, TEST_PACKAGE); } @@ -157,7 +157,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetCurrentTransport_callsGetCurrentTransportForUser() throws Exception { - mGlobalBackupManagerService.getCurrentTransport(); + mBackupManagerService.getCurrentTransport(); verify(mUserBackupManagerService).getCurrentTransport(); } @@ -166,7 +166,7 @@ public class GlobalBackupManagerServiceTest { @Test public void testGetCurrentTransportComponent_callsGetCurrentTransportComponentForUser() throws Exception { - mGlobalBackupManagerService.getCurrentTransportComponent(); + mBackupManagerService.getCurrentTransportComponent(); verify(mUserBackupManagerService).getCurrentTransportComponent(); } @@ -174,7 +174,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testListAllTransports_callsListAllTransportsForUser() throws Exception { - mGlobalBackupManagerService.listAllTransports(); + mBackupManagerService.listAllTransports(); verify(mUserBackupManagerService).listAllTransports(); } @@ -183,7 +183,7 @@ public class GlobalBackupManagerServiceTest { @Test public void testListAllTransportComponents_callsListAllTransportComponentsForUser() throws Exception { - mGlobalBackupManagerService.listAllTransportComponents(); + mBackupManagerService.listAllTransportComponents(); verify(mUserBackupManagerService).listAllTransportComponents(); } @@ -191,7 +191,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetTransportWhitelist_callsGetTransportWhitelistForUser() throws Exception { - mGlobalBackupManagerService.getTransportWhitelist(); + mBackupManagerService.getTransportWhitelist(); verify(mUserBackupManagerService).getTransportWhitelist(); } @@ -204,7 +204,7 @@ public class GlobalBackupManagerServiceTest { Intent configurationIntent = new Intent(); Intent dataManagementIntent = new Intent(); - mGlobalBackupManagerService.updateTransportAttributes( + mBackupManagerService.updateTransportAttributes( transport.getTransportComponent(), transport.transportName, configurationIntent, @@ -225,7 +225,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testSelectBackupTransport_callsSelectBackupTransportForUser() throws Exception { - mGlobalBackupManagerService.selectBackupTransport(TEST_TRANSPORT); + mBackupManagerService.selectBackupTransport(TEST_TRANSPORT); verify(mUserBackupManagerService).selectBackupTransport(TEST_TRANSPORT); } @@ -236,7 +236,7 @@ public class GlobalBackupManagerServiceTest { TransportData transport = backupTransport(); ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class); - mGlobalBackupManagerService.selectBackupTransportAsync( + mBackupManagerService.selectBackupTransportAsync( transport.getTransportComponent(), callback); verify(mUserBackupManagerService) @@ -246,7 +246,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetConfigurationIntent_callsGetConfigurationIntentForUser() throws Exception { - mGlobalBackupManagerService.getConfigurationIntent(TEST_TRANSPORT); + mBackupManagerService.getConfigurationIntent(TEST_TRANSPORT); verify(mUserBackupManagerService).getConfigurationIntent(TEST_TRANSPORT); } @@ -254,7 +254,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetDestinationString_callsGetDestinationStringForUser() throws Exception { - mGlobalBackupManagerService.getDestinationString(TEST_TRANSPORT); + mBackupManagerService.getDestinationString(TEST_TRANSPORT); verify(mUserBackupManagerService).getDestinationString(TEST_TRANSPORT); } @@ -262,7 +262,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetDataManagementIntent_callsGetDataManagementIntentForUser() throws Exception { - mGlobalBackupManagerService.getDataManagementIntent(TEST_TRANSPORT); + mBackupManagerService.getDataManagementIntent(TEST_TRANSPORT); verify(mUserBackupManagerService).getDataManagementIntent(TEST_TRANSPORT); } @@ -270,7 +270,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetDataManagementLabel_callsGetDataManagementLabelForUser() throws Exception { - mGlobalBackupManagerService.getDataManagementLabel(TEST_TRANSPORT); + mBackupManagerService.getDataManagementLabel(TEST_TRANSPORT); verify(mUserBackupManagerService).getDataManagementLabel(TEST_TRANSPORT); } @@ -282,7 +282,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void setBackupEnabled_callsSetBackupEnabledForUser() throws Exception { - mGlobalBackupManagerService.setBackupEnabled(true); + mBackupManagerService.setBackupEnabled(true); verify(mUserBackupManagerService).setBackupEnabled(true); } @@ -290,7 +290,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void setAutoRestore_callsSetAutoRestoreForUser() throws Exception { - mGlobalBackupManagerService.setAutoRestore(true); + mBackupManagerService.setAutoRestore(true); verify(mUserBackupManagerService).setAutoRestore(true); } @@ -298,7 +298,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testSetBackupProvisioned_callsSetBackupProvisionedForUser() throws Exception { - mGlobalBackupManagerService.setBackupProvisioned(true); + mBackupManagerService.setBackupProvisioned(true); verify(mUserBackupManagerService).setBackupProvisioned(true); } @@ -306,7 +306,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testIsBackupEnabled_callsIsBackupEnabledForUser() throws Exception { - mGlobalBackupManagerService.isBackupEnabled(); + mBackupManagerService.isBackupEnabled(); verify(mUserBackupManagerService).isBackupEnabled(); } @@ -318,7 +318,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testIsAppEligibleForBackup_callsIsAppEligibleForBackupForUser() throws Exception { - mGlobalBackupManagerService.isAppEligibleForBackup(TEST_PACKAGE); + mBackupManagerService.isAppEligibleForBackup(TEST_PACKAGE); verify(mUserBackupManagerService).isAppEligibleForBackup(TEST_PACKAGE); } @@ -329,7 +329,7 @@ public class GlobalBackupManagerServiceTest { throws Exception { String[] packages = {TEST_PACKAGE}; - mGlobalBackupManagerService.filterAppsEligibleForBackup(packages); + mBackupManagerService.filterAppsEligibleForBackup(packages); verify(mUserBackupManagerService).filterAppsEligibleForBackup(packages); } @@ -337,7 +337,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testBackupNow_callsBackupNowForUser() throws Exception { - mGlobalBackupManagerService.backupNow(); + mBackupManagerService.backupNow(); verify(mUserBackupManagerService).backupNow(); } @@ -349,7 +349,7 @@ public class GlobalBackupManagerServiceTest { IBackupObserver observer = mock(IBackupObserver.class); IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class); - mGlobalBackupManagerService.requestBackup(packages, observer, monitor, /* flags */ 0); + mBackupManagerService.requestBackup(packages, observer, monitor, /* flags */ 0); verify(mUserBackupManagerService).requestBackup(packages, observer, monitor, /* flags */ 0); } @@ -357,7 +357,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testCancelBackups_callsCancelBackupsForUser() throws Exception { - mGlobalBackupManagerService.cancelBackups(); + mBackupManagerService.cancelBackups(); verify(mUserBackupManagerService).cancelBackups(); } @@ -367,7 +367,7 @@ public class GlobalBackupManagerServiceTest { public void testBeginFullBackup_callsBeginFullBackupForUser() throws Exception { FullBackupJob job = new FullBackupJob(); - mGlobalBackupManagerService.beginFullBackup(job); + mBackupManagerService.beginFullBackup(job); verify(mUserBackupManagerService).beginFullBackup(job); } @@ -375,7 +375,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testEndFullBackup_callsEndFullBackupForUser() throws Exception { - mGlobalBackupManagerService.endFullBackup(); + mBackupManagerService.endFullBackup(); verify(mUserBackupManagerService).endFullBackup(); } @@ -385,7 +385,7 @@ public class GlobalBackupManagerServiceTest { public void testFullTransportBackup_callsFullTransportBackupForUser() throws Exception { String[] packages = {TEST_PACKAGE}; - mGlobalBackupManagerService.fullTransportBackup(packages); + mBackupManagerService.fullTransportBackup(packages); verify(mUserBackupManagerService).fullTransportBackup(packages); } @@ -397,7 +397,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testRestoreAtInstall_callsRestoreAtInstallForUser() throws Exception { - mGlobalBackupManagerService.restoreAtInstall(TEST_PACKAGE, /* token */ 0); + mBackupManagerService.restoreAtInstall(TEST_PACKAGE, /* token */ 0); verify(mUserBackupManagerService).restoreAtInstall(TEST_PACKAGE, /* token */ 0); } @@ -405,7 +405,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testBeginRestoreSession_callsBeginRestoreSessionForUser() throws Exception { - mGlobalBackupManagerService.beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT); + mBackupManagerService.beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT); verify(mUserBackupManagerService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT); } @@ -414,7 +414,7 @@ public class GlobalBackupManagerServiceTest { @Test public void testGetAvailableRestoreToken_callsGetAvailableRestoreTokenForUser() throws Exception { - mGlobalBackupManagerService.getAvailableRestoreToken(TEST_PACKAGE); + mBackupManagerService.getAvailableRestoreToken(TEST_PACKAGE); verify(mUserBackupManagerService).getAvailableRestoreToken(TEST_PACKAGE); } @@ -426,7 +426,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testSetBackupPassword_callsSetBackupPasswordForUser() throws Exception { - mGlobalBackupManagerService.setBackupPassword("currentPassword", "newPassword"); + mBackupManagerService.setBackupPassword("currentPassword", "newPassword"); verify(mUserBackupManagerService).setBackupPassword("currentPassword", "newPassword"); } @@ -434,7 +434,7 @@ public class GlobalBackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testHasBackupPassword_callsHasBackupPasswordForUser() throws Exception { - mGlobalBackupManagerService.hasBackupPassword(); + mBackupManagerService.hasBackupPassword(); verify(mUserBackupManagerService).hasBackupPassword(); } @@ -448,7 +448,7 @@ public class GlobalBackupManagerServiceTest { ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE); String[] packages = {TEST_PACKAGE}; - mGlobalBackupManagerService.adbBackup( + mBackupManagerService.adbBackup( parcelFileDescriptor, /* includeApks */ true, /* includeObbs */ true, @@ -482,7 +482,7 @@ public class GlobalBackupManagerServiceTest { ParcelFileDescriptor parcelFileDescriptor = ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE); - mGlobalBackupManagerService.adbRestore(parcelFileDescriptor); + mBackupManagerService.adbRestore(parcelFileDescriptor); verify(mUserBackupManagerService).adbRestore(parcelFileDescriptor); } @@ -493,7 +493,7 @@ public class GlobalBackupManagerServiceTest { throws Exception { IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class); - mGlobalBackupManagerService.acknowledgeAdbBackupOrRestore( + mBackupManagerService.acknowledgeAdbBackupOrRestore( /* token */ 0, /* allow */ true, "currentPassword", "encryptionPassword", observer); verify(mUserBackupManagerService) @@ -518,7 +518,7 @@ public class GlobalBackupManagerServiceTest { PrintWriter printWriter = new PrintWriter(testFile); String[] args = {"1", "2"}; - mGlobalBackupManagerService.dump(fileDescriptor, printWriter, args); + mBackupManagerService.dump(fileDescriptor, printWriter, args); verify(mUserBackupManagerService).dump(fileDescriptor, printWriter, args); } diff --git a/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java b/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java index 8ec0759e52db..a14cc51a3ab6 100644 --- a/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java +++ b/services/robotests/src/com/android/server/backup/internal/PerformInitializeTaskTest.java @@ -44,7 +44,7 @@ import android.platform.test.annotations.Presubmit; import android.util.Log; import com.android.internal.backup.IBackupTransport; -import com.android.server.backup.GlobalBackupManagerService; +import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.testing.TransportData; @@ -212,7 +212,7 @@ public class PerformInitializeTaskTest { performInitializeTask.run(); assertLogcatContains( - GlobalBackupManagerService.TAG, + BackupManagerService.TAG, log -> log.msg.contains("finishBackup()") && log.type >= Log.ERROR); } @@ -225,7 +225,7 @@ public class PerformInitializeTaskTest { performInitializeTask.run(); assertLogcatContains( - GlobalBackupManagerService.TAG, + BackupManagerService.TAG, log -> log.msg.contains("initializeDevice()") && log.type >= Log.ERROR); } diff --git a/services/tests/servicestests/res/raw/input_port_associations.xml b/services/tests/servicestests/res/raw/input_port_associations.xml new file mode 100644 index 000000000000..b10d541f942c --- /dev/null +++ b/services/tests/servicestests/res/raw/input_port_associations.xml @@ -0,0 +1,4 @@ +<ports> + <port display="0" input="USB1" /> + <port display="1" input="USB2" /> +</ports>
\ No newline at end of file diff --git a/services/tests/servicestests/res/raw/input_port_associations_bad_displayport.xml b/services/tests/servicestests/res/raw/input_port_associations_bad_displayport.xml new file mode 100644 index 000000000000..8eeb1f58ef9e --- /dev/null +++ b/services/tests/servicestests/res/raw/input_port_associations_bad_displayport.xml @@ -0,0 +1,3 @@ +<ports> + <port display="a" input="USB1" /> +</ports>
\ No newline at end of file diff --git a/services/tests/servicestests/res/raw/input_port_associations_bad_xml.xml b/services/tests/servicestests/res/raw/input_port_associations_bad_xml.xml new file mode 100644 index 000000000000..cf6e12486239 --- /dev/null +++ b/services/tests/servicestests/res/raw/input_port_associations_bad_xml.xml @@ -0,0 +1,3 @@ +<ports> + <port Garbage data inside xml> +</ports>
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java index c99e2a850679..7c002995a769 100644 --- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java @@ -83,7 +83,7 @@ public class TrampolineTest { }; private final int NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 1; - @Mock private GlobalBackupManagerService mBackupManagerServiceMock; + @Mock private BackupManagerService mBackupManagerServiceMock; @Mock private Context mContextMock; @Mock private File mSuppressFileMock; @Mock private File mSuppressFileParentMock; @@ -864,7 +864,7 @@ public class TrampolineTest { static boolean sBackupDisabled = false; static File sSuppressFile = null; static int sCallingUid = -1; - static GlobalBackupManagerService sBackupManagerServiceMock = null; + static BackupManagerService sBackupManagerServiceMock = null; private int mCreateServiceCallsCount = 0; TrampolineTestable(Context context) { @@ -887,7 +887,7 @@ public class TrampolineTest { } @Override - protected GlobalBackupManagerService createBackupManagerService() { + protected BackupManagerService createBackupManagerService() { mCreateServiceCallsCount++; return sBackupManagerServiceMock; } diff --git a/services/tests/servicestests/src/com/android/server/input/ConfigurationProcessorTest.java b/services/tests/servicestests/src/com/android/server/input/ConfigurationProcessorTest.java new file mode 100644 index 000000000000..636aa375a84c --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/input/ConfigurationProcessorTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2018 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.input; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.content.Context; +import android.util.Pair; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.InputStream; +import java.util.List; + +/** + * Build/Install/Run: + * atest ConfigurationProcessorTest + */ +@RunWith(AndroidJUnit4.class) +public class ConfigurationProcessorTest { + + private Context mContext; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getContext(); + } + + @Test + public void testGetInputPortAssociations() { + final int res = com.android.frameworks.servicestests.R.raw.input_port_associations; + InputStream xml = mContext.getResources().openRawResource(res); + List<Pair<String, String>> associations = null; + try { + associations = ConfigurationProcessor.processInputPortAssociations(xml); + } catch (Exception e) { + fail("Could not process xml file for input associations"); + } + assertNotNull(associations); + assertEquals(2, associations.size()); + assertTrue(associations.contains(Pair.create("USB1", "0"))); + assertTrue(associations.contains(Pair.create("USB2", "1"))); + } + + @Test + public void testGetInputPortAssociationsBadDisplayport() { + final int res = + com.android.frameworks.servicestests.R.raw.input_port_associations_bad_displayport; + InputStream xml = mContext.getResources().openRawResource(res); + List<Pair<String, String>> associations = null; + try { + associations = ConfigurationProcessor.processInputPortAssociations(xml); + } catch (Exception e) { + fail("Could not process xml file for input associations"); + } + assertNotNull(associations); + assertEquals(0, associations.size()); + } + + @Test + public void testGetInputPortAssociationsEmptyConfig() { + final int res = com.android.frameworks.servicestests.R.raw.input_port_associations_bad_xml; + InputStream xml = mContext.getResources().openRawResource(res); + try { + ConfigurationProcessor.processInputPortAssociations(xml); + fail("Parsing should fail, because xml contains bad data"); + } catch (Exception e) { + // This is expected + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SP800DeriveTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SP800DeriveTests.java new file mode 100644 index 000000000000..fc2dcb9cc83b --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/locksettings/SP800DeriveTests.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.locksettings; + +import android.test.AndroidTestCase; + +import com.android.internal.util.HexDump; + +public class SP800DeriveTests extends AndroidTestCase { + public void testFixedInput() throws Exception { + // CAVP: https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/key-derivation + byte[] keyBytes = HexDump.hexStringToByteArray( + "e204d6d466aad507ffaf6d6dab0a5b26" + + "152c9e21e764370464e360c8fbc765c6"); + SP800Derive sk = new SP800Derive(keyBytes); + byte[] fixedInput = HexDump.hexStringToByteArray( + "7b03b98d9f94b899e591f3ef264b71b1" + + "93fba7043c7e953cde23bc5384bc1a62" + + "93580115fae3495fd845dadbd02bd645" + + "5cf48d0f62b33e62364a3a80"); + byte[] res = sk.fixedInput(fixedInput); + assertEquals(( + "770dfab6a6a4a4bee0257ff335213f78" + + "d8287b4fd537d5c1fffa956910e7c779").toUpperCase(), HexDump.toHexString(res)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 92efc3cc2b3c..99b827c11853 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.net; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.TYPE_WIFI; @@ -72,7 +72,6 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; @@ -142,9 +141,8 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent; -import com.android.server.net.NetworkPolicyManagerInternal; -import com.android.server.net.NetworkPolicyManagerService; -import com.android.server.net.NetworkStatsManagerInternal; +import com.android.server.DeviceIdleController; +import com.android.server.LocalServices; import com.google.common.util.concurrent.AbstractFuture; @@ -195,15 +193,6 @@ import java.util.stream.Collectors; /** * Tests for {@link NetworkPolicyManagerService}. - * - * <p>Typical usage: - * - * <pre><code> - m -j32 FrameworksServicesTests && adb install -r -g \ - ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && \ - adb shell am instrument -e class "com.android.server.NetworkPolicyManagerServiceTest" -w \ - "com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner" - * </code></pre> */ @RunWith(AndroidJUnit4.class) @MediumTest @@ -376,7 +365,7 @@ public class NetworkPolicyManagerServiceTest { return null; } }).when(mActivityManager).registerUidObserver(any(), anyInt(), - eq(NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE), isNull(String.class)); + eq(NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE), any(String.class)); mFutureIntent = newRestrictBackgroundChangedFuture(); mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, @@ -425,7 +414,7 @@ public class NetworkPolicyManagerServiceTest { // catch INetworkManagementEventObserver during systemReady() final ArgumentCaptor<INetworkManagementEventObserver> networkObserver = - ArgumentCaptor.forClass(INetworkManagementEventObserver.class); + ArgumentCaptor.forClass(INetworkManagementEventObserver.class); verify(mNetworkManager).registerObserver(networkObserver.capture()); mNetworkObserver = networkObserver.getValue(); @@ -1782,7 +1771,7 @@ public class NetworkPolicyManagerServiceTest { } private static NetworkPolicy buildFakeMobilePolicy(int cycleDay, long warningBytes, - long limitBytes, boolean inferred){ + long limitBytes, boolean inferred) { final NetworkTemplate template = buildTemplateMobileAll(FAKE_SUBSCRIBER_ID); return new NetworkPolicy(template, cycleDay, new Time().timezone, warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, true, inferred); @@ -1880,7 +1869,7 @@ public class NetworkPolicyManagerServiceTest { } private static void assertNotificationType(int expected, String actualTag) { - assertEquals("notification type mismatch for '" + actualTag +"'", + assertEquals("notification type mismatch for '" + actualTag + "'", Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1)); } @@ -1914,7 +1903,8 @@ public class NetworkPolicyManagerServiceTest { final String action = ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; final Intent intent = future.get(5, TimeUnit.SECONDS); assertNotNull("Didn't get a " + action + "intent in 5 seconds"); - assertEquals("Wrong package on " + action + " intent", expectedPackage, intent.getPackage()); + assertEquals("Wrong package on " + action + " intent", + expectedPackage, intent.getPackage()); } // TODO: replace by Truth, Hamcrest, or a similar tool. @@ -1935,7 +1925,7 @@ public class NetworkPolicyManagerServiceTest { } if (errors.length() > 0) { fail("assertContainsInAnyOrder(expected=" + Arrays.toString(expected) - + ", actual=" + Arrays.toString(actual) +") failed: \n" + errors); + + ", actual=" + Arrays.toString(actual) + ") failed: \n" + errors); } } @@ -1998,7 +1988,7 @@ public class NetworkPolicyManagerServiceTest { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Log.d(TAG,"counting down on answer: " + invocation); + Log.d(TAG, "counting down on answer: " + invocation); latch.countDown(); return null; } @@ -2036,8 +2026,8 @@ public class NetworkPolicyManagerServiceTest { final String assetPath = NETPOLICY_DIR + "/" + mNetpolicyXml; final File netConfigFile = new File(mPolicyDir, "netpolicy.xml"); Log.d(TAG, "Creating " + netConfigFile + " from asset " + assetPath); - try (final InputStream in = context.getResources().getAssets().open(assetPath); - final OutputStream out = new FileOutputStream(netConfigFile)) { + try (InputStream in = context.getResources().getAssets().open(assetPath); + OutputStream out = new FileOutputStream(netConfigFile)) { Streams.copy(in, out); } } @@ -2049,9 +2039,7 @@ public class NetworkPolicyManagerServiceTest { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface NetPolicyXml { - - public String value() default ""; - + String value() default ""; } /** diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index d7988656c9de..ce59e6ec9760 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -31,6 +31,7 @@ import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; +import android.content.pm.UsesPermissionInfo; import android.os.Bundle; import android.os.Parcel; import android.platform.test.annotations.Presubmit; @@ -464,6 +465,7 @@ public class PackageParserTest { pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo())); pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo())); pkg.requestedPermissions.add("foo7"); + pkg.usesPermissionInfos.add(new UsesPermissionInfo("foo7")); pkg.implicitPermissions.add("foo25"); pkg.protectedBroadcasts = new ArrayList<>(); diff --git a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java index 991981f62d30..a6415d1f2b1f 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java @@ -145,7 +145,7 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testUpdateDimsAppliesSize() { + public void testUpdateDimsAppliesCrop() { mDimmer.dimAbove(mTransaction, 0.8f); int width = 100; @@ -153,7 +153,7 @@ public class DimmerTests extends WindowTestsBase { Rect bounds = new Rect(0, 0, width, height); mDimmer.updateDims(mTransaction, bounds); - verify(mTransaction).setSize(getDimLayer(), width, height); + verify(mTransaction).setWindowCrop(getDimLayer(), width, height); verify(mTransaction).show(getDimLayer()); } @@ -242,13 +242,13 @@ public class DimmerTests extends WindowTestsBase { SurfaceControl dimLayer = getDimLayer(); bounds.set(0, 0, 10, 10); mDimmer.updateDims(mTransaction, bounds); + verify(mTransaction).setWindowCrop(dimLayer, bounds.width(), bounds.height()); verify(mTransaction, times(1)).show(dimLayer); - verify(mTransaction).setSize(dimLayer, bounds.width(), bounds.height()); verify(mTransaction).setPosition(dimLayer, 0, 0); bounds.set(10, 10, 30, 30); mDimmer.updateDims(mTransaction, bounds); - verify(mTransaction).setSize(dimLayer, bounds.width(), bounds.height()); + verify(mTransaction).setWindowCrop(dimLayer, bounds.width(), bounds.height()); verify(mTransaction).setPosition(dimLayer, 10, 10); } diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayWindowSettingsTests.java index b823e706a586..7f390a55232d 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayWindowSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayWindowSettingsTests.java @@ -27,7 +27,12 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.WindowConfiguration; import android.platform.test.annotations.Presubmit; @@ -378,6 +383,33 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { mSecondaryDisplay.getDisplayRotation().getUserRotation()); } + @Test + public void testNotFixedToUserRotationByDefault() { + mTarget.setUserRotation(mPrimaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED, + Surface.ROTATION_0); + + final DisplayRotation displayRotation = mock(DisplayRotation.class); + mPrimaryDisplay = spy(mPrimaryDisplay); + when(mPrimaryDisplay.getDisplayRotation()).thenReturn(displayRotation); + + mTarget.applySettingsToDisplayLocked(mPrimaryDisplay); + + verify(displayRotation).restoreSettings(anyInt(), anyInt(), eq(false)); + } + + @Test + public void testSetFixedToUserRotation() { + mTarget.setFixedToUserRotation(mPrimaryDisplay, true); + + final DisplayRotation displayRotation = mock(DisplayRotation.class); + mPrimaryDisplay = spy(mPrimaryDisplay); + when(mPrimaryDisplay.getDisplayRotation()).thenReturn(displayRotation); + + applySettingsToDisplayByNewInstance(mPrimaryDisplay); + + verify(displayRotation).restoreSettings(anyInt(), anyInt(), eq(true)); + } + private static void assertOverscan(DisplayContent display, int left, int top, int right, int bottom) { final DisplayInfo info = display.getDisplayInfo(); diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java index 55e766da09fc..ad293d963f3e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java @@ -171,7 +171,7 @@ public class DragDropControllerTests extends WindowTestsBase { try { final SurfaceControl surface = new SurfaceControl.Builder(appSession) .setName("drag surface") - .setSize(100, 100) + .setBufferSize(100, 100) .setFormat(PixelFormat.TRANSLUCENT) .build(); diff --git a/services/tests/servicestests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/servicestests/src/com/android/server/wm/InsetsSourceProviderTest.java new file mode 100644 index 000000000000..241b987e58ba --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 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 android.view.InsetsState.TYPE_TOP_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static org.junit.Assert.assertEquals; + +import android.graphics.Insets; +import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; +import android.view.InsetsSource; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@SmallTest +@FlakyTest(detail = "Promote once confirmed non-flaky") +@Presubmit +public class InsetsSourceProviderTest extends WindowTestsBase { + + private InsetsSourceProvider mProvider = new InsetsSourceProvider( + new InsetsSource(TYPE_TOP_BAR)); + + @Test + public void testPostLayout() { + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + topBar.getFrameLw().set(0, 0, 500, 100); + topBar.mHasSurface = true; + mProvider.setWindow(topBar, null); + mProvider.onPostLayout(); + assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame()); + assertEquals(Insets.of(0, 100, 0, 0), + mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500), + false /* ignoreVisibility */)); + } + + @Test + public void testPostLayout_invisible() { + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + topBar.getFrameLw().set(0, 0, 500, 100); + mProvider.setWindow(topBar, null); + mProvider.onPostLayout(); + assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500), + false /* ignoreVisibility */)); + } + + @Test + public void testPostLayout_frameProvider() { + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + topBar.getFrameLw().set(0, 0, 500, 100); + mProvider.setWindow(topBar, + (displayFrames, windowState, rect) -> { + rect.set(10, 10, 20, 20); + }); + mProvider.onPostLayout(); + assertEquals(new Rect(10, 10, 20, 20), mProvider.getSource().getFrame()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/InsetsStateControllerTest.java new file mode 100644 index 000000000000..7505db103bbf --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 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 android.view.InsetsState.TYPE_IME; +import static android.view.InsetsState.TYPE_NAVIGATION_BAR; +import static android.view.InsetsState.TYPE_TOP_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import android.platform.test.annotations.Presubmit; +import android.view.InsetsState; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@SmallTest +@FlakyTest(detail = "Promote once confirmed non-flaky") +@Presubmit +public class InsetsStateControllerTest extends WindowTestsBase { + + @Test + public void testStripForDispatch_notOwn() { + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + final WindowState app = createWindow(null, TYPE_APPLICATION, "parentWindow"); + mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR) + .setWindow(topBar, null); + topBar.setInsetProvider( + mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR)); + assertNotNull(mDisplayContent.getInsetsStateController().getInsetsForDispatch(app) + .getSource(TYPE_TOP_BAR)); + } + + @Test + public void testStripForDispatch_own() { + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR) + .setWindow(topBar, null); + topBar.setInsetProvider( + mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR)); + assertEquals(new InsetsState(), + mDisplayContent.getInsetsStateController().getInsetsForDispatch(topBar)); + } + + @Test + public void testStripForDispatch_navBar() { + final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + final WindowState ime = createWindow(null, TYPE_APPLICATION, "parentWindow"); + mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR) + .setWindow(topBar, null); + mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_NAVIGATION_BAR) + .setWindow(navBar, null); + mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_IME) + .setWindow(ime, null); + assertEquals(new InsetsState(), + mDisplayContent.getInsetsStateController().getInsetsForDispatch(navBar)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java index 6833dc5f0497..e638a6accf7c 100644 --- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -225,11 +225,9 @@ public class SurfaceAnimatorTest extends WindowTestsBase { mTransaction = transaction; mParent = wm.makeSurfaceBuilder(mSession) .setName("test surface parent") - .setSize(3000, 3000) .build(); mSurface = wm.makeSurfaceBuilder(mSession) .setName("test surface") - .setSize(1, 1) .build(); mFinishedCallbackCalled = false; mLeash = null; diff --git a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java index 99deeb9e9397..432af0d7a469 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java @@ -24,6 +24,7 @@ import android.util.MergedConfiguration; import android.view.DisplayCutout; import android.view.DragEvent; import android.view.IWindow; +import android.view.InsetsState; import com.android.internal.os.IResultReceiver; @@ -39,6 +40,9 @@ public class TestIWindow extends IWindow.Stub { Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId, DisplayCutout.ParcelableWrapper displayCutout) throws RemoteException { } + @Override + public void insetsChanged(InsetsState insetsState) throws RemoteException { + } @Override public void moved(int newX, int newY) throws RemoteException { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index fcd29e13a07b..d950360791d2 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -3711,4 +3711,23 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mAssistants).notifyAssistantSuggestedReplySent( eq(r.sbn), eq(reply), eq(generatedByAssistant)); } + + @Test + public void testOnNotificationActionClick() { + final int actionIndex = 2; + final Notification.Action action = + new Notification.Action.Builder(null, "text", null).build(); + final boolean generatedByAssistant = false; + + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); + mService.addNotification(r); + + NotificationVisibility notificationVisibility = + NotificationVisibility.obtain(r.getKey(), 1, 2, true); + mService.mNotificationDelegate.onNotificationActionClick( + 10, 10, r.getKey(), actionIndex, action, notificationVisibility, + generatedByAssistant); + verify(mAssistants).notifyAssistantActionClicked( + eq(r.sbn), eq(actionIndex), eq(action), eq(generatedByAssistant)); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 38d8e3990e00..6c7ede3df4db 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -41,6 +41,7 @@ import static org.mockito.Mockito.when; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.AutomaticZenRule; import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.content.ComponentName; @@ -1097,6 +1098,25 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertFalse(Objects.equals(defaultRuleName, ruleAfterUpdating.name)); // update name } + @Test + public void testAddAutomaticZenRule() { + AutomaticZenRule zenRule = new AutomaticZenRule("name", + new ComponentName("android", "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id = mZenModeHelperSpy.addAutomaticZenRule(zenRule, "test"); + + assertTrue(id != null); + ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); + assertTrue(ruleInConfig != null); + assertEquals(zenRule.isEnabled(), ruleInConfig.enabled); + assertEquals(zenRule.isModified(), ruleInConfig.modified); + assertEquals(zenRule.getConditionId(), ruleInConfig.conditionId); + assertEquals(NotificationManager.zenModeFromInterruptionFilter( + zenRule.getInterruptionFilter(), -1), ruleInConfig.zenMode); + assertEquals(zenRule.getName(), ruleInConfig.name); + } + private void setupZenConfig() { mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.allowAlarms = false; diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index f128b4e2de2b..67acec689244 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -37,6 +37,8 @@ <application android:debuggable="true" android:testOnly="true"> + <uses-library android:name="android.test.mock" android:required="true" /> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityA" /> <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityB" /> <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityRequestedOrientationChange" /> diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index 0e30037bde6c..cac9cf69ce4d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -24,20 +24,30 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions; +import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.timeout; import android.content.Intent; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.SparseIntArray; +import android.util.proto.ProtoOutputStream; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; +import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto; + +import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentMatcher; + +import java.util.Arrays; /** * Tests for the {@link ActivityMetricsLaunchObserver} class. @@ -51,6 +61,7 @@ import org.junit.Test; public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { private ActivityMetricsLogger mActivityMetricsLogger; private ActivityMetricsLaunchObserver mLaunchObserver; + private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry; private TestActivityStack mStack; private TaskRecord mTask; @@ -61,16 +72,13 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void setUpAMLO() throws Exception { setupActivityTaskManagerService(); - mActivityMetricsLogger = - new ActivityMetricsLogger(mSupervisor, mService.mContext, mService.mH.getLooper()); - mLaunchObserver = mock(ActivityMetricsLaunchObserver.class); - // TODO: Use ActivityMetricsLaunchObserverRegistry . - java.lang.reflect.Field f = - mActivityMetricsLogger.getClass().getDeclaredField("mLaunchObserver"); - f.setAccessible(true); - f.set(mActivityMetricsLogger, mLaunchObserver); + // ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger. + mActivityMetricsLogger = mSupervisor.getActivityMetricsLogger(); + + mLaunchObserverRegistry = mActivityMetricsLogger.getLaunchObserverRegistry(); + mLaunchObserverRegistry.registerLaunchObserver(mLaunchObserver); // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful. // This seems to be the easiest way to create an ActivityRecord. @@ -81,13 +89,45 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build(); } + @After + public void tearDownAMLO() throws Exception { + if (mLaunchObserverRegistry != null) { // Don't NPE if setUp failed. + mLaunchObserverRegistry.unregisterLaunchObserver(mLaunchObserver); + } + } + + static class ActivityRecordMatcher implements ArgumentMatcher</*@ActivityRecordProto*/ byte[]> { + private final @ActivityRecordProto byte[] mExpected; + + public ActivityRecordMatcher(ActivityRecord activityRecord) { + mExpected = activityRecordToProto(activityRecord); + } + + public boolean matches(@ActivityRecordProto byte[] actual) { + return Arrays.equals(mExpected, actual); + } + } + + static @ActivityRecordProto byte[] activityRecordToProto(ActivityRecord record) { + return ActivityMetricsLogger.convertActivityRecordToProto(record); + } + + static @ActivityRecordProto byte[] eqProto(ActivityRecord record) { + return argThat(new ActivityRecordMatcher(record)); + } + + static <T> T verifyAsync(T mock) { + // AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout. + return verify(mock, timeout(100)); + } + @Test public void testOnIntentStarted() throws Exception { Intent intent = new Intent("action 1"); mActivityMetricsLogger.notifyActivityLaunching(intent); - verify(mLaunchObserver).onIntentStarted(eq(intent)); + verifyAsync(mLaunchObserver).onIntentStarted(eq(intent)); verifyNoMoreInteractions(mLaunchObserver); } @@ -102,7 +142,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, activityRecord); - verify(mLaunchObserver).onIntentFailed(); + verifyAsync(mLaunchObserver).onIntentFailed(); verifyNoMoreInteractions(mLaunchObserver); } @@ -113,7 +153,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mActivityRecord); - verify(mLaunchObserver).onActivityLaunched(eq(mActivityRecord), anyInt()); + verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt()); verifyNoMoreInteractions(mLaunchObserver); } @@ -127,7 +167,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(), SystemClock.uptimeMillis()); - verify(mLaunchObserver).onActivityLaunchFinished(eq(mActivityRecord)); + verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecord)); verifyNoMoreInteractions(mLaunchObserver); } @@ -135,12 +175,12 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnActivityLaunchCancelled() throws Exception { testOnActivityLaunched(); - mActivityRecord.nowVisible = true; + mActivityRecord.mDrawn = true; // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecord); - verify(mLaunchObserver).onActivityLaunchCancelled(eq(mActivityRecord)); + verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecord)); verifyNoMoreInteractions(mLaunchObserver); } @@ -151,7 +191,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mActivityRecord); - verify(mLaunchObserver).onActivityLaunched(eq(mActivityRecord), anyInt()); + verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt()); // A second, distinct, activity launch is coalesced into the the current app launch sequence mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, @@ -170,7 +210,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(), SystemClock.uptimeMillis()); - verify(mLaunchObserver).onActivityLaunchFinished(eq(mActivityRecordTrampoline)); + verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecordTrampoline)); verifyNoMoreInteractions(mLaunchObserver); } @@ -178,13 +218,26 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnActivityLaunchCancelledTrampoline() throws Exception { testOnActivityLaunchedTrampoline(); - mActivityRecordTrampoline.nowVisible = true; + mActivityRecordTrampoline.mDrawn = true; // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecordTrampoline); - verify(mLaunchObserver).onActivityLaunchCancelled(eq(mActivityRecordTrampoline)); + verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecordTrampoline)); verifyNoMoreInteractions(mLaunchObserver); } + + @Test + public void testActivityRecordProtoIsNotTooBig() throws Exception { + // The ActivityRecordProto must not be too big, otherwise converting it at runtime + // will become prohibitively expensive. + assertWithMessage("mActivityRecord: %s", mActivityRecord). + that(activityRecordToProto(mActivityRecord).length). + isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); + + assertWithMessage("mActivityRecordTrampoline: %s", mActivityRecordTrampoline). + that(activityRecordToProto(mActivityRecordTrampoline).length). + isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 81e97c688e6e..ead9731782e8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -233,7 +233,9 @@ class ActivityTestsBase { aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */, mService.mStackSupervisor, null /* options */, null /* sourceRecord */); + spyOn(activity); activity.mAppWindowToken = mock(AppWindowToken.class); + doNothing().when(activity).removeWindowContainer(); if (mTaskRecord != null) { mTaskRecord.addActivityToTop(activity); @@ -245,7 +247,6 @@ class ActivityTestsBase { mock(WindowProcessListener.class)); wpc.setThread(mock(IApplicationThread.class)); activity.setProcess(wpc); - activity.service.mWindowManager.mRoot = mock(RootWindowContainer.class); return activity; } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java new file mode 100644 index 000000000000..e9889948c341 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -0,0 +1,823 @@ +/* + * Copyright (C) 2018 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 android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.atMost; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.same; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.PowerManagerInternal; +import android.os.SystemClock; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.view.Surface; + +import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; + +import com.android.internal.util.test.FakeSettingsProvider; +import com.android.server.LocalServices; +import com.android.server.UiThread; +import com.android.server.policy.WindowManagerPolicy; +import com.android.server.statusbar.StatusBarManagerInternal; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Test class for {@link DisplayRotation}. + * + * Build/Install/Run: + * atest WmTests:DisplayRotationTests + */ +@SmallTest +@Presubmit +@FlakyTest(detail = "Confirm stable in post-submit before removing") +public class DisplayRotationTests { + private static final long UI_HANDLER_WAIT_TIMEOUT_MS = 50; + + private StatusBarManagerInternal mPreviousStatusBarManagerInternal; + + private WindowManagerService mMockWm; + private DisplayContent mMockDisplayContent; + private DisplayPolicy mMockDisplayPolicy; + private Context mMockContext; + private Resources mMockRes; + private SensorManager mMockSensorManager; + private Sensor mFakeSensor; + private DisplayWindowSettings mMockDisplayWindowSettings; + private ContentResolver mMockResolver; + private FakeSettingsProvider mFakeSettingsProvider; + private StatusBarManagerInternal mMockStatusBarManagerInternal; + + // Fields below are callbacks captured from test target. + private ContentObserver mShowRotationSuggestionsObserver; + private ContentObserver mAccelerometerRotationObserver; + private ContentObserver mUserRotationObserver; + private SensorEventListener mOrientationSensorListener; + + private DisplayRotationBuilder mBuilder; + + private DisplayRotation mTarget; + + @Before + public void setUp() { + FakeSettingsProvider.clearSettingsProvider(); + + mMockWm = mock(WindowManagerService.class); + mMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class); + + mPreviousStatusBarManagerInternal = LocalServices.getService( + StatusBarManagerInternal.class); + LocalServices.removeServiceForTest(StatusBarManagerInternal.class); + mMockStatusBarManagerInternal = mock(StatusBarManagerInternal.class); + LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal); + + mBuilder = new DisplayRotationBuilder(); + } + + @After + public void tearDown() { + LocalServices.removeServiceForTest(StatusBarManagerInternal.class); + if (mPreviousStatusBarManagerInternal != null) { + LocalServices.addService(StatusBarManagerInternal.class, + mPreviousStatusBarManagerInternal); + mPreviousStatusBarManagerInternal = null; + } + } + + // ================================ + // Display Settings Related Tests + // ================================ + @Test + public void testLocksUserRotation_LockRotation_DefaultDisplay() throws Exception { + mBuilder.build(); + + freezeRotation(Surface.ROTATION_180); + + assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, mTarget.getUserRotationMode()); + assertEquals(Surface.ROTATION_180, mTarget.getUserRotation()); + + assertEquals(0, Settings.System.getInt(mMockResolver, + Settings.System.ACCELEROMETER_ROTATION)); + assertEquals(Surface.ROTATION_180, Settings.System.getInt(mMockResolver, + Settings.System.USER_ROTATION)); + } + + @Test + public void testPersistsUserRotation_LockRotation_NonDefaultDisplay() throws Exception { + mBuilder.mIsDefaultDisplay = false; + + mBuilder.build(); + + freezeRotation(Surface.ROTATION_180); + + assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, mTarget.getUserRotationMode()); + assertEquals(Surface.ROTATION_180, mTarget.getUserRotation()); + + verify(mMockDisplayWindowSettings).setUserRotation(mMockDisplayContent, + WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_180); + } + + @Test + public void testPersistUserRotation_UnlockRotation_DefaultDisplay() throws Exception { + mBuilder.build(); + + thawRotation(); + + assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, mTarget.getUserRotationMode()); + + assertEquals(1, Settings.System.getInt(mMockResolver, + Settings.System.ACCELEROMETER_ROTATION)); + } + + @Test + public void testPersistsUserRotation_UnlockRotation_NonDefaultDisplay() throws Exception { + mBuilder.mIsDefaultDisplay = false; + + mBuilder.build(); + + thawRotation(); + + assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, mTarget.getUserRotationMode()); + + verify(mMockDisplayWindowSettings).setUserRotation(same(mMockDisplayContent), + eq(WindowManagerPolicy.USER_ROTATION_FREE), anyInt()); + } + + @Test + public void testPersistsFixedToUserRotation() throws Exception { + mBuilder.build(); + + mTarget.setFixedToUserRotation(true); + + verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent, true); + + reset(mMockDisplayWindowSettings); + mTarget.setFixedToUserRotation(false); + + verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent, false); + } + + // ======================================== + // Tests for User Rotation based Rotation + // ======================================== + @Test + public void testReturnsUserRotation_UserRotationLocked_NoAppRequest() + throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + + freezeRotation(Surface.ROTATION_180); + + assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation( + ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_90)); + } + + @Test + public void testReturnsUserRotation_UserRotationLocked_CompatibleAppRequest() + throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + + freezeRotation(Surface.ROTATION_180); + + assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation( + ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, Surface.ROTATION_90)); + } + + @Test + public void testReturnsSidesays_UserRotationLocked_IncompatibleAppRequest() + throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + + freezeRotation(Surface.ROTATION_180); + + final int rotation = mTarget.rotationForOrientation( + ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, Surface.ROTATION_90); + assertTrue("Rotation should be sideways, but it's " + + Surface.rotationToString(rotation), + rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270); + } + + // ================================= + // Tests for Sensor based Rotation + // ================================= + private void verifyOrientationListenerRegistration(int numOfInvocation) { + final ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass( + SensorEventListener.class); + verify(mMockSensorManager, times(numOfInvocation)).registerListener( + listenerCaptor.capture(), + same(mFakeSensor), + anyInt(), + any()); + if (numOfInvocation > 0) { + mOrientationSensorListener = listenerCaptor.getValue(); + } + } + + @Test + public void testNotEnablesSensor_AutoRotationNotSupported() throws Exception { + mBuilder.setSupportAutoRotation(false).build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + thawRotation(); + + when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); + when(mMockDisplayPolicy.isAwake()).thenReturn(true); + when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); + when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); + mTarget.updateOrientationListener(); + verifyOrientationListenerRegistration(0); + } + + @Test + public void testNotEnablesSensor_ScreenNotOn() throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + thawRotation(); + + when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(false); + when(mMockDisplayPolicy.isAwake()).thenReturn(true); + when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); + when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); + mTarget.updateOrientationListener(); + verifyOrientationListenerRegistration(0); + } + + @Test + public void testNotEnablesSensor_NotAwake() throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + thawRotation(); + + when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); + when(mMockDisplayPolicy.isAwake()).thenReturn(false); + when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); + when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); + mTarget.updateOrientationListener(); + verifyOrientationListenerRegistration(0); + } + + @Test + public void testNotEnablesSensor_KeyguardNotDrawnCompletely() throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + thawRotation(); + + when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); + when(mMockDisplayPolicy.isAwake()).thenReturn(true); + when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(false); + when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); + mTarget.updateOrientationListener(); + verifyOrientationListenerRegistration(0); + } + + @Test + public void testNotEnablesSensor_WindowManagerNotDrawnCompletely() throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + thawRotation(); + + when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); + when(mMockDisplayPolicy.isAwake()).thenReturn(true); + when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); + when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(false); + mTarget.updateOrientationListener(); + verifyOrientationListenerRegistration(0); + } + + @Test + public void testNotEnablesSensor_FixedUserRotation() throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); + when(mMockDisplayPolicy.isAwake()).thenReturn(true); + when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); + when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); + mTarget.setFixedToUserRotation(true); + mTarget.updateOrientationListener(); + verifyOrientationListenerRegistration(0); + } + + @Test + public void testNotEnablesSensor_ForceDefaultRotation() throws Exception { + mBuilder.build(); + when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation)) + .thenReturn(true); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + + when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); + when(mMockDisplayPolicy.isAwake()).thenReturn(true); + when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); + when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); + mTarget.updateOrientationListener(); + verifyOrientationListenerRegistration(0); + } + + @Test + public void testNotEnablesSensor_ForceDefaultRotation_Car() throws Exception { + mBuilder.build(); + when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation)) + .thenReturn(true); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, true, false); + + when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); + when(mMockDisplayPolicy.isAwake()).thenReturn(true); + when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); + when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); + mTarget.updateOrientationListener(); + verifyOrientationListenerRegistration(0); + } + + @Test + public void testNotEnablesSensor_ForceDefaultRotation_Tv() throws Exception { + mBuilder.build(); + when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation)) + .thenReturn(true); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, true); + + when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); + when(mMockDisplayPolicy.isAwake()).thenReturn(true); + when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); + when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); + mTarget.updateOrientationListener(); + verifyOrientationListenerRegistration(0); + } + + private void enableOrientationSensor() { + when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); + when(mMockDisplayPolicy.isAwake()).thenReturn(true); + when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); + when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); + mTarget.updateOrientationListener(); + verifyOrientationListenerRegistration(1); + } + + private SensorEvent createSensorEvent(int rotation) throws Exception { + final Constructor<SensorEvent> constructor = + SensorEvent.class.getDeclaredConstructor(int.class); + constructor.setAccessible(true); + final SensorEvent event = constructor.newInstance(1); + event.sensor = mFakeSensor; + event.values[0] = rotation; + event.timestamp = SystemClock.elapsedRealtimeNanos(); + return event; + } + + @Test + public void testReturnsSensorRotation_RotationThawed() throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + thawRotation(); + + enableOrientationSensor(); + + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); + + assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); + } + + private boolean waitForUiHandler() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + UiThread.getHandler().post(latch::countDown); + return latch.await(UI_HANDLER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + + @Test + public void testUpdatesRotationWhenSensorUpdates_RotationThawed() throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + thawRotation(); + + enableOrientationSensor(); + + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); + assertTrue(waitForUiHandler()); + + verify(mMockWm).updateRotation(false, false); + } + + @Test + public void testNotifiesChoiceWhenSensorUpdates_RotationLocked() throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + freezeRotation(Surface.ROTATION_270); + + enableOrientationSensor(); + + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); + assertTrue(waitForUiHandler()); + + verify(mMockStatusBarManagerInternal).onProposedRotationChanged(Surface.ROTATION_90, true); + } + + @Test + public void testReturnsCompatibleRotation_SensorEnabled_RotationThawed() throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + thawRotation(); + + enableOrientationSensor(); + + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180)); + + final int rotation = mTarget.rotationForOrientation(SCREEN_ORIENTATION_LANDSCAPE, + Surface.ROTATION_0); + assertTrue("Rotation should be sideways but it's " + + Surface.rotationToString(rotation), + rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270); + } + + @Test + public void testReturnsUserRotation_SensorEnabled_RotationLocked() throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + freezeRotation(Surface.ROTATION_270); + + enableOrientationSensor(); + + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180)); + + assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); + } + + // ================================= + // Tests for Policy based Rotation + // ================================= + @Test + public void testReturnsUserRotation_ForceDefaultRotation() throws Exception { + mBuilder.build(); + when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation)) + .thenReturn(true); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + + assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT, + Surface.ROTATION_180)); + } + + @Test + public void testReturnsUserRotation_ForceDefaultRotation_Car() throws Exception { + mBuilder.build(); + when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation)) + .thenReturn(true); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, true, false); + + assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT, + Surface.ROTATION_180)); + } + + @Test + public void testReturnsUserRotation_ForceDefaultRotation_Tv() throws Exception { + mBuilder.build(); + when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation)) + .thenReturn(true); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, true); + + assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT, + Surface.ROTATION_180)); + } + + @Test + public void testReturnsLidOpenRotation_LidOpen() throws Exception { + mBuilder.setLidOpenRotation(Surface.ROTATION_90).build(); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + + when(mMockDisplayPolicy.getLidState()).thenReturn( + WindowManagerPolicy.WindowManagerFuncs.LID_OPEN); + + freezeRotation(Surface.ROTATION_270); + + assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); + } + + @Test + public void testReturnsCarDockRotation_CarDockedMode() throws Exception { + mBuilder.setCarDockRotation(Surface.ROTATION_270).build(); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + + when(mMockDisplayPolicy.getDockMode()).thenReturn(Intent.EXTRA_DOCK_STATE_CAR); + + freezeRotation(Surface.ROTATION_90); + + assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_90)); + } + + @Test + public void testReturnsDeskDockRotation_DeskDockedMode() throws Exception { + mBuilder.setDeskDockRotation(Surface.ROTATION_270).build(); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + + when(mMockDisplayPolicy.getDockMode()).thenReturn(Intent.EXTRA_DOCK_STATE_DESK); + + freezeRotation(Surface.ROTATION_90); + + assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_90)); + } + + @Test + public void testReturnsUserRotation_FixedToUserRotation_IgnoreIncompatibleAppRequest() + throws Exception { + mBuilder.build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + + mTarget.setFixedToUserRotation(true); + + freezeRotation(Surface.ROTATION_180); + + final int rotation = mTarget.rotationForOrientation( + ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, Surface.ROTATION_90); + assertEquals(Surface.ROTATION_180, rotation); + } + + @Test + public void testReturnsUserRotation_NonDefaultDisplay() throws Exception { + mBuilder.setIsDefaultDisplay(false).build(); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + + freezeRotation(Surface.ROTATION_90); + + assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); + } + + /** + * Call {@link DisplayRotation#configure(int, int, int, int)} to configure {@link #mTarget} + * according to given parameters. + */ + private void configureDisplayRotation(int displayOrientation, boolean isCar, boolean isTv) { + final int width; + final int height; + switch (displayOrientation) { + case SCREEN_ORIENTATION_LANDSCAPE: + width = 1920; + height = 1080; + break; + case SCREEN_ORIENTATION_PORTRAIT: + width = 1080; + height = 1920; + break; + default: + throw new IllegalArgumentException("displayOrientation needs to be either landscape" + + " or portrait, but we got " + + ActivityInfo.screenOrientationToString(displayOrientation)); + } + + final PackageManager mockPackageManager = mock(PackageManager.class); + when(mMockContext.getPackageManager()).thenReturn(mockPackageManager); + when(mockPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) + .thenReturn(isCar); + when(mockPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) + .thenReturn(isTv); + + final int shortSizeDp = (isCar || isTv) ? 540 : 720; + final int longSizeDp = 960; + mTarget.configure(width, height, shortSizeDp, longSizeDp); + } + + private void freezeRotation(int rotation) { + mTarget.freezeRotation(rotation); + + if (mTarget.isDefaultDisplay) { + mAccelerometerRotationObserver.onChange(false); + mUserRotationObserver.onChange(false); + } + } + + private void thawRotation() { + mTarget.thawRotation(); + + if (mTarget.isDefaultDisplay) { + mAccelerometerRotationObserver.onChange(false); + mUserRotationObserver.onChange(false); + } + } + + private class DisplayRotationBuilder { + private boolean mIsDefaultDisplay = true; + private boolean mSupportAutoRotation = true; + + private int mLidOpenRotation = WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; + private int mCarDockRotation; + private int mDeskDockRotation; + private int mUndockedHdmiRotation; + + private DisplayRotationBuilder setIsDefaultDisplay(boolean isDefaultDisplay) { + mIsDefaultDisplay = isDefaultDisplay; + return this; + } + + private DisplayRotationBuilder setSupportAutoRotation(boolean supportAutoRotation) { + mSupportAutoRotation = supportAutoRotation; + return this; + } + + private DisplayRotationBuilder setLidOpenRotation(int rotation) { + mLidOpenRotation = rotation; + return this; + } + + private DisplayRotationBuilder setCarDockRotation(int rotation) { + mCarDockRotation = rotation; + return this; + } + + private DisplayRotationBuilder setDeskDockRotation(int rotation) { + mDeskDockRotation = rotation; + return this; + } + + private DisplayRotationBuilder setUndockedHdmiRotation(int rotation) { + mUndockedHdmiRotation = rotation; + return this; + } + + private void captureObservers() { + ArgumentCaptor<ContentObserver> captor = ArgumentCaptor.forClass( + ContentObserver.class); + verify(mMockResolver, atMost(1)).registerContentObserver( + eq(Settings.Secure.getUriFor(Settings.Secure.SHOW_ROTATION_SUGGESTIONS)), + anyBoolean(), + captor.capture(), + anyInt()); + if (!captor.getAllValues().isEmpty()) { + mShowRotationSuggestionsObserver = captor.getValue(); + } + + captor = ArgumentCaptor.forClass(ContentObserver.class); + verify(mMockResolver, atMost(1)).registerContentObserver( + eq(Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION)), + anyBoolean(), + captor.capture(), + anyInt()); + if (!captor.getAllValues().isEmpty()) { + mAccelerometerRotationObserver = captor.getValue(); + } + + captor = ArgumentCaptor.forClass(ContentObserver.class); + verify(mMockResolver, atMost(1)).registerContentObserver( + eq(Settings.System.getUriFor(Settings.System.USER_ROTATION)), + anyBoolean(), + captor.capture(), + anyInt()); + if (!captor.getAllValues().isEmpty()) { + mUserRotationObserver = captor.getValue(); + } + } + + private Sensor createSensor(int type) throws Exception { + Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor(); + constr.setAccessible(true); + Sensor sensor = constr.newInstance(); + + setSensorType(sensor, type); + setSensorField(sensor, "mName", "Mock " + sensor.getStringType() + "/" + type); + setSensorField(sensor, "mVendor", "Mock Vendor"); + setSensorField(sensor, "mVersion", 1); + setSensorField(sensor, "mHandle", -1); + setSensorField(sensor, "mMaxRange", 10); + setSensorField(sensor, "mResolution", 1); + setSensorField(sensor, "mPower", 1); + setSensorField(sensor, "mMinDelay", 1000); + setSensorField(sensor, "mMaxDelay", 1000000000); + setSensorField(sensor, "mFlags", 0); + setSensorField(sensor, "mId", -1); + + return sensor; + } + + private void setSensorType(Sensor sensor, int type) throws Exception { + Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE); + setter.setAccessible(true); + setter.invoke(sensor, type); + } + + private void setSensorField(Sensor sensor, String fieldName, Object value) + throws Exception { + Field field = Sensor.class.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(sensor, value); + } + + private int convertRotationToDegrees(@Surface.Rotation int rotation) { + switch (rotation) { + case Surface.ROTATION_0: + return 0; + case Surface.ROTATION_90: + return 90; + case Surface.ROTATION_180: + return 180; + case Surface.ROTATION_270: + return 270; + default: + return -1; + } + } + + private void build() throws Exception { + mMockContext = mock(Context.class); + + mMockDisplayContent = mock(WindowTestUtils.TestDisplayContent.class); + mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay; + + mMockDisplayPolicy = mock(DisplayPolicy.class); + + mMockRes = mock(Resources.class); + when(mMockContext.getResources()).thenReturn((mMockRes)); + when(mMockRes.getBoolean(com.android.internal.R.bool.config_supportAutoRotation)) + .thenReturn(mSupportAutoRotation); + when(mMockRes.getInteger(com.android.internal.R.integer.config_lidOpenRotation)) + .thenReturn(convertRotationToDegrees(mLidOpenRotation)); + when(mMockRes.getInteger(com.android.internal.R.integer.config_carDockRotation)) + .thenReturn(convertRotationToDegrees(mCarDockRotation)); + when(mMockRes.getInteger(com.android.internal.R.integer.config_deskDockRotation)) + .thenReturn(convertRotationToDegrees(mDeskDockRotation)); + when(mMockRes.getInteger(com.android.internal.R.integer.config_undockedHdmiRotation)) + .thenReturn(convertRotationToDegrees(mUndockedHdmiRotation)); + + mMockSensorManager = mock(SensorManager.class); + when(mMockContext.getSystemService(Context.SENSOR_SERVICE)) + .thenReturn(mMockSensorManager); + mFakeSensor = createSensor(Sensor.TYPE_DEVICE_ORIENTATION); + when(mMockSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION)).thenReturn( + Collections.singletonList(mFakeSensor)); + + mMockResolver = mock(ContentResolver.class); + when(mMockContext.getContentResolver()).thenReturn(mMockResolver); + mFakeSettingsProvider = new FakeSettingsProvider(); + when(mMockResolver.acquireProvider(Settings.AUTHORITY)) + .thenReturn(mFakeSettingsProvider.getIContentProvider()); + + mMockDisplayWindowSettings = mock(DisplayWindowSettings.class); + mTarget = new DisplayRotation(mMockWm, mMockDisplayContent, mMockDisplayPolicy, + mMockDisplayWindowSettings, mMockContext, new Object()); + + captureObservers(); + } + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index 2c3c66be6248..f3a125bf79e4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -272,6 +272,51 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { } @Test + public void testClearsRecordInMemory() { + mTarget.saveTask(mTestTask); + + mTarget.removeRecordForPackage(TEST_COMPONENT.getPackageName()); + + mTarget.getLaunchParams(mTestTask, null, mResult); + + assertTrue("Result should be empty.", mResult.isEmpty()); + } + + @Test + public void testClearsWriteQueueItem() { + mTarget.saveTask(mTestTask); + + mTarget.removeRecordForPackage(TEST_COMPONENT.getPackageName()); + + final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor, + mUserFolderGetter); + target.onSystemReady(); + target.onUnlockUser(TEST_USER_ID); + + target.getLaunchParams(mTestTask, null, mResult); + + assertTrue("Result should be empty.", mResult.isEmpty()); + } + + @Test + public void testClearsFile() { + mTarget.saveTask(mTestTask); + mPersisterQueue.flush(); + + mTarget.removeRecordForPackage(TEST_COMPONENT.getPackageName()); + + final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor, + mUserFolderGetter); + target.onSystemReady(); + target.onUnlockUser(TEST_USER_ID); + + target.getLaunchParams(mTestTask, null, mResult); + + assertTrue("Result should be empty.", mResult.isEmpty()); + } + + + @Test public void testClearsRecordInMemoryOnPackageUninstalled() { mTarget.saveTask(mTestTask); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index e56edabfa02f..3c877213a0e4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -65,7 +65,7 @@ public class WindowTestUtils { final DisplayRotation displayRotation = new DisplayRotation( mock(WindowManagerService.class), displayContent, displayPolicy, - context, new Object()); + mock(DisplayWindowSettings.class), context, new Object()); displayRotation.mPortraitRotation = Surface.ROTATION_0; displayRotation.mLandscapeRotation = Surface.ROTATION_90; displayRotation.mUpsideDownRotation = Surface.ROTATION_180; diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 34a8c9659595..45cfe1e303ec 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -569,14 +569,6 @@ public class SubscriptionManager { public static final String IS_OPPORTUNISTIC = "is_opportunistic"; /** - * TelephonyProvider column name for subId of parent subscription of an opportunistic - * subscription. - * if the parent sub id is valid, then is_opportunistic should always to true. - * @hide - */ - public static final String PARENT_SUB_ID = "parent_sub_id"; - - /** * TelephonyProvider column name for group ID. Subscriptions with same group ID * are considered bundled together, and should behave as a single subscription at * certain scenarios. diff --git a/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java b/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java index 8d8fc84126ec..b9e282ebdfef 100644 --- a/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java +++ b/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java @@ -38,7 +38,7 @@ public class WallpaperServiceTest { public Engine onCreateEngine() { return new Engine() { @Override - public void onAmbientModeChanged(boolean inAmbientMode, boolean animated) { + public void onAmbientModeChanged(boolean inAmbientMode, long duration) { ambientModeChangedCount[0]++; } }; @@ -47,12 +47,12 @@ public class WallpaperServiceTest { WallpaperService.Engine engine = service.onCreateEngine(); engine.setCreated(true); - engine.doAmbientModeChanged(false, false); + engine.doAmbientModeChanged(false, 0); assertFalse("ambient mode should be false", engine.isInAmbientMode()); assertEquals("onAmbientModeChanged should have been called", ambientModeChangedCount[0], 1); - engine.doAmbientModeChanged(true, false); + engine.doAmbientModeChanged(true, 0); assertTrue("ambient mode should be false", engine.isInAmbientMode()); assertEquals("onAmbientModeChanged should have been called", ambientModeChangedCount[0], 2); diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java index ae3914ebf162..d5987a5373b4 100644 --- a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java +++ b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java @@ -26,6 +26,7 @@ import android.util.MergedConfiguration; import android.view.Display; import android.view.DisplayCutout; import android.view.IWindowSession; +import android.view.InsetsState; import android.view.Surface; import android.view.View; import android.view.WindowManager; @@ -105,7 +106,7 @@ public class MainActivity extends Activity { window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, -1, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, new DisplayCutout.ParcelableWrapper(), new MergedConfiguration(), - new Surface()); + new Surface(), new InsetsState()); } catch (RemoteException e) { e.printStackTrace(); } @@ -131,8 +132,9 @@ public class MainActivity extends Activity { final IWindowSession session = WindowManagerGlobal.getWindowSession(); final Rect tmpRect = new Rect(); try { - final int res = session.addToDisplayWithoutInputChannel(window, window.mSeq, layoutParams, - View.VISIBLE, Display.DEFAULT_DISPLAY, tmpRect, tmpRect); + final int res = session.addToDisplayWithoutInputChannel(window, window.mSeq, + layoutParams, View.VISIBLE, Display.DEFAULT_DISPLAY, tmpRect, tmpRect, + new InsetsState()); } catch (RemoteException e) { e.printStackTrace(); } diff --git a/tools/hiddenapi/exclude.sh b/tools/hiddenapi/exclude.sh new file mode 100755 index 000000000000..2291e5a92730 --- /dev/null +++ b/tools/hiddenapi/exclude.sh @@ -0,0 +1,57 @@ +#!/bin/bash +set -e +# Make sure that entries are not added for packages that are already fully handled using +# annotations. +LOCAL_DIR="$( dirname ${BASH_SOURCE} )" +# Each team should add a <team>_PACKAGES and <team>_EMAIL with the list of packages and +# the team email to use in the event of this detecting an entry in a <team> package. Also +# add <team> to the TEAMS list. +LIBCORE_PACKAGES="\ + android.icu \ + android.system \ + com.android.bouncycastle \ + com.android.conscrypt \ + com.android.okhttp \ + com.sun \ + dalvik \ + java \ + javax \ + libcore \ + org.apache.harmony \ + org.json \ + org.w3c.dom \ + org.xml.sax \ + sun \ + " +LIBCORE_EMAIL=libcore-team@android.com + +# List of teams. +TEAMS=LIBCORE + +# Generate the list of packages and convert to a regular expression. +PACKAGES=$(for t in $TEAMS; do echo $(eval echo \${${t}_PACKAGES}); done) +RE=$(echo ${PACKAGES} | sed "s/ /|/g") +git show --name-only --pretty=format: $1 | grep "config/hiddenapi-.*txt" | while read file; do + ENTRIES=$(grep -E "^L(${RE})/" <(git show $1:$file)) + if [[ -n "${ENTRIES}" ]]; then + echo -e "\e[1m\e[31m$file $1 contains the following entries\e[0m" + echo -e "\e[1m\e[31mfor packages that are handled using UnsupportedAppUsage. Please remove\e[0m" + echo -e "\e[1m\e[31mthese entries and add annotations instead.\e[0m" + # Partition the entries by team and provide contact details to aid in fixing the issue. + for t in ${TEAMS} + do + PACKAGES=$(eval echo \${${t}_PACKAGES}) + RE=$(echo ${PACKAGES} | sed "s/ /|/g") + TEAM_ENTRIES=$(grep -E "^L(${RE})/" <(echo "${ENTRIES}")) + if [[ -n "${TEAM_ENTRIES}" ]]; then + EMAIL=$(eval echo \${${t}_EMAIL}) + echo -e "\e[33mContact ${EMAIL} or compat- for help with the following:\e[0m" + for i in ${ENTRIES} + do + echo -e "\e[33m ${i}\e[0m" + done + fi + done + exit 1 + fi +done diff --git a/tools/powermodel/Android.bp b/tools/powermodel/Android.bp new file mode 100644 index 000000000000..f597aab0f464 --- /dev/null +++ b/tools/powermodel/Android.bp @@ -0,0 +1,26 @@ + +java_library_host { + name: "powermodel", + srcs: [ + "src/**/*.java", + ], + static_libs: [ + "guava", + ], +} + +java_test_host { + name: "powermodel-test", + + test_suites: ["general-tests"], + + srcs: ["test/**/*.java"], + java_resource_dirs: ["test-resource"], + + static_libs: [ + "powermodel", + "junit", + "mockito", + ], +} + diff --git a/tools/powermodel/TEST_MAPPING b/tools/powermodel/TEST_MAPPING new file mode 100644 index 000000000000..c8db339ce23b --- /dev/null +++ b/tools/powermodel/TEST_MAPPING @@ -0,0 +1,8 @@ +{ + "presubmit": [ + { + "name": "powermodel-test" + } + ] +} + diff --git a/tools/powermodel/src/com/android/powermodel/ActivityReport.java b/tools/powermodel/src/com/android/powermodel/ActivityReport.java new file mode 100644 index 000000000000..4a8f63370cda --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/ActivityReport.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ImmutableList; + +/** + * ActivityReport contains the summary of the activity that consumes power + * as reported by batterystats or statsd. + */ +public class ActivityReport { + private AppList<AppActivity> mApps; + + public ImmutableList<AppActivity> getAllApps() { + return mApps.getAllApps(); + } + + public ImmutableList<AppActivity> getRegularApps() { + return mApps.getRegularApps(); + } + + public List<AppActivity> findApp(String pkg) { + return mApps.findApp(pkg); + } + + public AppActivity findApp(SpecialApp specialApp) { + return mApps.findApp(specialApp); + } + + /** + * Find a component in the GLOBAL app. + * <p> + * Returns null if either the global app doesn't exist (bad data?) or the component + * doesn't exist in the global app. + */ + public ComponentActivity findGlobalComponent(Component component) { + final AppActivity global = mApps.findApp(SpecialApp.GLOBAL); + if (global == null) { + return null; + } + return global.getComponentActivity(component); + } + + public static class Builder { + private AppList.Builder<AppActivity,AppActivity.Builder> mApps = new AppList.Builder(); + + public Builder() { + } + + public ActivityReport build() { + final ActivityReport result = new ActivityReport(); + result.mApps = mApps.build(); + return result; + } + + public void addActivity(Component component, Collection<ComponentActivity> activities) { + for (final ComponentActivity activity: activities) { + addActivity(component, activity); + } + } + + public void addActivity(Component component, ComponentActivity activity) { + AppActivity.Builder app = mApps.get(activity.attribution); + if (app == null) { + app = new AppActivity.Builder(); + app.setAttribution(activity.attribution); + mApps.put(activity.attribution, app); + } + app.addComponentActivity(component, activity); + } + } +} diff --git a/tools/powermodel/src/com/android/powermodel/AppActivity.java b/tools/powermodel/src/com/android/powermodel/AppActivity.java new file mode 100644 index 000000000000..b87426ce0dc3 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/AppActivity.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.util.HashMap; + +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public class AppActivity extends AppInfo { + + private ImmutableMap<Component, ComponentActivity> mComponents; + // TODO: power rails + // private ImmutableMap<Component, PowerRailActivity> mRails; + + private AppActivity() { + } + + /** + * Returns the {@link ComponentActivity} for the {@link Component} provided, + * or null if this AppActivity does not have that component. + * @more + * If there is no ComponentActivity for a particular Component, then + * there was no usage associated with that app for the app in question. + */ + public ComponentActivity getComponentActivity(Component component) { + return mComponents.get(component); + } + + public ImmutableSet<Component> getComponents() { + return mComponents.keySet(); + } + + public ImmutableMap<Component,ComponentActivity> getComponentActivities() { + return mComponents; + } + + // TODO: power rails + // public ComponentActivity getPowerRail(Component component) { + // return mComponents.get(component); + // } + // + // public Set<Component> getPowerRails() { + // return mComponents.keySet(); + // } + + public static class Builder extends AppInfo.Builder<AppActivity> { + private HashMap<Component, ComponentActivity> mComponents = new HashMap(); + // TODO power rails. + + public Builder() { + } + + public AppActivity build() { + final AppActivity result = new AppActivity(); + init(result); + result.mComponents = ImmutableMap.copyOf(mComponents); + return result; + } + + public void addComponentActivity(Component component, ComponentActivity activity) { + mComponents.put(component, activity); + } + } +} diff --git a/tools/powermodel/src/com/android/powermodel/AppInfo.java b/tools/powermodel/src/com/android/powermodel/AppInfo.java new file mode 100644 index 000000000000..208339e8e491 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/AppInfo.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 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.powermodel; + +class AppInfo { + private AttributionKey mAttribution; + + protected AppInfo() { + } + + public boolean hasPackage(String pkg) { + return mAttribution.hasPackage(pkg); + } + + public AttributionKey getAttribution() { + return mAttribution; + } + + abstract static class Builder<APP extends AppInfo> { + private AttributionKey mAttribution; + + public Builder() { + } + + public abstract APP build(); + + protected void init(AppInfo app) { + if (mAttribution == null) { + throw new RuntimeException("setAttribution(AttributionKey attribution) not called"); + } + app.mAttribution = mAttribution; + } + + public void setAttribution(AttributionKey attribution) { + mAttribution = attribution; + } + + public AttributionKey getAttribution() { + return mAttribution; + } + } +} diff --git a/tools/powermodel/src/com/android/powermodel/AppList.java b/tools/powermodel/src/com/android/powermodel/AppList.java new file mode 100644 index 000000000000..19572fc1cf15 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/AppList.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +class AppList<APP extends AppInfo> { + private ImmutableList<APP> mAllApps; + private ImmutableList<APP> mRegularApps; + private ImmutableMap<SpecialApp,APP> mSpecialApps; + + private AppList() { + } + + public ImmutableList<APP> getAllApps() { + return mAllApps; + } + + public ImmutableList<APP> getRegularApps() { + return mRegularApps; + } + + public List<APP> findApp(String pkg) { + List<APP> result = new ArrayList(); + for (APP app: mRegularApps) { + if (app.hasPackage(pkg)) { + result.add(app); + } + } + return result; + } + + public APP findApp(SpecialApp specialApp) { + return mSpecialApps.get(specialApp); + } + + public static class Builder<APP extends AppInfo, BUILDER extends AppInfo.Builder<APP>> { + private final HashMap<AttributionKey,BUILDER> mApps = new HashMap(); + + public Builder() { + } + + public AppList<APP> build() { + final AppList<APP> result = new AppList(); + final ArrayList<APP> allApps = new ArrayList(); + final ArrayList<APP> regularApps = new ArrayList(); + final HashMap<SpecialApp,APP> specialApps = new HashMap(); + for (AppInfo.Builder<APP> app: mApps.values()) { + final AttributionKey attribution = app.getAttribution(); + final APP appActivity = app.build(); + allApps.add(appActivity); + if (attribution.isSpecialApp()) { + specialApps.put(attribution.getSpecialApp(), appActivity); + } else { + regularApps.add(appActivity); + } + } + result.mAllApps = ImmutableList.copyOf(allApps); + result.mRegularApps = ImmutableList.copyOf(regularApps); + result.mSpecialApps = ImmutableMap.copyOf(specialApps); + return result; + } + + public BUILDER get(AttributionKey attribution) { + return mApps.get(attribution); + } + + public BUILDER put(AttributionKey attribution, BUILDER app) { + return mApps.put(attribution, app); + } + } +} diff --git a/tools/powermodel/src/com/android/powermodel/AppPower.java b/tools/powermodel/src/com/android/powermodel/AppPower.java new file mode 100644 index 000000000000..283982b8eda6 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/AppPower.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.util.HashMap; +import java.util.Set; + +import com.google.common.collect.ImmutableMap; + +public class AppPower extends AppInfo { + private ImmutableMap<Component, ComponentPower> mComponents; + + private double mAppPowerMah; + + + private AppPower() { + } + + /** + * Returns the {@link ComponentPower} for the {@link Component} provided, + * or null if this AppPower does not have that component. + * @more + * If the component was in the power profile for this device, there + * will be a component for it, even if there was no power used + * by that component. In that case, the + * {@link ComponentPower.getUsage() ComponentPower.getUsage()} + * method will return 0. + */ + public ComponentPower getComponentPower(Component component) { + return mComponents.get(component); + } + + public Set<Component> getComponents() { + return mComponents.keySet(); + } + + /** + * Return the total power used by this app. + */ + public double getAppPowerMah() { + return mAppPowerMah; + } + + /** + * Builder class for {@link AppPower} + */ + public static class Builder extends AppInfo.Builder<AppPower> { + private HashMap<Component, ComponentPower> mComponents = new HashMap(); + + public Builder() { + } + + public AppPower build() { + final AppPower result = new AppPower(); + init(result); + result.mComponents = ImmutableMap.copyOf(mComponents); + + // Add up the components + double appPowerMah = 0; + for (final ComponentPower componentPower: mComponents.values()) { + appPowerMah += componentPower.powerMah; + } + result.mAppPowerMah = appPowerMah; + + return result; + } + + public void addComponentPower(Component component, ComponentPower componentPower) { + mComponents.put(component, componentPower); + } + } +} diff --git a/tools/powermodel/src/com/android/powermodel/AttributionKey.java b/tools/powermodel/src/com/android/powermodel/AttributionKey.java new file mode 100644 index 000000000000..f19e0b7373c7 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/AttributionKey.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.util.Set; +import java.util.HashSet; + +import com.google.common.collect.ImmutableSet; + +public class AttributionKey { + private final int mUid; + private final ImmutableSet<String> mPackages; + private final SpecialApp mSpecialApp; + + public AttributionKey(SpecialApp specialApp) { + mUid = -1; + mPackages = ImmutableSet.of(); + mSpecialApp = specialApp; + } + + public AttributionKey(int uid, Set<String> packages) { + mUid = uid; + mPackages = ImmutableSet.copyOf(packages); + mSpecialApp = null; + } + + public ImmutableSet<String> getPackages() { + return mPackages; + } + + public boolean hasPackage(String pkg) { + return mPackages.contains(pkg); + } + + public SpecialApp getSpecialApp() { + return mSpecialApp; + } + + public boolean isSpecialApp() { + return mSpecialApp != null; + } + + /** + * Returns the uid for this attribution, or -1 if there isn't one + * (e.g. if it is a special app). + */ + public int getUid() { + return mUid; + } + @Override + public int hashCode() { + int hash = 7; + hash = (31 * hash) + (mUid); + hash = (31 * hash) + (mPackages == null ? 0 : mPackages.hashCode()); + hash = (31 * hash) + (mSpecialApp == null ? 0 : mSpecialApp.hashCode()); + return hash; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null) { + return false; + } + if (this.getClass() != o.getClass()) { + return false; + } + final AttributionKey that = (AttributionKey)o; + return (this.mUid == that.mUid) + && this.mPackages != null && this.mPackages.equals(that.mPackages) + && this.mSpecialApp != null && this.mSpecialApp.equals(that.mSpecialApp); + } + + @Override + public String toString() { + final StringBuilder str = new StringBuilder("AttributionKey("); + if (mUid >= 0) { + str.append(" uid="); + str.append(mUid); + } + if (mPackages.size() > 0) { + str.append(" packages=["); + for (String pkg: mPackages) { + str.append(' '); + str.append(pkg); + } + str.append(" ]"); + } + if (mSpecialApp != null) { + str.append(" specialApp="); + str.append(mSpecialApp.name()); + } + str.append(" )"); + return str.toString(); + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/BatteryStatsReader.java b/tools/powermodel/src/com/android/powermodel/BatteryStatsReader.java new file mode 100644 index 000000000000..595c6612dc3b --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/BatteryStatsReader.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.io.InputStream; +import java.io.IOException; +import com.android.powermodel.component.ModemBatteryStatsReader; + +public class BatteryStatsReader { + /** + * Construct a reader. + */ + public BatteryStatsReader() { + } + + /** + * Parse a powermodel.xml file and return a PowerProfile object. + * + * @param stream An InputStream containing the batterystats output. + * + * @throws ParseException Thrown when the xml file can not be parsed. + * @throws IOException When there is a problem reading the stream. + */ + public static ActivityReport parse(InputStream stream) throws ParseException, IOException { + final Parser parser = new Parser(stream); + return parser.parse(); + } + + /** + * Implements the reading and power model logic. + */ + private static class Parser { + final InputStream mStream; + final ActivityReport mResult; + RawBatteryStats mBs; + + /** + * Constructor to capture the parameters to read. + */ + Parser(InputStream stream) { + mStream = stream; + mResult = new ActivityReport(); + } + + /** + * Read the stream, parse it, and apply the power model. + * Do not call this more than once. + */ + ActivityReport parse() throws ParseException, IOException { + mBs = RawBatteryStats.parse(mStream); + + final ActivityReport.Builder report = new ActivityReport.Builder(); + + report.addActivity(Component.MODEM, ModemBatteryStatsReader.createActivities(mBs)); + + return report.build(); + } + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/Component.java b/tools/powermodel/src/com/android/powermodel/Component.java new file mode 100644 index 000000000000..baae6d784c47 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/Component.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 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.powermodel; + +/** + * The hardware components that use power on a device. + */ +public enum Component { + CPU, + SCREEN, + MODEM, + WIFI, + BLUETOOTH, + VIDEO, + AUDIO, + FLASHLIGHT, + CAMERA, + GPS, +} + diff --git a/tools/powermodel/src/com/android/powermodel/ComponentActivity.java b/tools/powermodel/src/com/android/powermodel/ComponentActivity.java new file mode 100644 index 000000000000..c1e2662b7b5f --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/ComponentActivity.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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.powermodel; + + +/** + * Encapsulates the work done by an app (including synthetic apps) that costs power. + */ +public class ComponentActivity { + public AttributionKey attribution; + + protected ComponentActivity(AttributionKey attribution) { + this.attribution = attribution; + } + + // TODO: Can we refactor what goes into the activities so this function + // doesn't need the global state? + /** + * Apply the power profile for this component. Subclasses should implement this + * to do the per-component calculatinos. The default implementation returns null. + * If this method returns null, then there will be no power associated for this + * component, which, for example is true with some of the GLOBAL activities. + */ + public ComponentPower applyProfile(ActivityReport activityReport, PowerProfile profile) { + return null; + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/ComponentPower.java b/tools/powermodel/src/com/android/powermodel/ComponentPower.java new file mode 100644 index 000000000000..b22ff8731d6f --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/ComponentPower.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 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.powermodel; + +/** + * The hardware component that uses power on a device. + * <p> + * This base class contains the total power used by each Component in an app. + * Subclasses may add more detail, which is a drill-down, but is not to be + * <i>added</i> to {@link #powerMah}. + */ +public abstract class ComponentPower<ACTIVITY extends ComponentActivity> { + /** + * The app associated with this ComponentPower. + */ + public AttributionKey attribution; + + /** + * The app activity that resulted in the power usage for this component. + */ + public ACTIVITY activity; + + /** + * The total power used by this component in this app. + */ + public double powerMah; +} diff --git a/tools/powermodel/src/com/android/powermodel/ComponentProfile.java b/tools/powermodel/src/com/android/powermodel/ComponentProfile.java new file mode 100644 index 000000000000..e76e5fb52481 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/ComponentProfile.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2018 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.powermodel; + +public class ComponentProfile { +} diff --git a/tools/powermodel/src/com/android/powermodel/CsvParser.java b/tools/powermodel/src/com/android/powermodel/CsvParser.java new file mode 100644 index 000000000000..78cd261306fc --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/CsvParser.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.io.InputStream; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +/** + * Parses CSV. + * <p> + * Call parse() with an InputStream. + * <p> + * CsvLineProcessor.onLine() will be called for each line in the source document. + * <p> + * To simplify parsing and to protect against using too much memory for bad + * data, the maximum field length is {@link #MAX_FIELD_SIZE}. + */ +class CsvParser { + /** + * The maximum size of a single field in bytes. + */ + public static final int MAX_FIELD_SIZE = (8*1024)-1; + + /** + * Callback interface for each line of CSV as it is parsed. + */ + interface LineProcessor { + /** + * A line of CSV was parsed. + * + * @param lineNumber the line number in the file, starting at 1 + * @param fields the comma separated fields for the line + */ + void onLine(int lineNumber, ArrayList<String> fields) throws ParseException; + } + + /** + * Parse the CSV text in input, calling onto processor for each row. + */ + public static void parse(InputStream input, LineProcessor processor) + throws IOException, ParseException { + final Charset utf8 = StandardCharsets.UTF_8; + final byte[] buf = new byte[MAX_FIELD_SIZE+1]; + int lineNumber = 1; + int readPos = 0; + int prev = 0; + ArrayList<String> fields = new ArrayList<String>(); + boolean finalBuffer = false; + boolean escaping = false; + boolean sawQuote = false; + + while (!finalBuffer) { + int amt = input.read(buf, readPos, buf.length-readPos); + if (amt < 0) { + // No more data. Process whatever's left from before. + amt = readPos; + finalBuffer = true; + } else { + // Process whatever's left from before, plus the new data. + amt += readPos; + finalBuffer = false; + } + + // Process as much of this buffer as we can. + int fieldStart = 0; + int index = readPos; + int escapeIndex = escaping ? readPos : -1; + while (index < amt) { + byte c = buf[index]; + if (c == '\r' || c == '\n') { + if (escaping) { + // TODO: Quotes do not escape newlines in our CSV dialect, + // but we actually see some data where it should. + fields.add(new String(buf, fieldStart, escapeIndex-fieldStart)); + escapeIndex = -1; + escaping = false; + sawQuote = false; + } else { + fields.add(new String(buf, fieldStart, index-fieldStart)); + } + // Don't report blank lines + if (fields.size() > 1 || (fields.size() == 1 && fields.get(0).length() > 0)) { + processor.onLine(lineNumber, fields); + } + fields = new ArrayList<String>(); + if (!(c == '\n' && prev == '\r')) { + // Don't double increment for dos line endings. + lineNumber++; + } + fieldStart = index = index + 1; + } else { + if (escaping) { + // Field started with a " so quotes are escaped with " and commas + // don't matter except when following a single quote. + if (c == '"') { + if (sawQuote) { + buf[escapeIndex] = buf[index]; + escapeIndex++; + sawQuote = false; + } else { + sawQuote = true; + } + index++; + } else if (sawQuote && c == ',') { + fields.add(new String(buf, fieldStart, escapeIndex-fieldStart)); + fieldStart = index = index + 1; + escapeIndex = -1; + escaping = false; + sawQuote = false; + } else { + buf[escapeIndex] = buf[index]; + escapeIndex++; + index++; + sawQuote = false; + } + } else { + if (c == ',') { + fields.add(new String(buf, fieldStart, index-fieldStart)); + fieldStart = index + 1; + } else if (c == '"' && fieldStart == index) { + // First character is a " + escaping = true; + fieldStart = escapeIndex = index + 1; + } + index++; + } + } + prev = c; + } + + // A single field is greater than buf.length, so fail. + if (fieldStart == 0 && index == buf.length) { + throw new ParseException(lineNumber, "Line is too long: " + + new String(buf, 0, 20, utf8) + "..."); + } + + // Move whatever we didn't process to the beginning of the buffer + // and try again. + if (fieldStart != amt) { + readPos = (escaping ? escapeIndex : index) - fieldStart; + System.arraycopy(buf, fieldStart, buf, 0, readPos); + } else { + readPos = 0; + } + + // Process whatever's left over + if (finalBuffer) { + fields.add(new String(buf, 0, readPos)); + // If there is any content, return the last line. + if (fields.size() > 1 || (fields.size() == 1 && fields.get(0).length() > 0)) { + processor.onLine(lineNumber, fields); + } + } + } + } +} diff --git a/tools/powermodel/src/com/android/powermodel/ParseException.java b/tools/powermodel/src/com/android/powermodel/ParseException.java new file mode 100644 index 000000000000..e1f232bfc44f --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/ParseException.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 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.powermodel; + +public class ParseException extends Exception { + public final int line; + + public ParseException(int line, String message, Throwable th) { + super(message, th); + this.line = line; + } + + public ParseException(int line, String message) { + this(line, message, null); + } + + public ParseException(String message) { + this(0, message, null); + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/PowerProfile.java b/tools/powermodel/src/com/android/powermodel/PowerProfile.java new file mode 100644 index 000000000000..373a9c981ec5 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/PowerProfile.java @@ -0,0 +1,527 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.io.InputStream; +import java.io.IOException; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.xml.sax.Attributes; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +import com.android.powermodel.component.AudioProfile; +import com.android.powermodel.component.BluetoothProfile; +import com.android.powermodel.component.CameraProfile; +import com.android.powermodel.component.CpuProfile; +import com.android.powermodel.component.FlashlightProfile; +import com.android.powermodel.component.GpsProfile; +import com.android.powermodel.component.ModemProfile; +import com.android.powermodel.component.ScreenProfile; +import com.android.powermodel.component.VideoProfile; +import com.android.powermodel.component.WifiProfile; +import com.android.powermodel.util.Conversion; + +public class PowerProfile { + + // Remaining fields from the android code for which the actual usage is unclear. + // battery.capacity + // bluetooth.controller.voltage + // modem.controller.voltage + // gps.voltage + // wifi.controller.voltage + // radio.on + // radio.scanning + // radio.active + // memory.bandwidths + // wifi.batchedscan + // wifi.scan + // wifi.on + // wifi.active + // wifi.controller.tx_levels + + private static Pattern RE_CLUSTER_POWER = Pattern.compile("cpu.cluster_power.cluster([0-9]*)"); + private static Pattern RE_CORE_SPEEDS = Pattern.compile("cpu.core_speeds.cluster([0-9]*)"); + private static Pattern RE_CORE_POWER = Pattern.compile("cpu.core_power.cluster([0-9]*)"); + + private HashMap<Component, ComponentProfile> mComponents = new HashMap(); + + /** + * Which element we are currently parsing. + */ + enum ElementState { + BEGIN, + TOP, + ITEM, + ARRAY, + VALUE + } + + /** + * Implements the reading and power model logic. + */ + private static class Parser { + private final InputStream mStream; + private final PowerProfile mResult; + + // Builders for the ComponentProfiles. + private final AudioProfile mAudio = new AudioProfile(); + private final BluetoothProfile mBluetooth = new BluetoothProfile(); + private final CameraProfile mCamera = new CameraProfile(); + private final CpuProfile.Builder mCpuBuilder = new CpuProfile.Builder(); + private final FlashlightProfile mFlashlight = new FlashlightProfile(); + private final GpsProfile.Builder mGpsBuilder = new GpsProfile.Builder(); + private final ModemProfile.Builder mModemBuilder = new ModemProfile.Builder(); + private final ScreenProfile mScreen = new ScreenProfile(); + private final VideoProfile mVideo = new VideoProfile(); + private final WifiProfile mWifi = new WifiProfile(); + + /** + * Constructor to capture the parameters to read. + */ + Parser(InputStream stream) { + mStream = stream; + mResult = new PowerProfile(); + } + + /** + * Read the stream, parse it, and apply the power model. + * Do not call this more than once. + */ + PowerProfile parse() throws ParseException { + final SAXParserFactory factory = SAXParserFactory.newInstance(); + AndroidResourceHandler handler = null; + try { + final SAXParser saxParser = factory.newSAXParser(); + + handler = new AndroidResourceHandler() { + @Override + public void onItem(Locator locator, String name, float value) + throws SAXParseException { + Parser.this.onItem(locator, name, value); + } + + @Override + public void onArray(Locator locator, String name, float[] value) + throws SAXParseException { + Parser.this.onArray(locator, name, value); + } + }; + + saxParser.parse(mStream, handler); + } catch (ParserConfigurationException ex) { + // Coding error, not runtime error. + throw new RuntimeException(ex); + } catch (SAXParseException ex) { + throw new ParseException(ex.getLineNumber(), ex.getMessage(), ex); + } catch (SAXException | IOException ex) { + // Make a guess about the line number. + throw new ParseException(handler.getLineNumber(), ex.getMessage(), ex); + } + + // TODO: This doesn't cover the multiple algorithms. Some refactoring will + // be necessary. + mResult.mComponents.put(Component.AUDIO, mAudio); + mResult.mComponents.put(Component.BLUETOOTH, mBluetooth); + mResult.mComponents.put(Component.CAMERA, mCamera); + mResult.mComponents.put(Component.CPU, mCpuBuilder.build()); + mResult.mComponents.put(Component.FLASHLIGHT, mFlashlight); + mResult.mComponents.put(Component.GPS, mGpsBuilder.build()); + mResult.mComponents.put(Component.MODEM, mModemBuilder.build()); + mResult.mComponents.put(Component.SCREEN, mScreen); + mResult.mComponents.put(Component.VIDEO, mVideo); + mResult.mComponents.put(Component.WIFI, mWifi); + + return mResult; + } + + /** + * Handles an item tag in the power_profile.xml. + */ + public void onItem(Locator locator, String name, float value) throws SAXParseException { + Integer index; + try { + if ("ambient.on".equals(name)) { + mScreen.ambientMa = value; + } else if ("audio".equals(name)) { + mAudio.onMa = value; + } else if ("bluetooth.controller.idle".equals(name)) { + mBluetooth.idleMa = value; + } else if ("bluetooth.controller.rx".equals(name)) { + mBluetooth.rxMa = value; + } else if ("bluetooth.controller.tx".equals(name)) { + mBluetooth.txMa = value; + } else if ("camera.avg".equals(name)) { + mCamera.onMa = value; + } else if ("camera.flashlight".equals(name)) { + mFlashlight.onMa = value; + } else if ("cpu.suspend".equals(name)) { + mCpuBuilder.setSuspendMa(value); + } else if ("cpu.idle".equals(name)) { + mCpuBuilder.setIdleMa(value); + } else if ("cpu.active".equals(name)) { + mCpuBuilder.setActiveMa(value); + } else if ((index = matchIndexedRegex(locator, RE_CLUSTER_POWER, name)) != null) { + mCpuBuilder.setClusterPower(index, value); + } else if ("gps.on".equals(name)) { + mGpsBuilder.setOnMa(value); + } else if ("modem.controller.sleep".equals(name)) { + mModemBuilder.setSleepMa(value); + } else if ("modem.controller.idle".equals(name)) { + mModemBuilder.setIdleMa(value); + } else if ("modem.controller.rx".equals(name)) { + mModemBuilder.setRxMa(value); + } else if ("radio.scanning".equals(name)) { + mModemBuilder.setScanningMa(value); + } else if ("screen.on".equals(name)) { + mScreen.onMa = value; + } else if ("screen.full".equals(name)) { + mScreen.fullMa = value; + } else if ("video".equals(name)) { + mVideo.onMa = value; + } else if ("wifi.controller.idle".equals(name)) { + mWifi.idleMa = value; + } else if ("wifi.controller.rx".equals(name)) { + mWifi.rxMa = value; + } else if ("wifi.controller.tx".equals(name)) { + mWifi.txMa = value; + } else { + // TODO: Uncomment this when we have all of the items parsed. + // throw new SAXParseException("Unhandled <item name=\"" + name + "\"> element", + // locator, ex); + + } + } catch (ParseException ex) { + throw new SAXParseException(ex.getMessage(), locator, ex); + } + } + + /** + * Handles an array tag in the power_profile.xml. + */ + public void onArray(Locator locator, String name, float[] value) throws SAXParseException { + Integer index; + try { + if ("cpu.clusters.cores".equals(name)) { + mCpuBuilder.setCoreCount(Conversion.toIntArray(value)); + } else if ((index = matchIndexedRegex(locator, RE_CORE_SPEEDS, name)) != null) { + mCpuBuilder.setCoreSpeeds(index, Conversion.toIntArray(value)); + } else if ((index = matchIndexedRegex(locator, RE_CORE_POWER, name)) != null) { + mCpuBuilder.setCorePower(index, value); + } else if ("gps.signalqualitybased".equals(name)) { + mGpsBuilder.setSignalMa(value); + } else if ("modem.controller.tx".equals(name)) { + mModemBuilder.setTxMa(value); + } else { + // TODO: Uncomment this when we have all of the items parsed. + // throw new SAXParseException("Unhandled <item name=\"" + name + "\"> element", + // locator, ex); + } + } catch (ParseException ex) { + throw new SAXParseException(ex.getMessage(), locator, ex); + } + } + } + + /** + * SAX XML handler that can parse the android resource files. + * In our case, all elements are floats. + */ + abstract static class AndroidResourceHandler extends DefaultHandler { + /** + * The set of names already processed. Map of name to line number. + */ + private HashMap<String,Integer> mAlreadySeen = new HashMap<String,Integer>(); + + /** + * Where in the document we are parsing. + */ + private Locator mLocator; + + /** + * Which element we are currently parsing. + */ + private ElementState mState = ElementState.BEGIN; + + /** + * Saved name from item and array elements. + */ + private String mName; + + /** + * The text that is currently being captured, or null if {@link #startCapturingText()} + * has not been called. + */ + private StringBuilder mText; + + /** + * The array values that have been parsed so for for this array. Null if we are + * not inside an array tag. + */ + private ArrayList<Float> mArray; + + /** + * Called when an item tag is encountered. + */ + public abstract void onItem(Locator locator, String name, float value) + throws SAXParseException; + + /** + * Called when an array is encountered. + */ + public abstract void onArray(Locator locator, String name, float[] value) + throws SAXParseException; + + /** + * If we have a Locator set, return the line number, otherwise return 0. + */ + public int getLineNumber() { + return mLocator != null ? mLocator.getLineNumber() : 0; + } + + /** + * Handle setting the parse location object. + */ + public void setDocumentLocator(Locator locator) { + mLocator = locator; + } + + /** + * Handle beginning of an element. + * + * @param ns Namespace uri + * @param ln Local name (inside namespace) + * @param element Tag name + */ + @Override + public void startElement(String ns, String ln, String element, + Attributes attr) throws SAXException { + switch (mState) { + case BEGIN: + // Outer element, we don't care the tag name. + mState = ElementState.TOP; + return; + case TOP: + if ("item".equals(element)) { + mState = ElementState.ITEM; + saveNameAttribute(attr); + startCapturingText(); + return; + } else if ("array".equals(element)) { + mState = ElementState.ARRAY; + mArray = new ArrayList<Float>(); + saveNameAttribute(attr); + return; + } + break; + case ARRAY: + if ("value".equals(element)) { + mState = ElementState.VALUE; + startCapturingText(); + return; + } + break; + } + throw new SAXParseException("unexpected element: '" + element + "'", mLocator); + } + + /** + * Handle end of an element. + * + * @param ns Namespace uri + * @param ln Local name (inside namespace) + * @param element Tag name + */ + @Override + public void endElement(String ns, String ln, String element) throws SAXException { + switch (mState) { + case ITEM: { + float value = parseFloat(finishCapturingText()); + mState = ElementState.TOP; + onItem(mLocator, mName, value); + break; + } + case ARRAY: { + final int N = mArray.size(); + float[] values = new float[N]; + for (int i=0; i<N; i++) { + values[i] = mArray.get(i); + } + mArray = null; + mState = ElementState.TOP; + onArray(mLocator, mName, values); + break; + } + case VALUE: { + mArray.add(parseFloat(finishCapturingText())); + mState = ElementState.ARRAY; + break; + } + } + } + + /** + * Interstitial text received. + * + * @throws SAXException if there shouldn't be non-whitespace text here + */ + @Override + public void characters(char text[], int start, int length) throws SAXException { + if (mText == null && length > 0 && !isWhitespace(text, start, length)) { + throw new SAXParseException("unexpected text: '" + + firstLine(text, start, length).trim() + "'", mLocator); + } + if (mText != null) { + mText.append(text, start, length); + } + } + + /** + * Begin collecting text from inside an element. + */ + private void startCapturingText() { + if (mText != null) { + throw new RuntimeException("ASSERTION FAILED: Shouldn't be already capturing" + + " text. mState=" + mState.name() + + " line=" + mLocator.getLineNumber() + + " column=" + mLocator.getColumnNumber()); + } + mText = new StringBuilder(); + } + + /** + * Stop capturing text from inside an element. + * + * @return the captured text + */ + private String finishCapturingText() { + if (mText == null) { + throw new RuntimeException("ASSERTION FAILED: Should already be capturing" + + " text. mState=" + mState.name() + + " line=" + mLocator.getLineNumber() + + " column=" + mLocator.getColumnNumber()); + } + final String result = mText.toString().trim(); + mText = null; + return result; + } + + /** + * Get the "name" attribute. + * + * @throws SAXParseException if the name attribute is not present or if + * the name has already been seen in the file. + */ + private void saveNameAttribute(Attributes attr) throws SAXParseException { + final String name = attr.getValue("name"); + if (name == null) { + throw new SAXParseException("expected 'name' attribute", mLocator); + } + Integer prev = mAlreadySeen.put(name, mLocator.getLineNumber()); + if (prev != null) { + throw new SAXParseException("name '" + name + "' already seen on line: " + prev, + mLocator); + } + mName = name; + } + + /** + * Gets the float value of the string. + * + * @throws SAXParseException if 'text' can't be parsed as a float. + */ + private float parseFloat(String text) throws SAXParseException { + try { + return Float.parseFloat(text); + } catch (NumberFormatException ex) { + throw new SAXParseException("not a valid float value: '" + text + "'", + mLocator, ex); + } + } + } + + /** + * Return whether the given substring is all whitespace. + */ + private static boolean isWhitespace(char[] text, int start, int length) { + for (int i = start; i < (start + length); i++) { + if (!Character.isSpace(text[i])) { + return false; + } + } + return true; + } + + /** + * Return the contents of text up to the first newline. + */ + private static String firstLine(char[] text, int start, int length) { + // TODO: The line number will be wrong if we skip preceeding blank lines. + while (length > 0) { + if (Character.isSpace(text[start])) { + start++; + length--; + } + } + int newlen = 0; + for (; newlen < length; newlen++) { + final char c = text[newlen]; + if (c == '\n' || c == '\r') { + break; + } + } + return new String(text, start, newlen); + } + + /** + * If the pattern matches, return the first group of that as an Integer. + * If not return null. + */ + private static Integer matchIndexedRegex(Locator locator, Pattern pattern, String text) + throws SAXParseException { + final Matcher m = pattern.matcher(text); + if (m.matches()) { + try { + return Integer.parseInt(m.group(1)); + } catch (NumberFormatException ex) { + throw new SAXParseException("Invalid field name: '" + text + "'", locator, ex); + } + } else { + return null; + } + } + + public static PowerProfile parse(InputStream stream) throws ParseException { + return (new Parser(stream)).parse(); + } + + private PowerProfile() { + } + + public ComponentProfile getComponent(Component component) { + return mComponents.get(component); + } + +} diff --git a/tools/powermodel/src/com/android/powermodel/PowerReport.java b/tools/powermodel/src/com/android/powermodel/PowerReport.java new file mode 100644 index 000000000000..76ba67235b0a --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/PowerReport.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ImmutableMap; + +/** + * PowerReport contains the summary of all power used on a device + * as reported by batterystats or statsd, based on the power profile. + */ +public class PowerReport { + private AppList<AppPower> mApps; + private double mTotalPowerMah; + + private PowerReport() { + } + + /** + * The total power used by this device for this PowerReport. + */ + public double getTotalPowerMah() { + return mTotalPowerMah; + } + + public List<AppPower> getAllApps() { + return mApps.getAllApps(); + } + + public List<AppPower> getRegularApps() { + return mApps.getRegularApps(); + } + + public List<AppPower> findApp(String pkg) { + return mApps.findApp(pkg); + } + + public AppPower findApp(SpecialApp specialApp) { + return mApps.findApp(specialApp); + } + + public static PowerReport createReport(PowerProfile profile, ActivityReport activityReport) { + final PowerReport.Builder powerReport = new PowerReport.Builder(); + for (final AppActivity appActivity: activityReport.getAllApps()) { + final AppPower.Builder appPower = new AppPower.Builder(); + appPower.setAttribution(appActivity.getAttribution()); + + for (final ImmutableMap.Entry<Component,ComponentActivity> entry: + appActivity.getComponentActivities().entrySet()) { + final ComponentPower componentPower = entry.getValue() + .applyProfile(activityReport, profile); + if (componentPower != null) { + appPower.addComponentPower(entry.getKey(), componentPower); + } + } + + powerReport.add(appPower); + } + return powerReport.build(); + } + + private static class Builder { + private AppList.Builder mApps = new AppList.Builder(); + + public Builder() { + } + + public PowerReport build() { + final PowerReport report = new PowerReport(); + + report.mApps = mApps.build(); + + for (AppPower app: report.mApps.getAllApps()) { + report.mTotalPowerMah += app.getAppPowerMah(); + } + + return report; + } + + public void add(AppPower.Builder app) { + mApps.put(app.getAttribution(), app); + } + } +} diff --git a/tools/powermodel/src/com/android/powermodel/RawBatteryStats.java b/tools/powermodel/src/com/android/powermodel/RawBatteryStats.java new file mode 100644 index 000000000000..76c0482772f7 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/RawBatteryStats.java @@ -0,0 +1,1175 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.io.InputStream; +import java.io.IOException; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public class RawBatteryStats { + /** + * The factory objects for the records. Initialized in the static block. + */ + private static HashMap<String,RecordFactory> sFactories + = new HashMap<String,RecordFactory>(); + + /** + * The Record objects that have been parsed. + */ + private ArrayList<Record> mRecords = new ArrayList<Record>(); + + /** + * The Record objects that have been parsed, indexed by type. + * + * Don't use this before {@link #indexRecords()} has been called. + */ + private ImmutableMap<String,ImmutableList<Record>> mRecordsByType; + + /** + * The attribution keys for which we have data (corresponding to UIDs we've seen). + * <p> + * Does not include the synthetic apps. + * <p> + * Don't use this before {@link #indexRecords()} has been called. + */ + private ImmutableSet<AttributionKey> mApps; + + /** + * The warnings that have been issued during parsing. + */ + private ArrayList<Warning> mWarnings = new ArrayList<Warning>(); + + /** + * The version of the BatteryStats dumpsys that we are using. This value + * is set to -1 initially, and then when parsing the (hopefully) first + * line, 'vers', it is set to the correct version. + */ + private int mDumpsysVersion = -1; + + /** + * Enum used in the Line annotation to mark whether a field is expected to be + * system-wide or scoped to an app. + */ + public enum Scope { + SYSTEM, + UID + } + + /** + * Enum used to indicated the expected number of results. + */ + public enum Count { + SINGLE, + MULTIPLE + } + + /** + * Annotates classes that represent a line of CSV in the batterystats CSV + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @interface Line { + String tag(); + Scope scope(); + Count count(); + } + + /** + * Annotates fields that should be parsed automatically from CSV + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface Field { + /** + * The "column" of this field in the most recent version of the CSV. + * When parsing old versions, fields that were added will be automatically + * removed and the indices will be fixed up. + * + * The header fields (version, uid, category, type) will be automatically + * handled for the base Line type. The index 0 should start after those. + */ + int index(); + + /** + * First version that this field appears in. + */ + int added() default 0; + } + + /** + * Each line in the BatteryStats CSV is tagged with a category, that says + * which of the time collection modes was used for the data. + */ + public enum Category { + INFO("i"), + LAST("l"), + UNPLUGGED("u"), + CURRENT("c"); + + public final String tag; + + Category(String tag) { + this.tag = tag; + } + } + + /** + * Base class for all lines in a batterystats CSV file. + */ + public static class Record { + /** + * Whether all of the fields for the indicated version of this record + * have been filled in. + */ + public boolean complete; + + + @Field(index=-4) + public int lineVersion; + + @Field(index=-3) + public int uid; + + @Field(index=-2) + public Category category; + + @Field(index=-1) + public String lineType; + } + + @Line(tag="bt", scope=Scope.SYSTEM, count=Count.SINGLE) + public static class Battery extends Record { + // If which != STATS_SINCE_CHARGED, the csv will be "N/A" and we will get + // a parsing warning. Nobody uses anything other than STATS_SINCE_CHARGED. + @Field(index=0) + public int startCount; + + @Field(index=1) + public long whichBatteryRealtimeMs; + + @Field(index=2) + public long whichBatteryUptimeMs; + + @Field(index=3) + public long totalRealtimeMs; + + @Field(index=4) + public long totalUptimeMs; + + @Field(index=5) + public long getStartClockTimeMs; + + @Field(index=6) + public long whichBatteryScreenOffRealtimeMs; + + @Field(index=7) + public long whichBatteryScreenOffUptimeMs; + + @Field(index=8) + public long estimatedBatteryCapacityMah; + + @Field(index=9) + public long minLearnedBatteryCapacityMah; + + @Field(index=10) + public long maxLearnedBatteryCapacityMah; + + @Field(index=11) + public long screenDozeTimeMs; + } + + @Line(tag="gn", scope=Scope.SYSTEM, count=Count.SINGLE) + public static class GlobalNetwork extends Record { + @Field(index=0) + public long mobileRxTotalBytes; + + @Field(index=1) + public long mobileTxTotalBytes; + + @Field(index=2) + public long wifiRxTotalBytes; + + @Field(index=3) + public long wifiTxTotalBytes; + + @Field(index=4) + public long mobileRxTotalPackets; + + @Field(index=5) + public long mobileTxTotalPackets; + + @Field(index=6) + public long wifiRxTotalPackets; + + @Field(index=7) + public long wifiTxTotalPackets; + + @Field(index=8) + public long btRxTotalBytes; + + @Field(index=9) + public long btTxTotalBytes; + } + + @Line(tag="gmcd", scope=Scope.SYSTEM, count=Count.SINGLE) + public static class GlobalModemController extends Record { + @Field(index=0) + public long idleMs; + + @Field(index=1) + public long rxTimeMs; + + @Field(index=2) + public long powerMaMs; + + @Field(index=3) + public long[] txTimeMs; + } + + @Line(tag="m", scope=Scope.SYSTEM, count=Count.SINGLE) + public static class Misc extends Record { + @Field(index=0) + public long screenOnTimeMs; + + @Field(index=1) + public long phoneOnTimeMs; + + @Field(index=2) + public long fullWakeLockTimeTotalMs; + + @Field(index=3) + public long partialWakeLockTimeTotalMs; + + @Field(index=4) + public long mobileRadioActiveTimeMs; + + @Field(index=5) + public long mobileRadioActiveAdjustedTimeMs; + + @Field(index=6) + public long interactiveTimeMs; + + @Field(index=7) + public long powerSaveModeEnabledTimeMs; + + @Field(index=8) + public int connectivityChangeCount; + + @Field(index=9) + public long deepDeviceIdleModeTimeMs; + + @Field(index=10) + public long deepDeviceIdleModeCount; + + @Field(index=11) + public long deepDeviceIdlingTimeMs; + + @Field(index=12) + public long deepDeviceIdlingCount; + + @Field(index=13) + public long mobileRadioActiveCount; + + @Field(index=14) + public long mobileRadioActiveUnknownTimeMs; + + @Field(index=15) + public long lightDeviceIdleModeTimeMs; + + @Field(index=16) + public long lightDeviceIdleModeCount; + + @Field(index=17) + public long lightDeviceIdlingTimeMs; + + @Field(index=18) + public long lightDeviceIdlingCount; + + @Field(index=19) + public long lightLongestDeviceIdleModeTimeMs; + + @Field(index=20) + public long deepLongestDeviceIdleModeTimeMs; + } + + @Line(tag="nt", scope=Scope.UID, count=Count.SINGLE) + public static class Network extends Record { + @Field(index=0) + public long mobileRxBytes; + + @Field(index=1) + public long mobileTxBytes; + + @Field(index=2) + public long wifiRxBytes; + + @Field(index=3) + public long wifiTxBytes; + + @Field(index=4) + public long mobileRxPackets; + + @Field(index=5) + public long mobileTxPackets; + + @Field(index=6) + public long wifiRxPackets; + + @Field(index=7) + public long wifiTxPackets; + + // This is microseconds, because... batterystats. + @Field(index=8) + public long mobileRadioActiveTimeUs; + + @Field(index=9) + public long mobileRadioActiveCount; + + @Field(index=10) + public long btRxBytes; + + @Field(index=11) + public long btTxBytes; + + @Field(index=12) + public long mobileWakeupCount; + + @Field(index=13) + public long wifiWakeupCount; + + @Field(index=14) + public long mobileBgRxBytes; + + @Field(index=15) + public long mobileBgTxBytes; + + @Field(index=16) + public long wifiBgRxBytes; + + @Field(index=17) + public long wifiBgTxBytes; + + @Field(index=18) + public long mobileBgRxPackets; + + @Field(index=19) + public long mobileBgTxPackets; + + @Field(index=20) + public long wifiBgRxPackets; + + @Field(index=21) + public long wifiBgTxPackets; + } + + @Line(tag="sgt", scope=Scope.SYSTEM, count=Count.SINGLE) + public static class SignalStrengthTime extends Record { + @Field(index=0) + public long[] phoneSignalStrengthTimeMs; + } + + @Line(tag="sst", scope=Scope.SYSTEM, count=Count.SINGLE) + public static class SignalScanningTime extends Record { + @Field(index=0) + public long phoneSignalScanningTimeMs; + } + + @Line(tag="uid", scope=Scope.UID, count=Count.MULTIPLE) + public static class Uid extends Record { + @Field(index=0) + public int uidKey; + + @Field(index=1) + public String pkg; + } + + @Line(tag="vers", scope=Scope.SYSTEM, count=Count.SINGLE) + public static class Version extends Record { + @Field(index=0) + public int dumpsysVersion; + + @Field(index=1) + public int parcelVersion; + + @Field(index=2) + public String startPlatformVersion; + + @Field(index=3) + public String endPlatformVersion; + } + + /** + * Codes for the warnings to classify warnings without parsing them. + */ + public enum WarningId { + /** + * A row didn't have enough fields to match any records and let us extract + * a line type. + */ + TOO_FEW_FIELDS_FOR_LINE_TYPE, + + /** + * We couldn't find a Record for the given line type. + */ + NO_MATCHING_LINE_TYPE, + + /** + * Couldn't set the value of a field. Usually this is because the + * contents of a numeric type couldn't be parsed. + */ + BAD_FIELD_TYPE, + + /** + * There were extra field values in the input text. + */ + TOO_MANY_FIELDS, + + /** + * There were fields that we were expecting (for this version + * of the dumpsys) that weren't provided in the CSV data. + */ + NOT_ENOUGH_FIELDS, + + /** + * The dumpsys version in the 'vers' CSV line couldn't be parsed. + */ + BAD_DUMPSYS_VERSION + } + + /** + * A non-fatal problem detected during parsing. + */ + public static class Warning { + private int mLineNumber; + private WarningId mId; + private ArrayList<String> mFields; + private String mMessage; + private String[] mExtras; + + public Warning(int lineNumber, WarningId id, ArrayList<String> fields, String message, + String[] extras) { + mLineNumber = lineNumber; + mId = id; + mFields = fields; + mMessage = message; + mExtras = extras; + } + + public int getLineNumber() { + return mLineNumber; + } + + public ArrayList<String> getFields() { + return mFields; + } + + public String getMessage() { + return mMessage; + } + + public String[] getExtras() { + return mExtras; + } + } + + /** + * Base class for classes to set fields on Record objects via reflection. + */ + private abstract static class FieldSetter { + private int mIndex; + private int mAdded; + protected java.lang.reflect.Field mField; + + FieldSetter(int index, int added, java.lang.reflect.Field field) { + mIndex = index; + mAdded = added; + mField = field; + } + + String getName() { + return mField.getName(); + } + + int getIndex() { + return mIndex; + } + + int getAdded() { + return mAdded; + } + + boolean isArray() { + return mField.getType().isArray(); + } + + abstract void setField(int lineNumber, Record object, String value) throws ParseException; + abstract void setArray(int lineNumber, Record object, ArrayList<String> values, + int startIndex, int endIndex) throws ParseException; + + @Override + public String toString() { + final String className = getClass().getName(); + int startIndex = Math.max(className.lastIndexOf('.'), className.lastIndexOf('$')); + if (startIndex < 0) { + startIndex = 0; + } else { + startIndex++; + } + return className.substring(startIndex) + "(index=" + mIndex + " added=" + mAdded + + " field=" + mField.getName() + + " type=" + mField.getType().getSimpleName() + + ")"; + } + } + + /** + * Sets int fields on Record objects using reflection. + */ + private static class IntFieldSetter extends FieldSetter { + IntFieldSetter(int index, int added, java.lang.reflect.Field field) { + super(index, added, field); + } + + void setField(int lineNumber, Record object, String value) throws ParseException { + try { + mField.setInt(object, Integer.parseInt(value.trim())); + } catch (NumberFormatException ex) { + throw new ParseException(lineNumber, "can't parse as integer: " + value); + } catch (IllegalAccessException | IllegalArgumentException + | ExceptionInInitializerError ex) { + throw new RuntimeException(ex); + } + } + + void setArray(int lineNumber, Record object, ArrayList<String> values, + int startIndex, int endIndex) throws ParseException { + try { + final int[] array = new int[endIndex-startIndex]; + for (int i=startIndex; i<endIndex; i++) { + final String value = values.get(startIndex+i); + try { + array[i] = Integer.parseInt(value.trim()); + } catch (NumberFormatException ex) { + throw new ParseException(lineNumber, "can't parse field " + + i + " as integer: " + value); + } + } + mField.set(object, array); + } catch (IllegalAccessException | IllegalArgumentException + | ExceptionInInitializerError ex) { + throw new RuntimeException(ex); + } + } + } + + /** + * Sets long fields on Record objects using reflection. + */ + private static class LongFieldSetter extends FieldSetter { + LongFieldSetter(int index, int added, java.lang.reflect.Field field) { + super(index, added, field); + } + + void setField(int lineNumber, Record object, String value) throws ParseException { + try { + mField.setLong(object, Long.parseLong(value.trim())); + } catch (NumberFormatException ex) { + throw new ParseException(lineNumber, "can't parse as long: " + value); + } catch (IllegalAccessException | IllegalArgumentException + | ExceptionInInitializerError ex) { + throw new RuntimeException(ex); + } + } + + void setArray(int lineNumber, Record object, ArrayList<String> values, + int startIndex, int endIndex) throws ParseException { + try { + final long[] array = new long[endIndex-startIndex]; + for (int i=0; i<(endIndex-startIndex); i++) { + final String value = values.get(startIndex+i); + try { + array[i] = Long.parseLong(value.trim()); + } catch (NumberFormatException ex) { + throw new ParseException(lineNumber, "can't parse field " + + i + " as long: " + value); + } + } + mField.set(object, array); + } catch (IllegalAccessException | IllegalArgumentException + | ExceptionInInitializerError ex) { + throw new RuntimeException(ex); + } + } + } + + /** + * Sets String fields on Record objects using reflection. + */ + private static class StringFieldSetter extends FieldSetter { + StringFieldSetter(int index, int added, java.lang.reflect.Field field) { + super(index, added, field); + } + + void setField(int lineNumber, Record object, String value) throws ParseException { + try { + mField.set(object, value); + } catch (IllegalAccessException | IllegalArgumentException + | ExceptionInInitializerError ex) { + throw new RuntimeException(ex); + } + } + + void setArray(int lineNumber, Record object, ArrayList<String> values, + int startIndex, int endIndex) throws ParseException { + try { + final String[] array = new String[endIndex-startIndex]; + for (int i=0; i<(endIndex-startIndex); i++) { + array[i] = values.get(startIndex+1); + } + mField.set(object, array); + } catch (IllegalAccessException | IllegalArgumentException + | ExceptionInInitializerError ex) { + throw new RuntimeException(ex); + } + } + } + + /** + * Sets enum fields on Record objects using reflection. + * + * To be parsed automatically, enums must have a public final String tag + * field, which is the string that will appear in the csv for that enum value. + */ + private static class EnumFieldSetter extends FieldSetter { + private final HashMap<String,Enum> mTags = new HashMap<String,Enum>(); + + EnumFieldSetter(int index, int added, java.lang.reflect.Field field) { + super(index, added, field); + + // Build the mapping of tags to values. + final Class<?> fieldType = field.getType(); + + java.lang.reflect.Field tagField = null; + try { + tagField = fieldType.getField("tag"); + } catch (NoSuchFieldException ex) { + throw new RuntimeException("Missing tag field." + + " To be parsed automatically, enums must have" + + " a String field called tag. Enum class: " + fieldType.getName() + + " Containing class: " + field.getDeclaringClass().getName() + + " Field: " + field.getName()); + + } + if (!String.class.equals(tagField.getType())) { + throw new RuntimeException("Tag field is not string." + + " To be parsed automatically, enums must have" + + " a String field called tag. Enum class: " + fieldType.getName() + + " Containing class: " + field.getDeclaringClass().getName() + + " Field: " + field.getName() + + " Tag field type: " + tagField.getType().getName()); + } + + for (final Object enumValue: fieldType.getEnumConstants()) { + String tag = null; + try { + tag = (String)tagField.get(enumValue); + } catch (IllegalAccessException | IllegalArgumentException + | ExceptionInInitializerError ex) { + throw new RuntimeException(ex); + } + mTags.put(tag, (Enum)enumValue); + } + } + + void setField(int lineNumber, Record object, String value) throws ParseException { + final Enum enumValue = mTags.get(value); + if (enumValue == null) { + throw new ParseException(lineNumber, "Could not find enum for field " + + getName() + " for tag: " + value); + } + try { + mField.set(object, enumValue); + } catch (IllegalAccessException | IllegalArgumentException + | ExceptionInInitializerError ex) { + throw new RuntimeException(ex); + } + } + + void setArray(int lineNumber, Record object, ArrayList<String> values, + int startIndex, int endIndex) throws ParseException { + try { + final Object array = Array.newInstance(mField.getType().getComponentType(), + endIndex-startIndex); + for (int i=0; i<(endIndex-startIndex); i++) { + final String value = values.get(startIndex+i); + final Enum enumValue = mTags.get(value); + if (enumValue == null) { + throw new ParseException(lineNumber, "Could not find enum for field " + + getName() + " for tag: " + value); + } + Array.set(array, i, enumValue); + } + mField.set(object, array); + } catch (IllegalAccessException | IllegalArgumentException + | ExceptionInInitializerError ex) { + throw new RuntimeException(ex); + } + } + } + + /** + * Factory for the record classes. Uses reflection to create + * the fields. + */ + private static class RecordFactory { + private String mTag; + private Class<? extends Record> mSubclass; + private ArrayList<FieldSetter> mFieldSetters; + + RecordFactory(String tag, Class<? extends Record> subclass, + ArrayList<FieldSetter> fieldSetters) { + mTag = tag; + mSubclass = subclass; + mFieldSetters = fieldSetters; + } + + /** + * Create an object of one of the subclasses of Record, and fill + * in the fields marked with the Field annotation. + * + * @return a new Record with the fields filled in. If there are missing + * fields, the {@link Record.complete} field will be set to false. + */ + Record create(RawBatteryStats bs, int dumpsysVersion, int lineNumber, + ArrayList<String> fieldValues) { + final boolean debug = false; + Record record = null; + try { + if (debug) { + System.err.println("Creating object: " + mSubclass.getSimpleName()); + } + record = mSubclass.newInstance(); + } catch (IllegalAccessException | InstantiationException + | ExceptionInInitializerError | SecurityException ex) { + throw new RuntimeException("Exception creating " + mSubclass.getName() + + " for '" + mTag + "' record.", ex); + } + record.complete = true; + int fieldIndex = 0; + int setterIndex = 0; + while (fieldIndex < fieldValues.size() && setterIndex < mFieldSetters.size()) { + final FieldSetter setter = mFieldSetters.get(setterIndex); + + if (dumpsysVersion >= 0 && dumpsysVersion < setter.getAdded()) { + // The version being parsed doesn't have the field for this setter, + // so skip the setter but not the field. + setterIndex++; + continue; + } + + final String value = fieldValues.get(fieldIndex); + try { + if (debug) { + System.err.println(" setting field " + setter + " to: " + value); + } + if (setter.isArray()) { + setter.setArray(lineNumber, record, fieldValues, + fieldIndex, fieldValues.size()); + // The rest of the fields have been consumed. + fieldIndex = fieldValues.size(); + setterIndex = mFieldSetters.size(); + break; + } else { + setter.setField(lineNumber, record, value); + } + } catch (ParseException ex) { + bs.addWarning(lineNumber, WarningId.BAD_FIELD_TYPE, fieldValues, + ex.getMessage(), mTag, value); + record.complete = false; + } + + fieldIndex++; + setterIndex++; + } + + // If there are extra fields, this record is complete, there are just + // extra values, so we issue a warning but don't mark it incomplete. + if (fieldIndex < fieldValues.size()) { + bs.addWarning(lineNumber, WarningId.TOO_MANY_FIELDS, fieldValues, + "Line '" + mTag + "' has extra fields.", + mTag, Integer.toString(fieldIndex), Integer.toString(fieldValues.size())); + if (debug) { + for (int i=0; i<mFieldSetters.size(); i++) { + System.err.println(" setter: [" + i + "] " + mFieldSetters.get(i)); + } + } + } + + // If we have any fields that are missing, add a warning and return null. + for (; setterIndex < mFieldSetters.size(); setterIndex++) { + final FieldSetter setter = mFieldSetters.get(setterIndex); + if (dumpsysVersion >= 0 && dumpsysVersion >= setter.getAdded()) { + bs.addWarning(lineNumber, WarningId.NOT_ENOUGH_FIELDS, fieldValues, + "Line '" + mTag + "' missing field: index=" + setterIndex + + " name=" + setter.getName(), + mTag, Integer.toString(setterIndex)); + record.complete = false; + } + } + + return record; + } + } + + /** + * Parse the input stream and return a RawBatteryStats object. + */ + public static RawBatteryStats parse(InputStream input) throws ParseException, IOException { + final RawBatteryStats result = new RawBatteryStats(); + result.parseImpl(input); + return result; + } + + /** + * Get a record. + * <p> + * If multiple of that record are found, returns the first one. There will already + * have been a warning recorded if the count annotation did not match what was in the + * csv. + * <p> + * Returns null if there are no records of that type. + */ + public <T extends Record> T getSingle(Class<T> cl) { + final List<Record> list = mRecordsByType.get(cl.getName()); + if (list == null) { + return null; + } + // Notes: + // - List can never be empty because the list itself wouldn't have been added. + // - Cast is safe because list was populated based on class name (let's assume + // there's only one class loader involved here). + return (T)list.get(0); + } + + /** + * Get a record. + * <p> + * If multiple of that record are found, returns the first one that matches that uid. + * <p> + * Returns null if there are no records of that type that match the given uid. + */ + public <T extends Record> T getSingle(Class<T> cl, int uid) { + final List<Record> list = mRecordsByType.get(cl.getName()); + if (list == null) { + return null; + } + for (final Record record: list) { + if (record.uid == uid) { + // Cast is safe because list was populated based on class name (let's assume + // there's only one class loader involved here). + return (T)record; + } + } + return null; + } + + /** + * Get all the records of the given type. + */ + public <T extends Record> List<T> getMultiple(Class<T> cl) { + final List<Record> list = mRecordsByType.get(cl.getName()); + if (list == null) { + return ImmutableList.<T>of(); + } + // Cast is safe because list was populated based on class name (let's assume + // there's only one class loader involved here). + return ImmutableList.copyOf((List<T>)list); + } + + /** + * Get the UIDs that are covered by this batterystats dump. + */ + public Set<AttributionKey> getApps() { + return mApps; + } + + /** + * No public constructor. Use {@link #parse}. + */ + private RawBatteryStats() { + } + + /** + * Get the list of Record objects that were parsed from the csv. + */ + public List<Record> getRecords() { + return mRecords; + } + + /** + * Gets the warnings that were encountered during parsing. + */ + public List<Warning> getWarnings() { + return mWarnings; + } + + /** + * Implementation of the csv parsing. + */ + private void parseImpl(InputStream input) throws ParseException, IOException { + // Parse the csv + CsvParser.parse(input, new CsvParser.LineProcessor() { + @Override + public void onLine(int lineNumber, ArrayList<String> fields) + throws ParseException { + handleCsvLine(lineNumber, fields); + } + }); + + // Gather the records by class name for the getSingle() and getMultiple() functions. + indexRecords(); + + // Gather the uids from all the places UIDs come from, for getApps(). + indexApps(); + } + + /** + * Handle a line of CSV input, creating the right Record object. + */ + private void handleCsvLine(int lineNumber, ArrayList<String> fields) throws ParseException { + // The standard rows all have the 4 core fields. Anything less isn't what we're + // looking for. + if (fields.size() <= 4) { + addWarning(lineNumber, WarningId.TOO_FEW_FIELDS_FOR_LINE_TYPE, fields, + "Line with too few fields (" + fields.size() + ")", + Integer.toString(fields.size())); + return; + } + + final String lineType = fields.get(3); + + // Handle the vers line specially, because we need the version number + // to make the rest of the machinery work. + if ("vers".equals(lineType)) { + final String versionText = fields.get(4); + try { + mDumpsysVersion = Integer.parseInt(versionText); + } catch (NumberFormatException ex) { + addWarning(lineNumber, WarningId.BAD_DUMPSYS_VERSION, fields, + "Couldn't parse dumpsys version number: '" + versionText, + versionText); + } + } + + // Find the right factory. + final RecordFactory factory = sFactories.get(lineType); + if (factory == null) { + addWarning(lineNumber, WarningId.NO_MATCHING_LINE_TYPE, fields, + "No Record for line type '" + lineType + "'", + lineType); + return; + } + + // Create the record. + final Record record = factory.create(this, mDumpsysVersion, lineNumber, fields); + mRecords.add(record); + } + + /** + * Add to the list of warnings. + */ + private void addWarning(int lineNumber, WarningId id, + ArrayList<String> fields, String message, String... extras) { + mWarnings.add(new Warning(lineNumber, id, fields, message, extras)); + final boolean debug = false; + if (debug) { + final StringBuilder text = new StringBuilder("line "); + text.append(lineNumber); + text.append(": WARNING: "); + text.append(message); + text.append("\n fields: "); + for (int i=0; i<fields.size(); i++) { + final String field = fields.get(i); + if (field.indexOf('"') >= 0) { + text.append('"'); + text.append(field.replace("\"", "\"\"")); + text.append('"'); + } else { + text.append(field); + } + if (i != fields.size() - 1) { + text.append(','); + } + } + text.append('\n'); + for (String extra: extras) { + text.append(" extra: "); + text.append(extra); + text.append('\n'); + } + System.err.print(text.toString()); + } + } + + /** + * Group records by class name. + */ + private void indexRecords() { + final HashMap<String,ArrayList<Record>> map = new HashMap<String,ArrayList<Record>>(); + + // Iterate over all of the records + for (Record record: mRecords) { + final String className = record.getClass().getName(); + + ArrayList<Record> list = map.get(className); + if (list == null) { + list = new ArrayList<Record>(); + map.put(className, list); + } + + list.add(record); + } + + // Make it immutable + final HashMap<String,ImmutableList<Record>> result + = new HashMap<String,ImmutableList<Record>>(); + for (HashMap.Entry<String,ArrayList<Record>> entry: map.entrySet()) { + result.put(entry.getKey(), ImmutableList.copyOf(entry.getValue())); + } + + // Initialize here so uninitialized access will result in NPE. + mRecordsByType = ImmutableMap.copyOf(result); + } + + /** + * Collect the UIDs from the csv. + * + * They come from two places. + * <ul> + * <li>The uid to package name map entries ({@link #Uid}) at the beginning. + * <li>The uid fields of the rest of the entries, some of which might not + * have package names associated with them. + * </ul> + * + * TODO: Is this where we should also do the logic about the special UIDs? + */ + private void indexApps() { + final HashMap<Integer,HashSet<String>> uids = new HashMap<Integer,HashSet<String>>(); + + // The Uid rows, from which we get package names + for (Uid record: getMultiple(Uid.class)) { + HashSet<String> list = uids.get(record.uidKey); + if (list == null) { + list = new HashSet<String>(); + uids.put(record.uidKey, list); + } + list.add(record.pkg); + } + + // The uid fields of everything + for (Record record: mRecords) { + // The 0 in the INFO records isn't really root, it's just unfilled data. + // The root uid (0) will show up practically in every record, but don't force it. + if (record.category != Category.INFO) { + if (uids.get(record.uid) == null) { + // There is no other data about this UID, but it does exist! + uids.put(record.uid, new HashSet<String>()); + } + } + } + + // Turn our temporary lists of package names into AttributionKeys. + final HashSet<AttributionKey> result = new HashSet<AttributionKey>(); + for (HashMap.Entry<Integer,HashSet<String>> entry: uids.entrySet()) { + result.add(new AttributionKey(entry.getKey(), entry.getValue())); + } + + // Initialize here so uninitialized access will result in NPE. + mApps = ImmutableSet.copyOf(result); + } + + /** + * Init the factory classes. + */ + static { + for (Class<?> cl: RawBatteryStats.class.getClasses()) { + final Line lineAnnotation = cl.getAnnotation(Line.class); + if (lineAnnotation != null && Record.class.isAssignableFrom(cl)) { + final ArrayList<FieldSetter> fieldSetters = new ArrayList<FieldSetter>(); + + for (java.lang.reflect.Field field: cl.getFields()) { + final Field fa = field.getAnnotation(Field.class); + if (fa != null) { + final Class<?> fieldType = field.getType(); + final Class<?> innerType = fieldType.isArray() + ? fieldType.getComponentType() + : fieldType; + if (Integer.TYPE.equals(innerType)) { + fieldSetters.add(new IntFieldSetter(fa.index(), fa.added(), field)); + } else if (Long.TYPE.equals(innerType)) { + fieldSetters.add(new LongFieldSetter(fa.index(), fa.added(), field)); + } else if (String.class.equals(innerType)) { + fieldSetters.add(new StringFieldSetter(fa.index(), fa.added(), field)); + } else if (innerType.isEnum()) { + fieldSetters.add(new EnumFieldSetter(fa.index(), fa.added(), field)); + } else { + throw new RuntimeException("Unsupported field type '" + + fieldType.getName() + "' on " + + cl.getName() + "." + field.getName()); + } + } + } + // Sort by index + Collections.sort(fieldSetters, new Comparator<FieldSetter>() { + @Override + public int compare(FieldSetter a, FieldSetter b) { + return a.getIndex() - b.getIndex(); + } + }); + // Only the last one can be an array + for (int i=0; i<fieldSetters.size()-1; i++) { + if (fieldSetters.get(i).isArray()) { + throw new RuntimeException("Only the last (highest index) @Field" + + " in class " + cl.getName() + " can be an array: " + + fieldSetters.get(i).getName()); + } + } + // Add to the map + sFactories.put(lineAnnotation.tag(), new RecordFactory(lineAnnotation.tag(), + (Class<Record>)cl, fieldSetters)); + } + } + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/SpecialApp.java b/tools/powermodel/src/com/android/powermodel/SpecialApp.java new file mode 100644 index 000000000000..df1e1fbda5f6 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/SpecialApp.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 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.powermodel; + +/** + * Identifiers for well-known apps that have unique characteristics. + * + * @more + * This includes three categories: + * <ul> + * <li><b>Built-in system components</b> – These have predefined UIDs that are + * always the same. For example, the system UID is always 1000.</li> + * <li><b>Well known apps with shared UIDs</b> – These do not have predefined + * UIDs (i.e. are different on each device), but since they have shared UIDs + * with varying sets of package names (GmsCore is the canonical example), we + * have special logic to capture these into a single entity with a well defined + * key. These have the {@link #uid uid} field set to + * {@link Uid#UID_VARIES Uid.UID_VARIES}.</li> + * <li><b>Synthetic remainder app</b> – The {@link #REMAINDER REMAINDER} app doesn't + * represent a real app. It contains accounting for usage which is not attributed + * to any UID. This app has the {@link #uid uid} field set to + * {@link Uid#UID_SYNTHETIC Uid.UID_SYNTHETIC}.</li> + * </ul> + */ +public enum SpecialApp { + + /** + * Synthetic app that accounts for the remaining amount of resources used + * that is unaccounted for by apps, or overcounted because of inaccuracies + * in the model. + */ + REMAINDER(Uid.UID_SYNTHETIC), + + /** + * Synthetic app that holds system-wide numbers, for example the total amount + * of various resources used, device-wide. + */ + GLOBAL(Uid.UID_SYNTHETIC), + + SYSTEM(1000), + + GOOGLE_SERVICES(Uid.UID_VARIES); + + /** + * Constants for SpecialApps where the uid is not actually a UID. + */ + public static class Uid { + /** + * Constant to indicate that this special app does not have a fixed UID. + */ + public static final int UID_VARIES = -1; + + /** + * Constant to indicate that this special app is not actually an app with a UID. + * + * @see SpecialApp#REMAINDER + * @see SpecialApp#GLOBAL + */ + public static final int UID_SYNTHETIC = -2; + } + + /** + * The fixed UID value of this special app, or {@link #UID_VARIES} if there + * isn't one. + */ + public final int uid; + + private SpecialApp(int uid) { + this.uid = uid; + } +} diff --git a/tools/powermodel/src/com/android/powermodel/component/AudioProfile.java b/tools/powermodel/src/com/android/powermodel/component/AudioProfile.java new file mode 100644 index 000000000000..63ff3a6b09fa --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/AudioProfile.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.Arrays; + +import com.android.powermodel.ComponentProfile; +import com.android.powermodel.ParseException; + +public class AudioProfile extends ComponentProfile { + public float onMa; +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/BluetoothProfile.java b/tools/powermodel/src/com/android/powermodel/component/BluetoothProfile.java new file mode 100644 index 000000000000..8f5e7d0ae1df --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/BluetoothProfile.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.Arrays; + +import com.android.powermodel.ComponentProfile; +import com.android.powermodel.ParseException; + +public class BluetoothProfile extends ComponentProfile { + public float idleMa; + public float rxMa; + public float txMa; +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/CameraProfile.java b/tools/powermodel/src/com/android/powermodel/component/CameraProfile.java new file mode 100644 index 000000000000..8ee22d03268c --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/CameraProfile.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.Arrays; + +import com.android.powermodel.ComponentProfile; +import com.android.powermodel.ParseException; + +public class CameraProfile extends ComponentProfile { + public float onMa; +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/CpuProfile.java b/tools/powermodel/src/com/android/powermodel/component/CpuProfile.java new file mode 100644 index 000000000000..0b34fc82622a --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/CpuProfile.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.Arrays; +import java.util.HashMap; + +import com.android.powermodel.ComponentProfile; +import com.android.powermodel.ParseException; + +public class CpuProfile extends ComponentProfile { + public float suspendMa; + public float idleMa; + public float activeMa; + public Cluster[] clusters; + + public static class Cluster { + public int coreCount; + public float onMa; + public Frequency[] frequencies; + } + + public static class Frequency { + public int speedHz; + public float onMa; + } + + public static class Builder { + private float mSuspendMa; + private float mIdleMa; + private float mActiveMa; + private int[] mCoreCount; + private HashMap<Integer,Float> mClusterOnPower = new HashMap<Integer,Float>(); + private HashMap<Integer,int[]> mCoreSpeeds = new HashMap<Integer,int[]>(); + private HashMap<Integer,float[]> mCorePower = new HashMap<Integer,float[]>(); + + public Builder() { + } + + public void setSuspendMa(float value) throws ParseException { + mSuspendMa = value; + } + + public void setIdleMa(float value) throws ParseException { + mIdleMa = value; + } + + public void setActiveMa(float value) throws ParseException { + mActiveMa = value; + } + + public void setCoreCount(int[] value) throws ParseException { + mCoreCount = Arrays.copyOf(value, value.length); + } + + public void setClusterPower(int cluster, float value) throws ParseException { + mClusterOnPower.put(cluster, value); + } + + public void setCoreSpeeds(int cluster, int[] value) throws ParseException { + mCoreSpeeds.put(cluster, Arrays.copyOf(value, value.length)); + float[] power = mCorePower.get(cluster); + if (power != null && value.length != power.length) { + throw new ParseException("length of cpu.core_speeds.cluster" + cluster + + " (" + value.length + ") is different from length of" + + " cpu.core_power.cluster" + cluster + " (" + power.length + ")"); + } + if (mCoreCount != null && cluster >= mCoreCount.length) { + throw new ParseException("cluster " + cluster + + " in cpu.core_speeds.cluster" + cluster + + " is larger than the number of clusters specified in cpu.clusters.cores (" + + mCoreCount.length + ")"); + } + } + + public void setCorePower(int cluster, float[] value) throws ParseException { + mCorePower.put(cluster, Arrays.copyOf(value, value.length)); + int[] speeds = mCoreSpeeds.get(cluster); + if (speeds != null && value.length != speeds.length) { + throw new ParseException("length of cpu.core_power.cluster" + cluster + + " (" + value.length + ") is different from length of" + + " cpu.clusters.cores" + cluster + " (" + speeds.length + ")"); + } + if (mCoreCount != null && cluster >= mCoreCount.length) { + throw new ParseException("cluster " + cluster + + " in cpu.core_power.cluster" + cluster + + " is larger than the number of clusters specified in cpu.clusters.cores (" + + mCoreCount.length + ")"); + } + } + + public CpuProfile build() throws ParseException { + final CpuProfile result = new CpuProfile(); + + // Validate cluster count + + // All null or none null + // TODO + + // Same size + // TODO + + // No gaps + // TODO + + // Fill in values + result.suspendMa = mSuspendMa; + result.idleMa = mIdleMa; + result.activeMa = mActiveMa; + if (mCoreCount != null) { + result.clusters = new Cluster[mCoreCount.length]; + for (int i = 0; i < result.clusters.length; i++) { + final Cluster cluster = result.clusters[i] = new Cluster(); + cluster.coreCount = mCoreCount[i]; + cluster.onMa = mClusterOnPower.get(i); + int[] speeds = mCoreSpeeds.get(i); + float[] power = mCorePower.get(i); + cluster.frequencies = new Frequency[speeds.length]; + for (int j = 0; j < speeds.length; j++) { + final Frequency freq = cluster.frequencies[j] = new Frequency(); + freq.speedHz = speeds[j]; + freq.onMa = power[j]; + } + } + } + + return result; + } + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/FlashlightProfile.java b/tools/powermodel/src/com/android/powermodel/component/FlashlightProfile.java new file mode 100644 index 000000000000..c85f3ff236fd --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/FlashlightProfile.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.Arrays; + +import com.android.powermodel.ComponentProfile; +import com.android.powermodel.ParseException; + +public class FlashlightProfile extends ComponentProfile { + public float onMa; +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/GpsProfile.java b/tools/powermodel/src/com/android/powermodel/component/GpsProfile.java new file mode 100644 index 000000000000..83c06a7881ca --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/GpsProfile.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.Arrays; + +import com.android.powermodel.ComponentProfile; +import com.android.powermodel.ParseException; + +public class GpsProfile extends ComponentProfile { + public float onMa; + public float[] signalQualityMa; + + public static class Builder { + private float onMa; + private float[] mSignalQualityMa; + + public Builder() { + } + + public void setOnMa(float value) throws ParseException { + onMa = value; + } + + public void setSignalMa(float[] value) throws ParseException { + mSignalQualityMa = value; + } + + public GpsProfile build() throws ParseException { + GpsProfile result = new GpsProfile(); + result.onMa = onMa; + result.signalQualityMa = mSignalQualityMa == null + ? new float[0] + : Arrays.copyOf(mSignalQualityMa, mSignalQualityMa.length); + return result; + } + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemAppActivity.java b/tools/powermodel/src/com/android/powermodel/component/ModemAppActivity.java new file mode 100644 index 000000000000..cb70051f1ae6 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/ModemAppActivity.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import com.android.powermodel.ActivityReport; +import com.android.powermodel.AttributionKey; +import com.android.powermodel.Component; +import com.android.powermodel.ComponentActivity; +import com.android.powermodel.PowerProfile; +import com.android.powermodel.util.Conversion; + +/** + * Encapsulates the work done by the celluar modem on behalf of an app. + */ +public class ModemAppActivity extends ComponentActivity { + /** + * Construct a new ModemAppActivity. + */ + public ModemAppActivity(AttributionKey attribution) { + super(attribution); + } + + /** + * The number of packets received by the app. + */ + public long rxPacketCount; + + /** + * The number of packets sent by the app. + */ + public long txPacketCount; + + @Override + public ModemAppPower applyProfile(ActivityReport activityReport, PowerProfile profile) { + // Profile + final ModemProfile modemProfile = (ModemProfile)profile.getComponent(Component.MODEM); + if (modemProfile == null) { + // TODO: This is kind of a big problem... Should this throw instead? + return null; + } + + // Activity + final ModemGlobalActivity global + = (ModemGlobalActivity)activityReport.findGlobalComponent(Component.MODEM); + if (global == null) { + return null; + } + + final double averageModemPowerMa = getAverageModemPowerMa(modemProfile); + final long totalPacketCount = global.rxPacketCount + global.txPacketCount; + final long appPacketCount = this.rxPacketCount + this.txPacketCount; + + final ModemAppPower result = new ModemAppPower(); + result.attribution = this.attribution; + result.activity = this; + result.powerMah = Conversion.msToHr( + (totalPacketCount > 0 ? (appPacketCount / (double)totalPacketCount) : 0) + * global.totalActiveTimeMs + * averageModemPowerMa); + return result; + } + + static final double getAverageModemPowerMa(ModemProfile profile) { + double sumMa = profile.getRxMa(); + for (float powerAtTxLevelMa: profile.getTxMa()) { + sumMa += powerAtTxLevelMa; + } + return sumMa / (profile.getTxMa().length + 1); + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemAppPower.java b/tools/powermodel/src/com/android/powermodel/component/ModemAppPower.java new file mode 100644 index 000000000000..f5531272d0b9 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/ModemAppPower.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import com.android.powermodel.Component; +import com.android.powermodel.ComponentPower; + +public class ModemAppPower extends ComponentPower<ModemAppActivity> { +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemBatteryStatsReader.java b/tools/powermodel/src/com/android/powermodel/component/ModemBatteryStatsReader.java new file mode 100644 index 000000000000..6dbfbc24d1ef --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/ModemBatteryStatsReader.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.ArrayList; +import java.util.List; +import com.android.powermodel.AttributionKey; +import com.android.powermodel.ComponentActivity; +import com.android.powermodel.RawBatteryStats; +import com.android.powermodel.SpecialApp; + +public class ModemBatteryStatsReader { + private ModemBatteryStatsReader() { + } + + public static List<ComponentActivity> createActivities(RawBatteryStats bs) { + final List<ComponentActivity> result = new ArrayList<ComponentActivity>(); + + // The whole system + createGlobal(result, bs); + + // The apps + createApps(result, bs); + + // The synthetic "cell" app. + createRemainder(result, bs); + + return result; + } + + private static void createGlobal(List<ComponentActivity> result, RawBatteryStats bs) { + final ModemGlobalActivity global + = new ModemGlobalActivity(new AttributionKey(SpecialApp.GLOBAL)); + + final RawBatteryStats.GlobalNetwork gn = bs.getSingle(RawBatteryStats.GlobalNetwork.class); + final RawBatteryStats.Misc misc = bs.getSingle(RawBatteryStats.Misc.class); + + // Null here just means no network activity. + if (gn != null && misc != null) { + global.rxPacketCount = gn.mobileRxTotalPackets; + global.txPacketCount = gn.mobileTxTotalPackets; + + global.totalActiveTimeMs = misc.mobileRadioActiveTimeMs; + } + + result.add(global); + } + + private static void createApps(List<ComponentActivity> result, RawBatteryStats bs) { + for (AttributionKey key: bs.getApps()) { + final int uid = key.getUid(); + final RawBatteryStats.Network network + = bs.getSingle(RawBatteryStats.Network.class, uid); + + // Null here just means no network activity. + if (network != null) { + final ModemAppActivity app = new ModemAppActivity(key); + + app.rxPacketCount = network.mobileRxPackets; + app.txPacketCount = network.mobileTxPackets; + + result.add(app); + } + } + } + + private static void createRemainder(List<ComponentActivity> result, RawBatteryStats bs) { + final RawBatteryStats.SignalStrengthTime strength + = bs.getSingle(RawBatteryStats.SignalStrengthTime.class); + final RawBatteryStats.SignalScanningTime scanning + = bs.getSingle(RawBatteryStats.SignalScanningTime.class); + final RawBatteryStats.Misc misc = bs.getSingle(RawBatteryStats.Misc.class); + + if (strength != null && scanning != null && misc != null) { + final ModemRemainderActivity remainder + = new ModemRemainderActivity(new AttributionKey(SpecialApp.REMAINDER)); + + // Signal strength buckets + remainder.strengthTimeMs = strength.phoneSignalStrengthTimeMs; + + // Time spent scanning + remainder.scanningTimeMs = scanning.phoneSignalScanningTimeMs; + + // Unaccounted for active time + final long totalActiveTimeMs = misc.mobileRadioActiveTimeMs; + long appActiveTimeMs = 0; + for (RawBatteryStats.Network nw: bs.getMultiple(RawBatteryStats.Network.class)) { + appActiveTimeMs += nw.mobileRadioActiveTimeUs / 1000; + } + remainder.activeTimeMs = totalActiveTimeMs - appActiveTimeMs; + + result.add(remainder); + } + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemGlobalActivity.java b/tools/powermodel/src/com/android/powermodel/component/ModemGlobalActivity.java new file mode 100644 index 000000000000..a53b53eede2b --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/ModemGlobalActivity.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import com.android.powermodel.ActivityReport; +import com.android.powermodel.AttributionKey; +import com.android.powermodel.ComponentActivity; +import com.android.powermodel.ComponentPower; +import com.android.powermodel.PowerProfile; + +/** + * Encapsulates total work done by the modem for the device. + */ +public class ModemGlobalActivity extends ComponentActivity { + /** + * Construct a new ModemGlobalActivity. + */ + public ModemGlobalActivity(AttributionKey attribution) { + super(attribution); + } + + /** + * Returns the total number of packets received in the whole device. + */ + public long rxPacketCount; + + /** + * Returns the total number of packets sent in the whole device. + */ + public long txPacketCount; + + /** + * Returns the total time the radio was active in the whole device. + */ + public long totalActiveTimeMs; +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemProfile.java b/tools/powermodel/src/com/android/powermodel/component/ModemProfile.java new file mode 100644 index 000000000000..cda72ee205e3 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/ModemProfile.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.Arrays; + +import com.android.powermodel.ComponentProfile; +import com.android.powermodel.ParseException; + +public class ModemProfile extends ComponentProfile { + public float sleepMa; + public float idleMa; + public float scanningMa; + public float rxMa; + public float[] txMa; + + public float getSleepMa() { + return sleepMa; + } + + public float getIdleMa() { + return idleMa; + } + + public float getRxMa() { + return rxMa; + } + + public float[] getTxMa() { + return Arrays.copyOf(txMa, txMa.length); + } + + public float getScanningMa() { + return scanningMa; + } + + public static class Builder { + private float mSleepMa; + private float mIdleMa; + private float mRxMa; + private float[] mTxMa; + private float mScanningMa; + + public Builder() { + } + + public void setSleepMa(float value) throws ParseException { + mSleepMa = value; + } + + public void setIdleMa(float value) throws ParseException { + mIdleMa = value; + } + + public void setRxMa(float value) throws ParseException { + mRxMa = value; + } + + public void setTxMa(float[] value) throws ParseException { + mTxMa = Arrays.copyOf(value, value.length); + } + + public void setScanningMa(float value) throws ParseException { + mScanningMa = value; + } + + public ModemProfile build() throws ParseException { + ModemProfile result = new ModemProfile(); + result.sleepMa = mSleepMa; + result.idleMa = mIdleMa; + result.rxMa = mRxMa; + result.txMa = mTxMa == null ? new float[0] : mTxMa; + result.scanningMa = mScanningMa; + return result; + } + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemRemainderActivity.java b/tools/powermodel/src/com/android/powermodel/component/ModemRemainderActivity.java new file mode 100644 index 000000000000..0e268c21d01d --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/ModemRemainderActivity.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import com.android.powermodel.ActivityReport; +import com.android.powermodel.AttributionKey; +import com.android.powermodel.Component; +import com.android.powermodel.ComponentActivity; +import com.android.powermodel.PowerProfile; +import com.android.powermodel.util.Conversion; + +/** + * Encapsulates the work done by the remaining + */ +public class ModemRemainderActivity extends ComponentActivity { + /** + * Construct a new ModemRemainderActivity. + */ + public ModemRemainderActivity(AttributionKey attribution) { + super(attribution); + } + + /** + * Number of milliseconds spent at each of the signal strengths. + */ + public long[] strengthTimeMs; + + /** + * Number of milliseconds spent scanning for a network. + */ + public long scanningTimeMs; + + /** + * Number of milliseconds that the radio is active for reasons other + * than an app transmitting and receiving data. + */ + public long activeTimeMs; + + @Override + public ModemRemainderPower applyProfile(ActivityReport activityReport, PowerProfile profile) { + // Profile + final ModemProfile modemProfile = (ModemProfile)profile.getComponent(Component.MODEM); + if (modemProfile == null) { + return null; + } + + // Activity + final ModemRemainderPower result = new ModemRemainderPower(); + result.attribution = this.attribution; + result.activity = this; + + // strengthMah + // TODO: If the array lengths don't match... then? + result.strengthMah = new double[this.strengthTimeMs.length]; + for (int i=0; i<this.strengthTimeMs.length; i++) { + result.strengthMah[i] = Conversion.msToHr( + this.strengthTimeMs[i] * modemProfile.getTxMa()[i]); + result.powerMah += result.strengthMah[i]; + } + + // scanningMah + result.scanningMah = Conversion.msToHr(this.scanningTimeMs * modemProfile.getScanningMa()); + result.powerMah += result.scanningMah; + + // activeMah + result.activeMah = Conversion.msToHr( + this.activeTimeMs * ModemAppActivity.getAverageModemPowerMa(modemProfile)); + result.powerMah += result.activeMah; + + return result; + } +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/ModemRemainderPower.java b/tools/powermodel/src/com/android/powermodel/component/ModemRemainderPower.java new file mode 100644 index 000000000000..7f38cd342e2f --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/ModemRemainderPower.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import com.android.powermodel.Component; +import com.android.powermodel.ComponentPower; + +public class ModemRemainderPower extends ComponentPower<ModemRemainderActivity> { + + public double[] strengthMah; + + public double scanningMah; + + public double activeMah; +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/ScreenProfile.java b/tools/powermodel/src/com/android/powermodel/component/ScreenProfile.java new file mode 100644 index 000000000000..e1051c69dec6 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/ScreenProfile.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.Arrays; + +import com.android.powermodel.ComponentProfile; +import com.android.powermodel.ParseException; + +public class ScreenProfile extends ComponentProfile { + public float onMa; + public float fullMa; + public float ambientMa; +} + diff --git a/tools/powermodel/src/com/android/powermodel/component/VideoProfile.java b/tools/powermodel/src/com/android/powermodel/component/VideoProfile.java new file mode 100644 index 000000000000..515279552245 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/VideoProfile.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.Arrays; + +import com.android.powermodel.ComponentProfile; +import com.android.powermodel.ParseException; + +public class VideoProfile extends ComponentProfile { + public float onMa; +} + + diff --git a/tools/powermodel/src/com/android/powermodel/component/WifiProfile.java b/tools/powermodel/src/com/android/powermodel/component/WifiProfile.java new file mode 100644 index 000000000000..6f424bf0837d --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/component/WifiProfile.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 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.powermodel.component; + +import java.util.Arrays; + +import com.android.powermodel.ComponentProfile; +import com.android.powermodel.ParseException; + +public class WifiProfile extends ComponentProfile { + public float idleMa; + public float rxMa; + public float txMa; +} + diff --git a/tools/powermodel/src/com/android/powermodel/util/Conversion.java b/tools/powermodel/src/com/android/powermodel/util/Conversion.java new file mode 100644 index 000000000000..e556c251a1c9 --- /dev/null +++ b/tools/powermodel/src/com/android/powermodel/util/Conversion.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 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.powermodel.util; + +public class Conversion { + + /** + * Convert the the float[] to an int[]. + * <p> + * Values are rounded to the nearest integral value. Null input + * results in null output. + */ + public static int[] toIntArray(float[] value) { + if (value == null) { + return null; + } + int[] result = new int[value.length]; + for (int i=0; i<result.length; i++) { + result[i] = (int)(value[i] + 0.5f); + } + return result; + } + + public static double msToHr(double ms) { + return ms / 3600.0 / 1000.0; + } + + /** + * No public constructor. + */ + private Conversion() { + } +} diff --git a/tools/powermodel/test-resource/bs.csv b/tools/powermodel/test-resource/bs.csv new file mode 100644 index 000000000000..6e84120168ce --- /dev/null +++ b/tools/powermodel/test-resource/bs.csv @@ -0,0 +1,7 @@ +9,0,i,vers,32,177,PPR1.180326.002,PQ1A.181105.015 +9,0,i,uid,10139,com.google.android.gm +9,0,l,gn,108060756,17293456,4896592,3290614,97840,72941,6903,8107,390,105 +9,0,l,m,2590630,0,384554,3943868,5113727,265,2565483,0,16,0,0,0,0,192,25331,3472068,17,3543323,14,614050,0 +9,10139,l,nt,13688501,534571,13842,7792,9925,5577,30,67,190051799,27,0,0,5,3,126020,42343,13842,7792,207,167,30,67 +9,0,l,sgt,3066958,0,34678,1643364,7045084 +9,0,l,sst,2443805 diff --git a/tools/powermodel/test-resource/power_profile.xml b/tools/powermodel/test-resource/power_profile.xml new file mode 100644 index 000000000000..8e388eadc608 --- /dev/null +++ b/tools/powermodel/test-resource/power_profile.xml @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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. +--> + +<!-- Test power profile that parses correctly. --> +<device> + <item name="battery.capacity">2915</item> + + <!-- Number of cores each CPU cluster contains --> + <array name="cpu.clusters.cores"> + <value>4</value> + <value>2</value> + </array> + + <!-- Power consumption when CPU is suspended --> + <item name="cpu.suspend">1.3</item> + + <!-- Additional power consumption when CPU is in a kernel idle loop --> + <item name="cpu.idle">3.9</item> + + <!-- Additional power consumption by CPU excluding cluster and core when + running --> + <item name="cpu.active">18.33</item> + + <!-- Additional power consumption by CPU cluster0 itself when running + excluding cores in it --> + <item name="cpu.cluster_power.cluster0">2.41</item> + + <!-- Additional power consumption by CPU cluster1 itself when running + excluding cores in it --> + <item name="cpu.cluster_power.cluster1">5.29</item> + + <!-- Different CPU speeds as reported in + /sys/devices/system/cpu/cpu0/cpufreq/stats/scaling_available_frequencies --> + <array name="cpu.core_speeds.cluster0"> + <value>100000</value> + <value>303200</value> + <value>380000</value> + <value>476000</value> + <value>552800</value> + <value>648800</value> + <value>725600</value> + <value>802400</value> + <value>879200</value> + </array> + + <!-- Different CPU speeds as reported in + /sys/devices/system/cpu/cpu4/cpufreq/stats/scaling_available_frequencies --> + <array name="cpu.core_speeds.cluster1"> + <value>825600</value> + <value>902400</value> + <value>979200</value> + <value>1056000</value> + <value>1209600</value> + <value>1286400</value> + <value>1363200</value> + </array> + + <!-- Additional power used by a CPU core from cluster 0 when running at + different speeds, excluding cluster and active cost --> + <array name="cpu.core_power.cluster0"> + <value>0.29</value> + <value>0.63</value> + <value>1.23</value> + <value>1.24</value> + <value>2.47</value> + <value>2.54</value> + <value>3.60</value> + <value>3.64</value> + <value>4.42</value> + </array> + + <!-- Additional power used by a CPU core from cluster 1 when running at + different speeds, excluding cluster and active cost --> + <array name="cpu.core_power.cluster1"> + <value>28.98</value> + <value>31.40</value> + <value>33.33</value> + <value>40.12</value> + <value>44.10</value> + <value>90.14</value> + <value>100</value> + </array> + + <!-- Additional power used when screen is ambient mode --> + <item name="ambient.on">12</item> + + <!-- Additional power used when screen is turned on at minimum brightness --> + <item name="screen.on">102.4</item> + <!-- Additional power used when screen is at maximum brightness, compared to + screen at minimum brightness --> + <item name="screen.full">1234</item> + + <!-- Average power used by the camera flash module when on --> + <item name="camera.flashlight">1233.47</item> + + <!-- Average power use by the camera subsystem for a typical camera + application. Intended as a rough estimate for an application running a + preview and capturing approximately 10 full-resolution pictures per + minute. --> + <item name="camera.avg">941</item> + + <!-- Additional power used when video is playing --> + <item name="video">123</item> + + <!-- Additional power used when audio is playing --> + <item name="audio">12</item> + + <!-- Cellular modem related values.--> + <item name="modem.controller.sleep">1</item> + <item name="modem.controller.idle">44</item> + <item name="modem.controller.rx">11</item> + <array name="modem.controller.tx"> <!-- Strength 0 to 4 --> + <value>16</value> + <value>19</value> + <value>22</value> + <value>73</value> + <value>132</value> + </array> + <item name="modem.controller.voltage">1400</item> + <item name="radio.scanning">12</item> + + <!-- GPS related values.--> + <item name="gps.on">1</item> + <array name="gps.signalqualitybased"> <!-- Strength 0 to 1 --> + <value>88</value> + <value>07</value> + </array> + <item name="gps.voltage">1500</item> + + <!-- Idle Receive current for wifi radio in mA.--> + <item name="wifi.controller.idle">2</item> + + <!-- Rx current for wifi radio in mA.--> + <item name="wifi.controller.rx">123</item> + + <!-- Tx current for wifi radio in mA--> + <item name="wifi.controller.tx">333</item> + + <!-- Operating volatage for wifi radio in mV.--> + <item name="wifi.controller.voltage">3700</item> + + <!-- Idle current for bluetooth in mA.--> + <item name="bluetooth.controller.idle">0.02</item> + + <!-- Rx current for bluetooth in mA.--> + <item name="bluetooth.controller.rx">3</item> + + <!-- Tx current for bluetooth in mA--> + <item name="bluetooth.controller.tx">5</item> + + <!-- Operating voltage for bluetooth in mV.--> + <item name="bluetooth.controller.voltage">3300</item> + +</device> + + diff --git a/tools/powermodel/test/com/android/powermodel/BatteryStatsReaderTest.java b/tools/powermodel/test/com/android/powermodel/BatteryStatsReaderTest.java new file mode 100644 index 000000000000..e7b2c3746c85 --- /dev/null +++ b/tools/powermodel/test/com/android/powermodel/BatteryStatsReaderTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; +import org.junit.Test; +import org.junit.Assert; + +import com.android.powermodel.component.ModemAppActivity; +import com.android.powermodel.component.ModemGlobalActivity; +import com.android.powermodel.component.ModemRemainderActivity; + +/** + * Tests {@link BatteryStatsReader}. + */ +public class BatteryStatsReaderTest { + private static InputStream loadCsvStream() { + return BatteryStatsReaderTest.class.getResourceAsStream("/bs.csv"); + } + + @Test public void testModemGlobal() throws Exception { + final ActivityReport report = BatteryStatsReader.parse(loadCsvStream()); + + final AppActivity global = report.findApp(SpecialApp.GLOBAL); + Assert.assertNotNull(global); + + final ModemGlobalActivity modem + = (ModemGlobalActivity)global.getComponentActivity(Component.MODEM); + Assert.assertNotNull(modem); + Assert.assertEquals(97840, modem.rxPacketCount); + Assert.assertEquals(72941, modem.txPacketCount); + Assert.assertEquals(5113727, modem.totalActiveTimeMs); + } + + @Test public void testModemApp() throws Exception { + final ActivityReport report = BatteryStatsReader.parse(loadCsvStream()); + + final List<AppActivity> gmailList = report.findApp("com.google.android.gm"); + Assert.assertEquals(1, gmailList.size()); + final AppActivity gmail = gmailList.get(0); + + final ModemAppActivity modem + = (ModemAppActivity)gmail.getComponentActivity(Component.MODEM); + Assert.assertNotNull(modem); + Assert.assertEquals(9925, modem.rxPacketCount); + Assert.assertEquals(5577, modem.txPacketCount); + } + + @Test public void testModemRemainder() throws Exception { + final ActivityReport report = BatteryStatsReader.parse(loadCsvStream()); + + final AppActivity remainder = report.findApp(SpecialApp.REMAINDER); + Assert.assertNotNull(remainder); + + final ModemRemainderActivity modem + = (ModemRemainderActivity)remainder.getComponentActivity(Component.MODEM); + Assert.assertNotNull(modem); + Assert.assertArrayEquals(new long[] { 3066958, 0, 34678, 1643364, 7045084 }, + modem.strengthTimeMs); + Assert.assertEquals(2443805, modem.scanningTimeMs); + Assert.assertEquals(4923676, modem.activeTimeMs); + } +} diff --git a/tools/powermodel/test/com/android/powermodel/CsvParserTest.java b/tools/powermodel/test/com/android/powermodel/CsvParserTest.java new file mode 100644 index 000000000000..55dde412b78e --- /dev/null +++ b/tools/powermodel/test/com/android/powermodel/CsvParserTest.java @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests {@link PowerProfile} + */ +public class CsvParserTest { + + class LineCollector implements CsvParser.LineProcessor { + ArrayList<ArrayList<String>> results = new ArrayList<ArrayList<String>>(); + + @Override + public void onLine(int lineNumber, ArrayList<String> fields) { + System.out.println(lineNumber); + for (String str: fields) { + System.out.println("-->" + str + "<--"); + } + results.add(fields); + } + } + + private void assertEquals(String[][] expected, ArrayList<ArrayList<String>> results) { + final String[][] resultArray = new String[results.size()][]; + for (int i=0; i<results.size(); i++) { + final ArrayList<String> list = results.get(i); + resultArray[i] = list.toArray(new String[list.size()]); + } + Assert.assertArrayEquals(expected, resultArray); + } + + private String makeString(int length) { + final StringBuilder str = new StringBuilder(); + for (int i=0; i<length; i++) { + str.append('a'); + } + return str.toString(); + } + + @Test public void testEmpty() throws Exception { + final String text = ""; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + }, collector.results); + } + + @Test public void testOnlyNewline() throws Exception { + final String text = "\n"; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + }, collector.results); + } + + @Test public void testTwoLines() throws Exception { + final String text = "one,twoo,3\nfour,5,six\n"; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { "one", "twoo", "3", }, + { "four", "5", "six", }, + }, collector.results); + } + + + @Test public void testEscapedEmpty() throws Exception { + final String text = "\"\",\"\",\"\"\n"; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { "", "", "", }, + }, collector.results); + } + + @Test public void testEscapedText() throws Exception { + final String text = "\"one\",\"twoo\",\"3\"\n"; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { "one", "twoo", "3", }, + }, collector.results); + } + + @Test public void testEscapedQuotes() throws Exception { + final String text = "\"\"\"\",\"\"\"\"\"\",\"\"\"\"\n"; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { "\"", "\"\"", "\"", }, + }, collector.results); + } + + @Test public void testEscapedCommas() throws Exception { + final String text = "\",\",\",\",\",\"\n"; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { ",", ",", ",", }, + }, collector.results); + } + + @Test public void testEscapedQuotesAndCommas() throws Exception { + final String text = "\"\"\",\",\"\"\",\",\"\"\",\"\n"; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { "\",", "\",", "\",", }, + }, collector.results); + } + + @Test public void testNoNewline() throws Exception { + final String text = "a,b,c"; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { "a", "b", "c", } + }, collector.results); + } + + @Test public void testNoNewlineWithCommas() throws Exception { + final String text = "a,b,,"; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { "a", "b", "", "" } + }, collector.results); + } + + @Test public void testNoNewlineWithQuote() throws Exception { + final String text = "a,b,\",\""; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { "a", "b", "," } + }, collector.results); + } + + @Test public void testNoCommas() throws Exception { + final String text = "aasdfadfadfad"; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { "aasdfadfadfad", } + }, collector.results); + } + + @Test public void testMaxLength() throws Exception { + final String text = makeString(CsvParser.MAX_FIELD_SIZE); + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { text, } + }, collector.results); + } + + @Test public void testMaxLengthTwice() throws Exception { + String big = makeString(CsvParser.MAX_FIELD_SIZE); + final String text = big + "," + big; + System.out.println("Test: [" + text + "]"); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { big, big, } + }, collector.results); + } + + @Test public void testTooLong() throws Exception { + final String text = makeString(CsvParser.MAX_FIELD_SIZE+1); + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + try { + CsvParser.parse(is, collector); + throw new RuntimeException("Expected CsvParser.parse to throw ParseException"); + } catch (ParseException ex) { + // good + } + } + + @Test public void testBufferBoundary() throws Exception { + final String big = makeString(CsvParser.MAX_FIELD_SIZE-3); + final String text = big + ",b,c,d,e,f,g"; + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { big, "b", "c", "d", "e", "f", "g", } + }, collector.results); + } + + @Test public void testBufferBoundaryEmpty() throws Exception { + final String big = makeString(CsvParser.MAX_FIELD_SIZE-3); + final String text = big + ",,,,,,"; + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { big, "", "", "", "", "", "", } + }, collector.results); + } + + // Checks that the escaping and sawQuote behavior is correct at the buffer boundary + @Test public void testBufferBoundaryEscapingEven() throws Exception { + final String big = makeString(CsvParser.MAX_FIELD_SIZE-2); + final String text = big + ",\"\"\"\"\"\"\"\"\"\"\"\"," + big; + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { big, "\"\"\"\"\"", big } + }, collector.results); + } + + // Checks that the escaping and sawQuote behavior is correct at the buffer boundary + @Test public void testBufferBoundaryEscapingOdd() throws Exception { + final String big = makeString(CsvParser.MAX_FIELD_SIZE-3); + final String text = big + ",\"\"\"\"\"\"\"\"\"\"\"\"," + big; + final InputStream is = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); + LineCollector collector = new LineCollector(); + + CsvParser.parse(is, collector); + + assertEquals(new String[][] { + { big, "\"\"\"\"\"", big } + }, collector.results); + } + +} diff --git a/tools/powermodel/test/com/android/powermodel/PowerProfileTest.java b/tools/powermodel/test/com/android/powermodel/PowerProfileTest.java new file mode 100644 index 000000000000..ab458311a98e --- /dev/null +++ b/tools/powermodel/test/com/android/powermodel/PowerProfileTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.io.InputStream; + +import com.android.powermodel.component.CpuProfile; +import com.android.powermodel.component.AudioProfile; +import com.android.powermodel.component.BluetoothProfile; +import com.android.powermodel.component.CameraProfile; +import com.android.powermodel.component.FlashlightProfile; +import com.android.powermodel.component.GpsProfile; +import com.android.powermodel.component.ModemProfile; +import com.android.powermodel.component.ScreenProfile; +import com.android.powermodel.component.VideoProfile; +import com.android.powermodel.component.WifiProfile; +import org.junit.Assert; +import org.junit.Test; + +/* + * Additional tests needed: + * - CPU clusters with mismatching counts of speeds and coefficients + * - Extra fields + * - Name listed twice + */ + +/** + * Tests {@link PowerProfile} + */ +public class PowerProfileTest { + private static final float EPSILON = 0.00001f; + + private static InputStream loadPowerProfileStream() { + return PowerProfileTest.class.getResourceAsStream("/power_profile.xml"); + } + + @Test public void testReadGood() throws Exception { + final InputStream is = loadPowerProfileStream(); + + final PowerProfile profile = PowerProfile.parse(is); + + // Audio + final AudioProfile audio = (AudioProfile)profile.getComponent(Component.AUDIO); + Assert.assertEquals(12.0f, audio.onMa, EPSILON); + + // Bluetooth + final BluetoothProfile bluetooth + = (BluetoothProfile)profile.getComponent(Component.BLUETOOTH); + Assert.assertEquals(0.02f, bluetooth.idleMa, EPSILON); + Assert.assertEquals(3.0f, bluetooth.rxMa, EPSILON); + Assert.assertEquals(5.0f, bluetooth.txMa, EPSILON); + + // Camera + final CameraProfile camera = (CameraProfile)profile.getComponent(Component.CAMERA); + Assert.assertEquals(941.0f, camera.onMa, EPSILON); + + // CPU + final CpuProfile cpu = (CpuProfile)profile.getComponent(Component.CPU); + Assert.assertEquals(1.3f, cpu.suspendMa, EPSILON); + Assert.assertEquals(3.9f, cpu.idleMa, EPSILON); + Assert.assertEquals(18.33f, cpu.activeMa, EPSILON); + Assert.assertEquals(2, cpu.clusters.length); + // Cluster 0 + Assert.assertEquals(4, cpu.clusters[0].coreCount); + Assert.assertEquals(2.41f, cpu.clusters[0].onMa, EPSILON); + Assert.assertEquals(9, cpu.clusters[0].frequencies.length, EPSILON); + Assert.assertEquals(100000, cpu.clusters[0].frequencies[0].speedHz); + Assert.assertEquals(0.29f, cpu.clusters[0].frequencies[0].onMa, EPSILON); + Assert.assertEquals(303200, cpu.clusters[0].frequencies[1].speedHz); + Assert.assertEquals(0.63f, cpu.clusters[0].frequencies[1].onMa, EPSILON); + Assert.assertEquals(380000, cpu.clusters[0].frequencies[2].speedHz); + Assert.assertEquals(1.23f, cpu.clusters[0].frequencies[2].onMa, EPSILON); + Assert.assertEquals(476000, cpu.clusters[0].frequencies[3].speedHz); + Assert.assertEquals(1.24f, cpu.clusters[0].frequencies[3].onMa, EPSILON); + Assert.assertEquals(552800, cpu.clusters[0].frequencies[4].speedHz); + Assert.assertEquals(2.47f, cpu.clusters[0].frequencies[4].onMa, EPSILON); + Assert.assertEquals(648800, cpu.clusters[0].frequencies[5].speedHz); + Assert.assertEquals(2.54f, cpu.clusters[0].frequencies[5].onMa, EPSILON); + Assert.assertEquals(725600, cpu.clusters[0].frequencies[6].speedHz); + Assert.assertEquals(3.60f, cpu.clusters[0].frequencies[6].onMa, EPSILON); + Assert.assertEquals(802400, cpu.clusters[0].frequencies[7].speedHz); + Assert.assertEquals(3.64f, cpu.clusters[0].frequencies[7].onMa, EPSILON); + Assert.assertEquals(879200, cpu.clusters[0].frequencies[8].speedHz); + Assert.assertEquals(4.42f, cpu.clusters[0].frequencies[8].onMa, EPSILON); + // Cluster 1 + Assert.assertEquals(2, cpu.clusters[1].coreCount); + Assert.assertEquals(5.29f, cpu.clusters[1].onMa, EPSILON); + Assert.assertEquals(7, cpu.clusters[1].frequencies.length, EPSILON); + Assert.assertEquals(825600, cpu.clusters[1].frequencies[0].speedHz); + Assert.assertEquals(28.98f, cpu.clusters[1].frequencies[0].onMa, EPSILON); + Assert.assertEquals(902400, cpu.clusters[1].frequencies[1].speedHz); + Assert.assertEquals(31.40f, cpu.clusters[1].frequencies[1].onMa, EPSILON); + Assert.assertEquals(979200, cpu.clusters[1].frequencies[2].speedHz); + Assert.assertEquals(33.33f, cpu.clusters[1].frequencies[2].onMa, EPSILON); + Assert.assertEquals(1056000, cpu.clusters[1].frequencies[3].speedHz); + Assert.assertEquals(40.12f, cpu.clusters[1].frequencies[3].onMa, EPSILON); + Assert.assertEquals(1209600, cpu.clusters[1].frequencies[4].speedHz); + Assert.assertEquals(44.10f, cpu.clusters[1].frequencies[4].onMa, EPSILON); + Assert.assertEquals(1286400, cpu.clusters[1].frequencies[5].speedHz); + Assert.assertEquals(90.14f, cpu.clusters[1].frequencies[5].onMa, EPSILON); + Assert.assertEquals(1363200, cpu.clusters[1].frequencies[6].speedHz); + Assert.assertEquals(100f, cpu.clusters[1].frequencies[6].onMa, EPSILON); + + // Flashlight + final FlashlightProfile flashlight + = (FlashlightProfile)profile.getComponent(Component.FLASHLIGHT); + Assert.assertEquals(1233.47f, flashlight.onMa, EPSILON); + + // GPS + final GpsProfile gps = (GpsProfile)profile.getComponent(Component.GPS); + Assert.assertEquals(1.0f, gps.onMa, EPSILON); + Assert.assertEquals(2, gps.signalQualityMa.length); + Assert.assertEquals(88.0f, gps.signalQualityMa[0], EPSILON); + Assert.assertEquals(7.0f, gps.signalQualityMa[1], EPSILON); + + // Modem + final ModemProfile modem = (ModemProfile)profile.getComponent(Component.MODEM); + Assert.assertEquals(1.0f, modem.sleepMa, EPSILON); + Assert.assertEquals(44.0f, modem.idleMa, EPSILON); + Assert.assertEquals(12.0f, modem.scanningMa, EPSILON); + Assert.assertEquals(11.0f, modem.rxMa, EPSILON); + Assert.assertEquals(5, modem.txMa.length); + Assert.assertEquals(16.0f, modem.txMa[0], EPSILON); + Assert.assertEquals(19.0f, modem.txMa[1], EPSILON); + Assert.assertEquals(22.0f, modem.txMa[2], EPSILON); + Assert.assertEquals(73.0f, modem.txMa[3], EPSILON); + Assert.assertEquals(132.0f, modem.txMa[4], EPSILON); + + // Screen + final ScreenProfile screen = (ScreenProfile)profile.getComponent(Component.SCREEN); + Assert.assertEquals(102.4f, screen.onMa, EPSILON); + Assert.assertEquals(1234.0f, screen.fullMa, EPSILON); + Assert.assertEquals(12.0f, screen.ambientMa, EPSILON); + + // Video + final VideoProfile video = (VideoProfile)profile.getComponent(Component.VIDEO); + Assert.assertEquals(123.0f, video.onMa, EPSILON); + + // Wifi + final WifiProfile wifi = (WifiProfile)profile.getComponent(Component.WIFI); + Assert.assertEquals(2.0f, wifi.idleMa, EPSILON); + Assert.assertEquals(123.0f, wifi.rxMa, EPSILON); + Assert.assertEquals(333.0f, wifi.txMa, EPSILON); + } +} diff --git a/tools/powermodel/test/com/android/powermodel/PowerReportTest.java b/tools/powermodel/test/com/android/powermodel/PowerReportTest.java new file mode 100644 index 000000000000..1a61737a4b2f --- /dev/null +++ b/tools/powermodel/test/com/android/powermodel/PowerReportTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; +import org.junit.Test; +import org.junit.Assert; + +import com.android.powermodel.component.ModemAppPower; +import com.android.powermodel.component.ModemRemainderPower; + +/** + * Tests {@link PowerReport}. + */ +public class PowerReportTest { + private static final double EPSILON = 0.001; + private static final double MS_PER_HR = 3600000.0; + + private static final double AVERAGE_MODEM_POWER = ((11+16+19+22+73+132) / 6.0); + private static final double GMAIL_MODEM_MAH = ((9925+5577) / (double)(97840+72941)) + * 5113727 * AVERAGE_MODEM_POWER * (1.0 / 3600 / 1000); + private static final double GMAIL_MAH + = GMAIL_MODEM_MAH; + + private static final double REMAINDER_MODEM_MAH + = (1.0 / 3600 / 1000) + * ((3066958 * 16) + (0 * 19) + (34678 * 22) + (1643364 * 73) + (7045084 * 132) + + (2443805 * 12) + + (4923676 * AVERAGE_MODEM_POWER)); + private static final double REMAINDER_MAH + = REMAINDER_MODEM_MAH; + + private static final double TOTAL_MAH + = GMAIL_MAH + + REMAINDER_MAH; + + private static InputStream loadPowerProfileStream() { + return PowerProfileTest.class.getResourceAsStream("/power_profile.xml"); + } + + private static InputStream loadCsvStream() { + return BatteryStatsReaderTest.class.getResourceAsStream("/bs.csv"); + } + + private static PowerReport loadPowerReport() throws Exception { + final PowerProfile profile = PowerProfile.parse(loadPowerProfileStream()); + final ActivityReport activity = BatteryStatsReader.parse(loadCsvStream()); + return PowerReport.createReport(profile, activity); + } + + @Test public void testModemApp() throws Exception { + final PowerReport report = loadPowerReport(); + + final List<AppPower> gmailList = report.findApp("com.google.android.gm"); + Assert.assertEquals(1, gmailList.size()); + final AppPower gmail = gmailList.get(0); + + final ModemAppPower modem = (ModemAppPower)gmail.getComponentPower(Component.MODEM); + Assert.assertNotNull(modem); + Assert.assertEquals(GMAIL_MODEM_MAH, modem.powerMah, EPSILON); + } + + @Test public void testModemRemainder() throws Exception { + final PowerReport report = loadPowerReport(); + + final AppPower remainder = report.findApp(SpecialApp.REMAINDER); + Assert.assertNotNull(remainder); + + final ModemRemainderPower modem + = (ModemRemainderPower)remainder.getComponentPower(Component.MODEM); + Assert.assertNotNull(modem); + + Assert.assertArrayEquals(new double[] { + 3066958 * 16.0 / MS_PER_HR, + 0 * 19.0 / MS_PER_HR, + 34678 * 22.0 / MS_PER_HR, + 1643364 * 73.0 / MS_PER_HR, + 7045084 * 132.0 / MS_PER_HR }, + modem.strengthMah, EPSILON); + Assert.assertEquals(2443805 * 12 / MS_PER_HR, modem.scanningMah, EPSILON); + Assert.assertEquals(4923676 * AVERAGE_MODEM_POWER / MS_PER_HR, modem.activeMah, EPSILON); + + Assert.assertEquals(REMAINDER_MODEM_MAH, modem.powerMah, EPSILON); + } + + @Test public void testAppTotal() throws Exception { + final PowerReport report = loadPowerReport(); + + final List<AppPower> gmailList = report.findApp("com.google.android.gm"); + Assert.assertEquals(1, gmailList.size()); + final AppPower gmail = gmailList.get(0); + + Assert.assertEquals(GMAIL_MAH, gmail.getAppPowerMah(), EPSILON); + } + + @Test public void testRemainderTotal() throws Exception { + final PowerReport report = loadPowerReport(); + + final AppPower remainder = report.findApp(SpecialApp.REMAINDER); + Assert.assertNotNull(remainder); + + Assert.assertEquals(REMAINDER_MAH, remainder.getAppPowerMah(), EPSILON); + } + + @Test public void testTotal() throws Exception { + final PowerReport report = loadPowerReport(); + + Assert.assertEquals(TOTAL_MAH, report.getTotalPowerMah(), EPSILON); + } +} + diff --git a/tools/powermodel/test/com/android/powermodel/RawBatteryStatsTest.java b/tools/powermodel/test/com/android/powermodel/RawBatteryStatsTest.java new file mode 100644 index 000000000000..fbcac41a9e1c --- /dev/null +++ b/tools/powermodel/test/com/android/powermodel/RawBatteryStatsTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2018 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.powermodel; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; +import org.junit.Test; +import org.junit.Assert; + +/** + * Tests {@link RawBatteryStats}. + */ +public class RawBatteryStatsTest { + private static final int BS_VERSION = 32; + + private static InputStream makeCsv(String... lines) { + return makeCsv(BS_VERSION, lines); + } + + private static InputStream makeCsv(int version, String... lines) { + final StringBuilder result = new StringBuilder("9,0,i,vers,"); + result.append(version); + result.append(",177,PPR1.180326.002,PQ1A.181105.015\n"); + for (String line: lines) { + result.append(line); + result.append('\n'); + } + return new ByteArrayInputStream(result.toString().getBytes(StandardCharsets.UTF_8)); + } + + @Test public void testVersion() throws Exception { + final InputStream is = makeCsv(); + + final RawBatteryStats bs = RawBatteryStats.parse(is); + final List<RawBatteryStats.Record> records = bs.getRecords(); + final RawBatteryStats.Version line = (RawBatteryStats.Version)records.get(0); + + Assert.assertEquals(0, bs.getWarnings().size()); + Assert.assertEquals(true, line.complete); + + Assert.assertEquals(9, line.lineVersion); + Assert.assertEquals(0, line.uid); + Assert.assertEquals(RawBatteryStats.Category.INFO, line.category); + Assert.assertEquals("vers", line.lineType); + + Assert.assertEquals(BS_VERSION, line.dumpsysVersion); + Assert.assertEquals(177, line.parcelVersion); + Assert.assertEquals("PPR1.180326.002", line.startPlatformVersion); + Assert.assertEquals("PQ1A.181105.015", line.endPlatformVersion); + } + + @Test public void testUid() throws Exception { + final InputStream is = makeCsv("9,0,i,uid,1000,com.example.app"); + + final RawBatteryStats bs = RawBatteryStats.parse(is); + final List<RawBatteryStats.Record> records = bs.getRecords(); + final RawBatteryStats.Uid line = (RawBatteryStats.Uid)records.get(1); + + Assert.assertEquals(1000, line.uidKey); + Assert.assertEquals("com.example.app", line.pkg); + } + + @Test public void testVarargs() throws Exception { + final InputStream is = makeCsv("9,0,i,gmcd,1,2,3,4,5,6,7"); + + final RawBatteryStats bs = RawBatteryStats.parse(is); + final List<RawBatteryStats.Record> records = bs.getRecords(); + final RawBatteryStats.GlobalModemController line + = (RawBatteryStats.GlobalModemController)records.get(1); + + Assert.assertEquals(1, line.idleMs); + Assert.assertEquals(2, line.rxTimeMs); + Assert.assertEquals(3, line.powerMaMs); + Assert.assertEquals(4, line.txTimeMs.length); + Assert.assertEquals(4, line.txTimeMs[0]); + Assert.assertEquals(5, line.txTimeMs[1]); + Assert.assertEquals(6, line.txTimeMs[2]); + Assert.assertEquals(7, line.txTimeMs[3]); + } +} diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index 8585ae9f3f61..88b7e2e9de21 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -1128,7 +1128,10 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp hadStringOrChain = true; fprintf(out, " jbyte* jbyte_array%d;\n", argIndex); fprintf(out, " const char* str%d;\n", argIndex); - fprintf(out, " if (arg%d != NULL) {\n", argIndex); + fprintf(out, + " if (arg%d != NULL && env->GetArrayLength(arg%d) > " + "0) {\n", + argIndex, argIndex); fprintf(out, " jbyte_array%d = " "env->GetByteArrayElements(arg%d, NULL);\n", diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 3ec8a4155292..364d5084fbc9 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -58,7 +58,7 @@ interface IWifiManager */ oneway void requestActivityInfo(in ResultReceiver result); - ParceledListSlice getConfiguredNetworks(); + ParceledListSlice getConfiguredNetworks(String packageName); ParceledListSlice getPrivilegedConfiguredNetworks(); @@ -90,11 +90,11 @@ interface IWifiManager List<ScanResult> getScanResults(String callingPackage); - void disconnect(String packageName); + boolean disconnect(String packageName); - void reconnect(String packageName); + boolean reconnect(String packageName); - void reassociate(String packageName); + boolean reassociate(String packageName); WifiInfo getConnectionInfo(String callingPackage); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 7aff03c00dd3..8dd6c771a924 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1067,7 +1067,7 @@ public class WifiManager { public List<WifiConfiguration> getConfiguredNetworks() { try { ParceledListSlice<WifiConfiguration> parceledList = - mService.getConfiguredNetworks(); + mService.getConfiguredNetworks(mContext.getOpPackageName()); if (parceledList == null) { return Collections.emptyList(); } @@ -1761,8 +1761,7 @@ public class WifiManager { @Deprecated public boolean disconnect() { try { - mService.disconnect(mContext.getOpPackageName()); - return true; + return mService.disconnect(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1786,8 +1785,7 @@ public class WifiManager { @Deprecated public boolean reconnect() { try { - mService.reconnect(mContext.getOpPackageName()); - return true; + return mService.reconnect(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1811,8 +1809,7 @@ public class WifiManager { @Deprecated public boolean reassociate() { try { - mService.reassociate(mContext.getOpPackageName()); - return true; + return mService.reassociate(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2132,14 +2129,14 @@ public class WifiManager { * existing networks. You should assume the network IDs can be different * after calling this method. * - * @return {@code false} Will always return true. + * @return {@code false}. * @deprecated There is no need to call this method - * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)} * and {@link #removeNetwork(int)} already persist the configurations automatically. */ @Deprecated public boolean saveConfiguration() { - return true; + return false; } /** @@ -3406,6 +3403,11 @@ public class WifiManager { * @hide */ @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD, + android.Manifest.permission.NETWORK_STACK + }) public void connect(WifiConfiguration config, ActionListener listener) { if (config == null) throw new IllegalArgumentException("config cannot be null"); // Use INVALID_NETWORK_ID for arg1 when passing a config object @@ -3426,7 +3428,12 @@ public class WifiManager { * initialized again * @hide */ - @UnsupportedAppUsage + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD, + android.Manifest.permission.NETWORK_STACK + }) public void connect(int networkId, ActionListener listener) { if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative"); getChannel().sendMessage(CONNECT_NETWORK, networkId, putListener(listener)); @@ -3452,7 +3459,12 @@ public class WifiManager { * initialized again * @hide */ - @UnsupportedAppUsage + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD, + android.Manifest.permission.NETWORK_STACK + }) public void save(WifiConfiguration config, ActionListener listener) { if (config == null) throw new IllegalArgumentException("config cannot be null"); getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config); @@ -3471,7 +3483,12 @@ public class WifiManager { * initialized again * @hide */ - @UnsupportedAppUsage + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD, + android.Manifest.permission.NETWORK_STACK + }) public void forget(int netId, ActionListener listener) { if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative"); getChannel().sendMessage(FORGET_NETWORK, netId, putListener(listener)); @@ -3486,7 +3503,12 @@ public class WifiManager { * initialized again * @hide */ - @UnsupportedAppUsage + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD, + android.Manifest.permission.NETWORK_STACK + }) public void disable(int netId, ActionListener listener) { if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative"); getChannel().sendMessage(DISABLE_NETWORK, netId, putListener(listener)); @@ -3498,6 +3520,12 @@ public class WifiManager { * @param SSID, in the format of WifiConfiguration's SSID. * @hide */ + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD, + android.Manifest.permission.NETWORK_STACK + }) public void disableEphemeralNetwork(String SSID) { if (SSID == null) throw new IllegalArgumentException("SSID cannot be null"); try { diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java index 529548f1d2b8..6622a2571870 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -184,6 +184,9 @@ public class WifiScanner { public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings"; /** {@hide} */ public static final String SCAN_PARAMS_WORK_SOURCE_KEY = "WorkSource"; + /** {@hide} */ + public static final String REQUEST_PACKAGE_NAME_KEY = "PackageName"; + /** * scan configuration parameters to be sent to {@link #startBackgroundScan} */ @@ -798,6 +801,7 @@ public class WifiScanner { Bundle scanParams = new Bundle(); scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings); scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource); + scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName()); mAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams); } @@ -812,8 +816,11 @@ public class WifiScanner { int key = removeListener(listener); if (key == INVALID_KEY) return; validateChannel(); - mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key); + Bundle scanParams = new Bundle(); + scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName()); + mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key, scanParams); } + /** * reports currently available scan results on appropriate listeners * @return true if all scan results were reported correctly @@ -821,7 +828,10 @@ public class WifiScanner { @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean getScanResults() { validateChannel(); - Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0); + Bundle scanParams = new Bundle(); + scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName()); + Message reply = + mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0, 0, scanParams); return reply.what == CMD_OP_SUCCEEDED; } @@ -856,6 +866,7 @@ public class WifiScanner { Bundle scanParams = new Bundle(); scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings); scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource); + scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName()); mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams); } @@ -870,7 +881,9 @@ public class WifiScanner { int key = removeListener(listener); if (key == INVALID_KEY) return; validateChannel(); - mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key); + Bundle scanParams = new Bundle(); + scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName()); + mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key, scanParams); } /** @@ -879,7 +892,10 @@ public class WifiScanner { */ public List<ScanResult> getSingleScanResults() { validateChannel(); - Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SINGLE_SCAN_RESULTS, 0); + Bundle scanParams = new Bundle(); + scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName()); + Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SINGLE_SCAN_RESULTS, 0, 0, + scanParams); if (reply.what == WifiScanner.CMD_OP_SUCCEEDED) { return Arrays.asList(((ParcelableScanResults) reply.obj).getResults()); } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java index 67720961f8ed..6631fa806fc6 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java @@ -16,10 +16,16 @@ package android.net.wifi.p2p; +import android.annotation.IntDef; import android.annotation.UnsupportedAppUsage; +import android.net.MacAddress; import android.net.wifi.WpsInfo; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * A class representing a Wi-Fi P2p configuration for setting up a connection @@ -38,12 +44,46 @@ public class WifiP2pConfig implements Parcelable { */ public WpsInfo wps; + /** + * The network name of a group, should be configured by helper method + */ + /** @hide */ + public String networkName = ""; + + /** + * The passphrase of a group, should be configured by helper method + */ + /** @hide */ + public String passphrase = ""; + + /** + * The required band for Group Owner + */ + /** @hide */ + public int groupOwnerBand = GROUP_OWNER_BAND_AUTO; + /** @hide */ public static final int MAX_GROUP_OWNER_INTENT = 15; /** @hide */ @UnsupportedAppUsage public static final int MIN_GROUP_OWNER_INTENT = 0; + /** @hide */ + @IntDef(flag = false, prefix = { "GROUP_OWNER_BAND_" }, value = { + GROUP_OWNER_BAND_AUTO, + GROUP_OWNER_BAND_2GHZ, + GROUP_OWNER_BAND_5GHZ + }) + @Retention(RetentionPolicy.SOURCE) + public @interface GroupOwnerBandType {} + + /** + * Recognized Group Owner required band. + */ + public static final int GROUP_OWNER_BAND_AUTO = 0; + public static final int GROUP_OWNER_BAND_2GHZ = 1; + public static final int GROUP_OWNER_BAND_5GHZ = 2; + /** * This is an integer value between 0 and 15 where 0 indicates the least * inclination to be a group owner and 15 indicates the highest inclination @@ -115,6 +155,10 @@ public class WifiP2pConfig implements Parcelable { sbuf.append("\n wps: ").append(wps); sbuf.append("\n groupOwnerIntent: ").append(groupOwnerIntent); sbuf.append("\n persist: ").append(netId); + sbuf.append("\n networkName: ").append(networkName); + sbuf.append("\n passphrase: ").append( + TextUtils.isEmpty(passphrase) ? "<empty>" : "<non-empty>"); + sbuf.append("\n groupOwnerBand: ").append(groupOwnerBand); return sbuf.toString(); } @@ -130,6 +174,9 @@ public class WifiP2pConfig implements Parcelable { wps = new WpsInfo(source.wps); groupOwnerIntent = source.groupOwnerIntent; netId = source.netId; + networkName = source.networkName; + passphrase = source.passphrase; + groupOwnerBand = source.groupOwnerBand; } } @@ -139,6 +186,9 @@ public class WifiP2pConfig implements Parcelable { dest.writeParcelable(wps, flags); dest.writeInt(groupOwnerIntent); dest.writeInt(netId); + dest.writeString(networkName); + dest.writeString(passphrase); + dest.writeInt(groupOwnerBand); } /** Implement the Parcelable interface */ @@ -150,6 +200,9 @@ public class WifiP2pConfig implements Parcelable { config.wps = (WpsInfo) in.readParcelable(null); config.groupOwnerIntent = in.readInt(); config.netId = in.readInt(); + config.networkName = in.readString(); + config.passphrase = in.readString(); + config.groupOwnerBand = in.readInt(); return config; } @@ -157,4 +210,140 @@ public class WifiP2pConfig implements Parcelable { return new WifiP2pConfig[size]; } }; + + /** + * Builder used to build {@link WifiP2pConfig} objects for + * creating or joining a group. + */ + public static final class Builder { + + private static final MacAddress MAC_ANY_ADDRESS = + MacAddress.fromString("00:00:00:00:00:00"); + + private MacAddress mDeviceAddress = MAC_ANY_ADDRESS; + private String mNetworkName = ""; + private String mPassphrase = ""; + private int mGroupOwnerBand = GROUP_OWNER_BAND_AUTO; + private int mNetId = WifiP2pGroup.TEMPORARY_NET_ID; + + /** + * Specify the peer's MAC address. If not set, the device will + * try to find a peer whose SSID matches the network name as + * specified by {@link #setNetworkName(String)}. Specifying null will + * reset the peer's MAC address to "00:00:00:00:00:00". + * <p> + * Optional. "00:00:00:00:00:00" by default. + * + * @param deviceAddress the peer's MAC address. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setDeviceAddress(MacAddress deviceAddress) { + if (deviceAddress == null) { + mDeviceAddress = MAC_ANY_ADDRESS; + } else { + mDeviceAddress = deviceAddress; + } + return this; + } + + /** + * Specify the network name, a.k.a. group name, + * for creating or joining a group. + * <p> + * Must be called - an empty network name is not valid. + * + * @param networkName network name of a group. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setNetworkName(String networkName) { + if (TextUtils.isEmpty(networkName)) { + throw new IllegalArgumentException( + "network name must be non-empty."); + } + mNetworkName = networkName; + return this; + } + + /** + * Specify the passphrase for creating or joining a group. + * <p> + * Must be called - an empty passphrase is not valid. + * + * @param passphrase the passphrase of a group. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setPassphrase(String passphrase) { + if (TextUtils.isEmpty(passphrase)) { + throw new IllegalArgumentException( + "passphrase must be non-empty."); + } + mPassphrase = passphrase; + return this; + } + + /** + * Specify the band to use for creating the group. This method only applies when + * creating a group as Group Owner using {@link WifiP2pManager#createGroup}. + * The band should be {@link #GROUP_OWNER_BAND_2GHZ} or {@link #GROUP_OWNER_BAND_5GHZ}, + * or allow the system to pick the band by specifying {@link #GROUP_OWNER_BAND_AUTO}. + * If the Group Owner cannot create a group in the specified band, the operation will fail. + * <p> + * Optional. {@link #GROUP_OWNER_BAND_AUTO} by default. + * + * @param band the required band of group owner. + * This should be one of {@link #GROUP_OWNER_BAND_AUTO}, + * {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ}. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setGroupOwnerBand(int band) { + mGroupOwnerBand = band; + return this; + } + + /** + * Specify that the group configuration be persisted (i.e. saved). + * By default the group configuration will not be saved. + * <p> + * Optional. false by default. + * + * @param persistent is this group persistent group. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder enablePersistentMode(boolean persistent) { + if (persistent) { + mNetId = WifiP2pGroup.PERSISTENT_NET_ID; + } else { + mNetId = WifiP2pGroup.TEMPORARY_NET_ID; + } + return this; + } + + /** + * Build {@link WifiP2pConfig} given the current requests made on the builder. + * @return {@link WifiP2pConfig} constructed based on builder method calls. + */ + public WifiP2pConfig build() { + if (TextUtils.isEmpty(mNetworkName)) { + throw new IllegalStateException( + "network name must be non-empty."); + } + if (TextUtils.isEmpty(mPassphrase)) { + throw new IllegalStateException( + "passphrase must be non-empty."); + } + + WifiP2pConfig config = new WifiP2pConfig(); + config.deviceAddress = mDeviceAddress.toString(); + config.networkName = mNetworkName; + config.passphrase = mPassphrase; + config.groupOwnerBand = mGroupOwnerBand; + config.netId = mNetId; + return config; + } + } } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index f58a006278d2..d0efbcffd0ae 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -16,6 +16,7 @@ package android.net.wifi.p2p; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -25,6 +26,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.UnsupportedAppUsage; import android.content.Context; +import android.net.NetworkInfo; import android.net.wifi.WpsInfo; import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo; import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceResponse; @@ -49,6 +51,8 @@ import com.android.internal.util.Protocol; import dalvik.system.CloseGuard; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -158,6 +162,14 @@ public class WifiP2pManager { */ public static final String EXTRA_WIFI_STATE = "wifi_p2p_state"; + /** @hide */ + @IntDef({ + WIFI_P2P_STATE_DISABLED, + WIFI_P2P_STATE_ENABLED}) + @Retention(RetentionPolicy.SOURCE) + public @interface WifiP2pState { + } + /** * Wi-Fi p2p is disabled. * @@ -250,6 +262,14 @@ public class WifiP2pManager { */ public static final String EXTRA_DISCOVERY_STATE = "discoveryState"; + /** @hide */ + @IntDef({ + WIFI_P2P_DISCOVERY_STOPPED, + WIFI_P2P_DISCOVERY_STARTED}) + @Retention(RetentionPolicy.SOURCE) + public @interface WifiP2pDiscoveryState { + } + /** * p2p discovery has stopped * @@ -502,6 +522,21 @@ public class WifiP2pManager { /** @hide */ public static final int SET_ONGOING_PEER_CONFIG_SUCCEEDED = BASE + 89; + /** @hide */ + public static final int REQUEST_P2P_STATE = BASE + 90; + /** @hide */ + public static final int RESPONSE_P2P_STATE = BASE + 91; + + /** @hide */ + public static final int REQUEST_DISCOVERY_STATE = BASE + 92; + /** @hide */ + public static final int RESPONSE_DISCOVERY_STATE = BASE + 93; + + /** @hide */ + public static final int REQUEST_NETWORK_INFO = BASE + 94; + /** @hide */ + public static final int RESPONSE_NETWORK_INFO = BASE + 95; + /** * Create a new WifiP2pManager instance. Applications use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve @@ -690,6 +725,43 @@ public class WifiP2pManager { public void onHandoverMessageAvailable(String handoverMessage); } + /** Interface for callback invocation when p2p state is available + * in response to {@link #requestP2pState}. + */ + public interface P2pStateListener { + /** + * The requested p2p state is available. + * @param state Wi-Fi p2p state + * @see #WIFI_P2P_STATE_DISABLED + * @see #WIFI_P2P_STATE_ENABLED + */ + void onP2pStateAvailable(@WifiP2pState int state); + } + + /** Interface for callback invocation when p2p state is available + * in response to {@link #requestDiscoveryState}. + */ + public interface DiscoveryStateListener { + /** + * The requested p2p discovery state is available. + * @param state Wi-Fi p2p discovery state + * @see #WIFI_P2P_DISCOVERY_STARTED + * @see #WIFI_P2P_DISCOVERY_STOPPED + */ + void onDiscoveryStateAvailable(@WifiP2pDiscoveryState int state); + } + + /** Interface for callback invocation when {@link android.net.NetworkInfo} is available + * in response to {@link #requestNetworkInfo}. + */ + public interface NetworkInfoListener { + /** + * The requested {@link android.net.NetworkInfo} is available + * @param networkInfo Wi-Fi p2p {@link android.net.NetworkInfo} + */ + void onNetworkInfoAvailable(NetworkInfo networkInfo); + } + /** * Interface for callback invocation when ongoing peer info is available * @hide @@ -889,6 +961,24 @@ public class WifiP2pManager { .onOngoingPeerAvailable(peerConfig); } break; + case RESPONSE_P2P_STATE: + if (listener != null) { + ((P2pStateListener) listener) + .onP2pStateAvailable(message.arg1); + } + break; + case RESPONSE_DISCOVERY_STATE: + if (listener != null) { + ((DiscoveryStateListener) listener) + .onDiscoveryStateAvailable(message.arg1); + } + break; + case RESPONSE_NETWORK_INFO: + if (listener != null) { + ((NetworkInfoListener) listener) + .onNetworkInfoAvailable((NetworkInfo) message.obj); + } + break; default: Log.d(TAG, "Ignored " + message); break; @@ -1616,4 +1706,68 @@ public class WifiP2pManager { c.mAsyncChannel.sendMessage(SET_ONGOING_PEER_CONFIG, 0, c.putListener(listener), config); } + + /** + * Request p2p enabled state. + * + * <p> This state indicates whether Wi-Fi p2p is enabled or disabled. + * The valid value is one of {@link #WIFI_P2P_STATE_DISABLED} or + * {@link #WIFI_P2P_STATE_ENABLED}. The state is returned using the + * {@link P2pStateListener} listener. + * + * <p> This state is also included in the {@link #WIFI_P2P_STATE_CHANGED_ACTION} + * broadcast event with extra {@link #EXTRA_WIFI_STATE}. + * + * @param c is the channel created at {@link #initialize}. + * @param listener for callback when p2p state is available.. + */ + public void requestP2pState(@NonNull Channel c, + @NonNull P2pStateListener listener) { + checkChannel(c); + if (listener == null) throw new IllegalArgumentException("This listener cannot be null."); + c.mAsyncChannel.sendMessage(REQUEST_P2P_STATE, 0, c.putListener(listener)); + } + + /** + * Request p2p discovery state. + * + * <p> This state indicates whether p2p discovery has started or stopped. + * The valid value is one of {@link #WIFI_P2P_DISCOVERY_STARTED} or + * {@link #WIFI_P2P_DISCOVERY_STOPPED}. The state is returned using the + * {@link DiscoveryStateListener} listener. + * + * <p> This state is also included in the {@link #WIFI_P2P_DISCOVERY_CHANGED_ACTION} + * broadcast event with extra {@link #EXTRA_DISCOVERY_STATE}. + * + * @param c is the channel created at {@link #initialize}. + * @param listener for callback when discovery state is available.. + */ + public void requestDiscoveryState(@NonNull Channel c, + @NonNull DiscoveryStateListener listener) { + checkChannel(c); + if (listener == null) throw new IllegalArgumentException("This listener cannot be null."); + c.mAsyncChannel.sendMessage(REQUEST_DISCOVERY_STATE, 0, c.putListener(listener)); + } + + /** + * Request network info. + * + * <p> This method provides the network info in the form of a {@link android.net.NetworkInfo}. + * {@link android.net.NetworkInfo#isAvailable()} indicates the p2p availability and + * {@link android.net.NetworkInfo#getDetailedState()} reports the current fine-grained state + * of the network. This {@link android.net.NetworkInfo} is returned using the + * {@link NetworkInfoListener} listener. + * + * <p> This information is also included in the {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} + * broadcast event with extra {@link #EXTRA_NETWORK_INFO}. + * + * @param c is the channel created at {@link #initialize}. + * @param listener for callback when network info is available.. + */ + public void requestNetworkInfo(@NonNull Channel c, + @NonNull NetworkInfoListener listener) { + checkChannel(c); + if (listener == null) throw new IllegalArgumentException("This listener cannot be null."); + c.mAsyncChannel.sendMessage(REQUEST_NETWORK_INFO, 0, c.putListener(listener)); + } } diff --git a/wifi/java/com/android/server/wifi/AbstractWifiService.java b/wifi/java/com/android/server/wifi/AbstractWifiService.java index 04bc55710dfd..aa526d248d14 100644 --- a/wifi/java/com/android/server/wifi/AbstractWifiService.java +++ b/wifi/java/com/android/server/wifi/AbstractWifiService.java @@ -73,7 +73,7 @@ public abstract class AbstractWifiService extends IWifiManager.Stub { } @Override - public ParceledListSlice getConfiguredNetworks() { + public ParceledListSlice getConfiguredNetworks(String packageName) { throw new UnsupportedOperationException(); } @@ -188,17 +188,17 @@ public abstract class AbstractWifiService extends IWifiManager.Stub { } @Override - public void disconnect(String packageName) { + public boolean disconnect(String packageName) { throw new UnsupportedOperationException(); } @Override - public void reconnect(String packageName) { + public boolean reconnect(String packageName) { throw new UnsupportedOperationException(); } @Override - public void reassociate(String packageName) { + public boolean reassociate(String packageName) { throw new UnsupportedOperationException(); } |