summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp3
-rw-r--r--core/api/current.txt28
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/api/test-current.txt8
-rw-r--r--core/java/android/app/WallpaperManager.java39
-rw-r--r--core/java/android/content/SyncAdapterType.java2
-rw-r--r--core/java/android/content/pm/ActivityInfo.java19
-rw-r--r--core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java1
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedActivity.java12
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedActivityUtils.java5
-rw-r--r--core/java/android/graphics/fonts/FontManager.java1
-rw-r--r--core/java/android/hardware/SystemSensorManager.java2
-rw-r--r--core/java/android/os/Environment.java60
-rw-r--r--core/java/android/os/incremental/IncrementalManager.java21
-rw-r--r--core/java/android/os/incremental/IncrementalMetrics.java39
-rw-r--r--core/java/android/os/incremental/IncrementalStorage.java14
-rw-r--r--core/java/android/util/apk/ApkSigningBlockUtils.java5
-rw-r--r--core/java/android/util/apk/DataSource.java22
-rw-r--r--core/java/android/util/apk/MemoryMappedFileDataSource.java1
-rw-r--r--core/java/android/util/apk/ReadFileDataSource.java73
-rw-r--r--core/java/android/util/apk/TEST_MAPPING11
-rw-r--r--core/java/android/util/apk/VerityBuilder.java8
-rw-r--r--core/java/android/util/imetracing/ImeTracing.java7
-rw-r--r--core/java/android/util/imetracing/ImeTracingClientImpl.java6
-rw-r--r--core/java/android/util/imetracing/ImeTracingServerImpl.java27
-rw-r--r--core/java/android/view/DisplayInfo.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java11
-rw-r--r--core/java/android/widget/AnalogClock.java2
-rw-r--r--core/java/android/widget/Editor.java4
-rw-r--r--core/java/android/widget/TextView.java13
-rw-r--r--core/java/android/window/ITaskOrganizer.aidl7
-rw-r--r--core/java/android/window/SplashScreenView.java9
-rw-r--r--core/java/android/window/StartingWindowInfo.java8
-rw-r--r--core/java/android/window/TaskOrganizer.java15
-rw-r--r--core/jni/android_os_incremental_IncrementalManager.cpp5
-rw-r--r--core/jni/android_view_InputEventSender.cpp28
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp2
-rw-r--r--core/proto/android/server/windowmanagerservice.proto3
-rw-r--r--core/res/res/values/attrs_manifest.xml11
-rw-r--r--core/res/res/values/config.xml93
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/res/res/values/strings.xml10
-rw-r--r--core/res/res/values/symbols.xml93
-rw-r--r--core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java69
-rw-r--r--core/tests/mockingcoretests/src/android/view/DisplayTests.java107
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--libs/WindowManager/Shell/AndroidManifest.xml1
-rw-r--r--libs/WindowManager/Shell/res/values/config.xml6
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java328
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java50
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java225
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidTest.xml2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java29
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java3
-rw-r--r--packages/Connectivity/framework/api/current.txt8
-rw-r--r--packages/Connectivity/framework/api/module-lib-current.txt1
-rw-r--r--packages/Connectivity/framework/api/system-current.txt1
-rw-r--r--packages/Connectivity/framework/src/android/net/ConnectivityManager.java103
-rw-r--r--packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl4
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkCapabilities.java109
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkInfo.java3
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkRequest.java15
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkState.java4
-rw-r--r--packages/Connectivity/framework/src/android/net/ParseException.java (renamed from core/java/android/net/ParseException.java)0
-rw-r--r--packages/Connectivity/framework/src/android/net/QosSocketInfo.java6
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java52
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java4
-rw-r--r--services/core/Android.bp7
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java144
-rw-r--r--services/core/java/com/android/server/IpSecService.java19
-rw-r--r--services/core/java/com/android/server/NetIdManager.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java33
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java74
-rw-r--r--services/core/java/com/android/server/am/ProcessErrorStateRecord.java36
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java54
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java66
-rw-r--r--services/core/java/com/android/server/content/ContentService.java3
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java16
-rw-r--r--services/core/java/com/android/server/graphics/fonts/FontManagerService.java2
-rw-r--r--services/core/java/com/android/server/hdmi/DeviceSelectAction.java15
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecConfig.java433
-rwxr-xr-xservices/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecNetwork.java7
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java1
-rw-r--r--services/core/java/com/android/server/hdmi/OneTouchPlayAction.java37
-rw-r--r--services/core/java/com/android/server/hdmi/cec_config.xml133
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java11
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java19
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java147
-rw-r--r--services/core/java/com/android/server/policy/SplashScreenSurface.java2
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java21
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java6
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java2
-rw-r--r--services/core/java/com/android/server/wm/DragState.java44
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java42
-rw-r--r--services/core/java/com/android/server/wm/StartingSurfaceController.java10
-rw-r--r--services/core/java/com/android/server/wm/Task.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java31
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioningController.java3
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java7
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowFrames.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java68
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp11
-rw-r--r--services/core/xsd/Android.bp7
-rw-r--r--services/core/xsd/cec-config/cec-config.xsd29
-rw-r--r--services/core/xsd/cec-config/schema/current.txt44
-rw-r--r--services/core/xsd/cec-config/schema/last_current.txt0
-rw-r--r--services/core/xsd/cec-config/schema/last_removed.txt0
-rw-r--r--services/core/xsd/cec-config/schema/removed.txt1
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java11
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java7
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java40
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java353
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java856
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java46
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java90
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java285
-rw-r--r--tests/FlickerTests/AndroidTest.xml2
-rw-r--r--tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java14
-rw-r--r--tests/net/common/java/android/net/NetworkCapabilitiesTest.java105
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java22
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java174
-rw-r--r--tests/net/java/com/android/server/IpSecServiceTest.java10
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java48
141 files changed, 3283 insertions, 2384 deletions
diff --git a/Android.bp b/Android.bp
index 622b2c6120bd..9690969305bf 100644
--- a/Android.bp
+++ b/Android.bp
@@ -665,9 +665,8 @@ java_defaults {
],
required: [
"framework-platform-compat-config",
- // TODO: remove gps_debug, cec_config.xml and protolog.conf.json when the build system propagates "required" properly.
+ // TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
"gps_debug.conf",
- "cec_config.xml",
"icu4j-platform-compat-config",
"libcore-platform-compat-config",
"protolog.conf.json.gz",
diff --git a/core/api/current.txt b/core/api/current.txt
index bc25561cf1aa..61d2db931843 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -329,6 +329,7 @@ package android {
field public static final int apiKey = 16843281; // 0x1010211
field public static final int appCategory = 16844101; // 0x1010545
field public static final int appComponentFactory = 16844154; // 0x101057a
+ field public static final int attributionTags = 16844353; // 0x1010641
field public static final int author = 16843444; // 0x10102b4
field public static final int authorities = 16842776; // 0x1010018
field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -26137,10 +26138,6 @@ package android.net {
ctor public NetworkSpecifier();
}
- public class ParseException extends java.lang.RuntimeException {
- field public String response;
- }
-
public abstract class PlatformVpnProfile {
method public final int getType();
method @NonNull public final String getTypeString();
@@ -40614,14 +40611,6 @@ package android.telephony {
public static final class CarrierConfigManager.Iwlan {
field public static final int AUTHENTICATION_METHOD_CERT = 1; // 0x1
field public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0; // 0x0
- field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2
- field public static final int DH_GROUP_1536_BIT_MODP = 5; // 0x5
- field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe
- field public static final int DH_GROUP_3072_BIT_MODP = 15; // 0xf
- field public static final int DH_GROUP_4096_BIT_MODP = 16; // 0x10
- field public static final int DH_GROUP_NONE = 0; // 0x0
- field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc
- field public static final int ENCRYPTION_ALGORITHM_AES_CTR = 13; // 0xd
field public static final int EPDG_ADDRESS_CELLULAR_LOC = 3; // 0x3
field public static final int EPDG_ADDRESS_PCO = 2; // 0x2
field public static final int EPDG_ADDRESS_PLMN = 1; // 0x1
@@ -40629,12 +40618,6 @@ package android.telephony {
field public static final int ID_TYPE_FQDN = 2; // 0x2
field public static final int ID_TYPE_KEY_ID = 11; // 0xb
field public static final int ID_TYPE_RFC822_ADDR = 3; // 0x3
- field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe
- field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0
field public static final String KEY_ADD_KE_TO_CHILD_SESSION_REKEY_BOOL = "iwlan.add_ke_to_child_session_rekey_bool";
field public static final String KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT = "iwlan.child_sa_rekey_hard_timer_sec_int";
field public static final String KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT = "iwlan.child_sa_rekey_soft_timer_sec_int";
@@ -40654,10 +40637,6 @@ package android.telephony {
field public static final String KEY_IKE_REMOTE_ID_TYPE_INT = "iwlan.ike_remote_id_type_int";
field public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_cbc_key_size_int_array";
field public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_ctr_key_size_int_array";
- field public static final int KEY_LEN_AES_128 = 128; // 0x80
- field public static final int KEY_LEN_AES_192 = 192; // 0xc0
- field public static final int KEY_LEN_AES_256 = 256; // 0x100
- field public static final int KEY_LEN_UNUSED = 0; // 0x0
field public static final String KEY_MAX_RETRIES_INT = "iwlan.max_retries_int";
field public static final String KEY_MCC_MNCS_STRING_ARRAY = "iwlan.mcc_mncs_string_array";
field public static final String KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT = "iwlan.natt_keep_alive_timer_sec_int";
@@ -40667,11 +40646,6 @@ package android.telephony {
field public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = "iwlan.supported_ike_session_encryption_algorithms_int_array";
field public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY = "iwlan.supported_integrity_algorithms_int_array";
field public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = "iwlan.supported_prf_algorithms_int_array";
- field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4
- field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
- field public static final int PSEUDORANDOM_FUNCTION_SHA2_256 = 5; // 0x5
- field public static final int PSEUDORANDOM_FUNCTION_SHA2_384 = 6; // 0x6
- field public static final int PSEUDORANDOM_FUNCTION_SHA2_512 = 7; // 0x7
}
public abstract class CellIdentity implements android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index eddf5a4a92b9..6019ab56dea7 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2901,7 +2901,7 @@ package android.graphics.fonts {
}
public class FontManager {
- method @NonNull public android.text.FontConfig getFontConfig();
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public android.text.FontConfig getFontConfig();
method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int);
field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb
field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 8fa46591e514..a7ca44cd4a5c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -706,6 +706,10 @@ package android.content {
method public int getDisplayId();
}
+ public class SyncAdapterType implements android.os.Parcelable {
+ method @Nullable public String getPackageName();
+ }
+
}
package android.content.integrity {
@@ -968,7 +972,7 @@ package android.graphics.drawable {
package android.graphics.fonts {
public class FontManager {
- method @NonNull public android.text.FontConfig getFontConfig();
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public android.text.FontConfig getFontConfig();
method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int);
field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb
field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff
@@ -2921,7 +2925,7 @@ package android.window {
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer();
- method @BinderThread public void removeStartingWindow(int);
+ method @BinderThread public void removeStartingWindow(int, @Nullable android.view.SurfaceControl, @Nullable android.graphics.Rect, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer();
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 8e53b5ba1c9f..7dbbc54665e9 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -57,6 +57,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.DeadSystemException;
+import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
@@ -120,6 +121,8 @@ public class WallpaperManager {
/** {@hide} */
private static final String VALUE_CMF_COLOR =
android.os.SystemProperties.get("ro.boot.hardware.color");
+ /** {@hide} */
+ private static final String WALLPAPER_CMF_PATH = "/wallpaper/image/";
/**
* Activity Action: Show settings for choosing wallpaper. Do not use directly to construct
@@ -2066,31 +2069,45 @@ public class WallpaperManager {
return null;
} else {
whichProp = PROP_WALLPAPER;
- final int defaultColorResId = context.getResources().getIdentifier(
- "default_wallpaper_" + VALUE_CMF_COLOR, "drawable", "android");
- defaultResId =
- defaultColorResId == 0 ? com.android.internal.R.drawable.default_wallpaper
- : defaultColorResId;
+ defaultResId = com.android.internal.R.drawable.default_wallpaper;
}
final String path = SystemProperties.get(whichProp);
+ final InputStream wallpaperInputStream = getWallpaperInputStream(path);
+ if (wallpaperInputStream != null) {
+ return wallpaperInputStream;
+ }
+ final String cmfPath = getCmfWallpaperPath();
+ final InputStream cmfWallpaperInputStream = getWallpaperInputStream(cmfPath);
+ if (cmfWallpaperInputStream != null) {
+ return cmfWallpaperInputStream;
+ }
+ try {
+ return context.getResources().openRawResource(defaultResId);
+ } catch (NotFoundException e) {
+ // no default defined for this device; this is not a failure
+ }
+ return null;
+ }
+
+ private static InputStream getWallpaperInputStream(String path) {
if (!TextUtils.isEmpty(path)) {
final File file = new File(path);
if (file.exists()) {
try {
return new FileInputStream(file);
} catch (IOException e) {
- // Ignored, fall back to platform default below
+ // Ignored, fall back to platform default
}
}
}
- try {
- return context.getResources().openRawResource(defaultResId);
- } catch (NotFoundException e) {
- // no default defined for this device; this is not a failure
- }
return null;
}
+ private static String getCmfWallpaperPath() {
+ return Environment.getProductDirectory() + WALLPAPER_CMF_PATH + "default_wallpaper_"
+ + VALUE_CMF_COLOR;
+ }
+
/**
* Return {@link ComponentName} of the default live wallpaper, or
* {@code null} if none is defined.
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
index 1c21b2aa73a5..47c333ceb931 100644
--- a/core/java/android/content/SyncAdapterType.java
+++ b/core/java/android/content/SyncAdapterType.java
@@ -17,6 +17,7 @@
package android.content;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -168,6 +169,7 @@ public class SyncAdapterType implements Parcelable {
*
* @hide
*/
+ @TestApi
public @Nullable String getPackageName() {
return packageName;
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 5a17753bf9ad..58f83a73ff16 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1086,6 +1086,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
*/
public WindowLayout windowLayout;
+ /**
+ * Attribution tags for finer grained calls if a {@android.content.Context#sendBroadcast(Intent,
+ * String)} is used with a permission.
+ * @hide
+ */
+ public String[] attributionTags;
+
public ActivityInfo() {
}
@@ -1114,6 +1121,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
maxAspectRatio = orig.maxAspectRatio;
minAspectRatio = orig.minAspectRatio;
supportsSizeChanges = orig.supportsSizeChanges;
+ attributionTags = orig.attributionTags;
}
/**
@@ -1361,6 +1369,15 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
if (supportsSizeChanges) {
pw.println(prefix + "supportsSizeChanges=true");
}
+ if (attributionTags != null && attributionTags.length > 0) {
+ StringBuilder tags = new StringBuilder();
+ tags.append(attributionTags[0]);
+ for (int i = 1; i < attributionTags.length; i++) {
+ tags.append(", ");
+ tags.append(attributionTags[i]);
+ }
+ pw.println(prefix + "attributionTags=[" + tags + "]");
+ }
super.dumpBack(pw, prefix, dumpFlags);
}
@@ -1406,6 +1423,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
dest.writeFloat(maxAspectRatio);
dest.writeFloat(minAspectRatio);
dest.writeBoolean(supportsSizeChanges);
+ dest.writeString8Array(attributionTags);
}
/**
@@ -1525,6 +1543,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
maxAspectRatio = source.readFloat();
minAspectRatio = source.readFloat();
supportsSizeChanges = source.readBoolean();
+ attributionTags = source.createString8Array();
}
/**
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 9a84ded99c67..b660a00443a4 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -482,6 +482,7 @@ public class PackageInfoWithoutStateUtils {
ai.rotationAnimation = a.getRotationAnimation();
ai.colorMode = a.getColorMode();
ai.windowLayout = a.getWindowLayout();
+ ai.attributionTags = a.getAttributionTags();
if ((flags & PackageManager.GET_META_DATA) != 0) {
ai.metaData = a.getMetaData();
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 6f478accedd7..9285ccb3cf0c 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -82,6 +82,9 @@ public class ParsedActivity extends ParsedMainComponent {
@Nullable
ActivityInfo.WindowLayout windowLayout;
+ @Nullable
+ String[] attributionTags;
+
public ParsedActivity(ParsedActivity other) {
super(other);
this.theme = other.theme;
@@ -107,6 +110,7 @@ public class ParsedActivity extends ParsedMainComponent {
this.rotationAnimation = other.rotationAnimation;
this.colorMode = other.colorMode;
this.windowLayout = other.windowLayout;
+ this.attributionTags = other.attributionTags;
}
/**
@@ -172,6 +176,7 @@ public class ParsedActivity extends ParsedMainComponent {
alias.requestedVrComponent = target.requestedVrComponent;
alias.directBootAware = target.directBootAware;
alias.setProcessName(target.getProcessName());
+ alias.attributionTags = target.attributionTags;
return alias;
// Not all attributes from the target ParsedActivity are copied to the alias.
@@ -299,6 +304,7 @@ public class ParsedActivity extends ParsedMainComponent {
} else {
dest.writeBoolean(false);
}
+ dest.writeString8Array(this.attributionTags);
}
public ParsedActivity() {
@@ -332,6 +338,7 @@ public class ParsedActivity extends ParsedMainComponent {
if (in.readBoolean()) {
windowLayout = new ActivityInfo.WindowLayout(in);
}
+ this.attributionTags = in.createString8Array();
}
public static final Parcelable.Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
@@ -445,4 +452,9 @@ public class ParsedActivity extends ParsedMainComponent {
public ActivityInfo.WindowLayout getWindowLayout() {
return windowLayout;
}
+
+ @Nullable
+ public String[] getAttributionTags() {
+ return attributionTags;
+ }
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index 0f4aa061b72d..d99c4109e5ad 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -210,6 +210,11 @@ public class ParsedActivityUtils {
pkg.setVisibleToInstantApps(true);
}
+ String attributionTags = sa.getString(R.styleable.AndroidManifestActivity_attributionTags);
+ if (attributionTags != null) {
+ activity.attributionTags = attributionTags.split("\\|");
+ }
+
return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver,
false /*isAlias*/, visibleToEphemeral, input,
R.styleable.AndroidManifestActivity_parentActivityName,
diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java
index 7bf692f1d318..fa2ccbc189ad 100644
--- a/core/java/android/graphics/fonts/FontManager.java
+++ b/core/java/android/graphics/fonts/FontManager.java
@@ -195,6 +195,7 @@ public class FontManager {
* @return The current font configuration. null if failed to fetch information from the system
* service.
*/
+ @RequiresPermission(Manifest.permission.UPDATE_FONTS)
public @NonNull FontConfig getFontConfig() {
try {
return mIFontManager.getFontConfig();
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 788afe3bdb8e..365dea691489 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -65,7 +65,7 @@ public class SystemSensorManager extends SensorManager {
private static final int CAPPED_SAMPLING_RATE_LEVEL = SensorDirectChannel.RATE_NORMAL;
private static final String HIGH_SAMPLING_RATE_SENSORS_PERMISSION =
- "android.permisison.HIGH_SAMPLING_RATE_SENSORS";
+ "android.permission.HIGH_SAMPLING_RATE_SENSORS";
/**
* For apps targeting S and above, a SecurityException is thrown when they do not have
* HIGH_SAMPLING_RATE_SENSORS permission, run in debug mode, and request sampling rates that
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 124c0b00b2b2..21bf8b8c30e4 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -728,11 +728,11 @@ public class Environment {
/**
* Standard directory in which to place any audio files that should be
* in the regular list of music for the user.
- * This may be combined with
+ * This may be combined with {@link #DIRECTORY_AUDIOBOOKS},
* {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
- * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
- * of directories to categories a particular audio file as more than one
- * type.
+ * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
+ * {@link #DIRECTORY_RECORDINGS} as a series of directories to
+ * categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_MUSIC = "Music";
@@ -741,10 +741,10 @@ public class Environment {
* in the list of podcasts that the user can select (not as regular
* music).
* This may be combined with {@link #DIRECTORY_MUSIC},
- * {@link #DIRECTORY_NOTIFICATIONS},
- * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
- * of directories to categories a particular audio file as more than one
- * type.
+ * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_NOTIFICATIONS},
+ * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
+ * {@link #DIRECTORY_RECORDINGS} as a series of directories to
+ * categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_PODCASTS = "Podcasts";
@@ -753,10 +753,10 @@ public class Environment {
* in the list of ringtones that the user can select (not as regular
* music).
* This may be combined with {@link #DIRECTORY_MUSIC},
- * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
- * {@link #DIRECTORY_ALARMS} as a series
- * of directories to categories a particular audio file as more than one
- * type.
+ * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+ * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS},
+ * and {@link #DIRECTORY_RECORDINGS} as a series of directories
+ * to categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_RINGTONES = "Ringtones";
@@ -765,10 +765,10 @@ public class Environment {
* in the list of alarms that the user can select (not as regular
* music).
* This may be combined with {@link #DIRECTORY_MUSIC},
- * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
- * and {@link #DIRECTORY_RINGTONES} as a series
- * of directories to categories a particular audio file as more than one
- * type.
+ * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+ * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_RINGTONES},
+ * and {@link #DIRECTORY_RECORDINGS} as a series of directories
+ * to categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_ALARMS = "Alarms";
@@ -777,10 +777,10 @@ public class Environment {
* in the list of notifications that the user can select (not as regular
* music).
* This may be combined with {@link #DIRECTORY_MUSIC},
- * {@link #DIRECTORY_PODCASTS},
- * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
- * of directories to categories a particular audio file as more than one
- * type.
+ * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+ * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
+ * {@link #DIRECTORY_RECORDINGS} as a series of directories to
+ * categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_NOTIFICATIONS = "Notifications";
@@ -831,14 +831,26 @@ public class Environment {
public static String DIRECTORY_SCREENSHOTS = "Screenshots";
/**
- * Standard directory in which to place any audio files which are
- * audiobooks.
+ * Standard directory in which to place any audio files that should be
+ * in the list of audiobooks that the user can select (not as regular
+ * music).
+ * This may be combined with {@link #DIRECTORY_MUSIC},
+ * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
+ * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES},
+ * and {@link #DIRECTORY_RECORDINGS} as a series of directories
+ * to categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_AUDIOBOOKS = "Audiobooks";
/**
- * Standard directory in which to place any audio files which are
- * recordings.
+ * Standard directory in which to place any audio files that should be
+ * in the list of voice recordings recorded by voice recorder apps that
+ * the user can select (not as regular music).
+ * This may be combined with {@link #DIRECTORY_MUSIC},
+ * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+ * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS},
+ * and {@link #DIRECTORY_RINGTONES} as a series of directories
+ * to categorize a particular audio file as more than one type.
*/
@NonNull
// The better way is that expose a static method getRecordingDirectories.
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index dc6f63a94685..047c05a8734b 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -30,6 +30,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -265,6 +266,13 @@ public final class IncrementalManager {
}
/**
+ * Checks if an fd corresponds to a file on a mounted Incremental File System.
+ */
+ public static boolean isIncrementalFileFd(@NonNull FileDescriptor fd) {
+ return nativeIsIncrementalFd(fd.getInt$());
+ }
+
+ /**
* Returns raw signature for file if it's on Incremental File System.
* Unsafe, use only if you are sure what you are doing.
*/
@@ -421,9 +429,22 @@ public final class IncrementalManager {
storage.unregisterStorageHealthListener();
}
+ /**
+ * Returns the metrics of an Incremental Storage.
+ */
+ public IncrementalMetrics getMetrics(@NonNull String codePath) {
+ final IncrementalStorage storage = openStorage(codePath);
+ if (storage == null) {
+ // storage does not exist, package not installed
+ return null;
+ }
+ return new IncrementalMetrics(storage.getMetrics());
+ }
+
/* Native methods */
private static native boolean nativeIsEnabled();
private static native boolean nativeIsV2Available();
private static native boolean nativeIsIncrementalPath(@NonNull String path);
+ private static native boolean nativeIsIncrementalFd(@NonNull int fd);
private static native byte[] nativeUnsafeGetFileSignature(@NonNull String path);
}
diff --git a/core/java/android/os/incremental/IncrementalMetrics.java b/core/java/android/os/incremental/IncrementalMetrics.java
new file mode 100644
index 000000000000..44dea1be50f0
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalMetrics.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.annotation.NonNull;
+import android.os.PersistableBundle;
+
+/**
+ * Provides methods to access metrics about an app installed via Incremental
+ * @hide
+ */
+public class IncrementalMetrics {
+ @NonNull private final PersistableBundle mData;
+
+ public IncrementalMetrics(@NonNull PersistableBundle data) {
+ mData = data;
+ }
+
+ /**
+ * @return Milliseconds between now and when the oldest pending read happened
+ */
+ public long getMillisSinceOldestPendingRead() {
+ return mData.getLong(IIncrementalService.METRICS_MILLIS_SINCE_OLDEST_PENDING_READ, -1);
+ }
+}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index e6ce8cd56d28..7cf0144d71f7 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.DataLoaderParams;
import android.content.pm.IDataLoaderStatusListener;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import java.io.File;
@@ -601,4 +602,17 @@ public final class IncrementalStorage {
return;
}
}
+
+ /**
+ * Returns the metrics of the current storage.
+ * {@see IIncrementalService} for metrics keys.
+ */
+ public PersistableBundle getMetrics() {
+ try {
+ return mService.getMetrics(mId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
}
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index c97c995641d1..7e6175c03d35 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -200,10 +200,9 @@ public final class ApkSigningBlockUtils {
// physical memory.
DataSource beforeApkSigningBlock =
- new MemoryMappedFileDataSource(apkFileDescriptor, 0,
- signatureInfo.apkSigningBlockOffset);
+ DataSource.create(apkFileDescriptor, 0, signatureInfo.apkSigningBlockOffset);
DataSource centralDir =
- new MemoryMappedFileDataSource(
+ DataSource.create(
apkFileDescriptor, signatureInfo.centralDirOffset,
signatureInfo.eocdOffset - signatureInfo.centralDirOffset);
diff --git a/core/java/android/util/apk/DataSource.java b/core/java/android/util/apk/DataSource.java
index 82f3800aa6d3..dd6389d012bc 100644
--- a/core/java/android/util/apk/DataSource.java
+++ b/core/java/android/util/apk/DataSource.java
@@ -16,6 +16,10 @@
package android.util.apk;
+import android.annotation.NonNull;
+import android.os.incremental.IncrementalManager;
+
+import java.io.FileDescriptor;
import java.io.IOException;
import java.security.DigestException;
@@ -35,4 +39,22 @@ interface DataSource {
*/
void feedIntoDataDigester(DataDigester md, long offset, int size)
throws IOException, DigestException;
+
+ /**
+ * Creates a DataSource that can handle the passed fd in the most efficient and safe manner.
+ * @param fd file descriptor to read from
+ * @param pos starting offset
+ * @param size size of the region
+ * @return created DataSource object
+ */
+ static @NonNull DataSource create(@NonNull FileDescriptor fd, long pos, long size) {
+ if (IncrementalManager.isIncrementalFileFd(fd)) {
+ // IncFS-based files may have missing pages, and reading those via mmap() results
+ // in a SIGBUS signal. Java doesn't have a good way of catching it, ending up killing
+ // the process by default. Going back to read() is the safest option for these files.
+ return new ReadFileDataSource(fd, pos, size);
+ } else {
+ return new MemoryMappedFileDataSource(fd, pos, size);
+ }
+ }
}
diff --git a/core/java/android/util/apk/MemoryMappedFileDataSource.java b/core/java/android/util/apk/MemoryMappedFileDataSource.java
index 8d2b1e328862..69a526d09ad9 100644
--- a/core/java/android/util/apk/MemoryMappedFileDataSource.java
+++ b/core/java/android/util/apk/MemoryMappedFileDataSource.java
@@ -40,6 +40,7 @@ class MemoryMappedFileDataSource implements DataSource {
/**
* Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
*
+ * @param fd file descriptor to read from.
* @param position start position of the region in the file.
* @param size size (in bytes) of the region.
*/
diff --git a/core/java/android/util/apk/ReadFileDataSource.java b/core/java/android/util/apk/ReadFileDataSource.java
new file mode 100644
index 000000000000..d0e1140c0eb4
--- /dev/null
+++ b/core/java/android/util/apk/ReadFileDataSource.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 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.util.apk;
+
+import android.system.ErrnoException;
+import android.system.Os;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+
+/**
+ * {@link DataSource} which provides data from a file descriptor by reading the sections
+ * of the file via raw read() syscall. This is slower than memory-mapping but safer.
+ */
+class ReadFileDataSource implements DataSource {
+ private final FileDescriptor mFd;
+ private final long mFilePosition;
+ private final long mSize;
+
+ private static final int CHUNK_SIZE = 1024 * 1024;
+
+ /**
+ * Constructs a new {@code ReadFileDataSource} for the specified region of the file.
+ *
+ * @param fd file descriptor to read from.
+ * @param position start position of the region in the file.
+ * @param size size (in bytes) of the region.
+ */
+ ReadFileDataSource(FileDescriptor fd, long position, long size) {
+ mFd = fd;
+ mFilePosition = position;
+ mSize = size;
+ }
+
+ @Override
+ public long size() {
+ return mSize;
+ }
+
+ @Override
+ public void feedIntoDataDigester(DataDigester md, long offset, int size)
+ throws IOException, DigestException {
+ try {
+ final byte[] buffer = new byte[Math.min(size, CHUNK_SIZE)];
+ final long start = mFilePosition + offset;
+ final long end = start + size;
+ for (long pos = start, curSize = Math.min(size, CHUNK_SIZE);
+ pos < end; curSize = Math.min(end - pos, CHUNK_SIZE)) {
+ final int readSize = Os.pread(mFd, buffer, 0, (int) curSize, pos);
+ md.consume(ByteBuffer.wrap(buffer, 0, readSize));
+ pos += readSize;
+ }
+ } catch (ErrnoException e) {
+ throw new IOException(e);
+ }
+ }
+}
diff --git a/core/java/android/util/apk/TEST_MAPPING b/core/java/android/util/apk/TEST_MAPPING
index 8544e82e04e0..4598b4ffe4f6 100644
--- a/core/java/android/util/apk/TEST_MAPPING
+++ b/core/java/android/util/apk/TEST_MAPPING
@@ -1,6 +1,17 @@
{
"presubmit": [
{
+ "name": "CtsContentTestCases",
+ "options": [
+ {
+ "include-filter": "android.content.pm.cts.PackageManagerShellCommandIncrementalTest"
+ },
+ {
+ "include-filter": "android.content.pm.cts.PackageManagerShellCommandTest"
+ }
+ ]
+ },
+ {
"name": "FrameworksCoreTests",
"options": [
{
diff --git a/core/java/android/util/apk/VerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java
index 4596c6e8f83d..b0a5992230bd 100644
--- a/core/java/android/util/apk/VerityBuilder.java
+++ b/core/java/android/util/apk/VerityBuilder.java
@@ -294,7 +294,7 @@ public abstract class VerityBuilder {
// 1. Digest the whole file by chunks.
consumeByChunk(digester,
- new MemoryMappedFileDataSource(file.getFD(), 0, file.length()),
+ DataSource.create(file.getFD(), 0, file.length()),
MMAP_REGION_SIZE_BYTES);
// 2. Pad 0s up to the nearest 4096-byte block before hashing.
@@ -315,7 +315,7 @@ public abstract class VerityBuilder {
// 1. Digest from the beginning of the file, until APK Signing Block is reached.
consumeByChunk(digester,
- new MemoryMappedFileDataSource(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset),
+ DataSource.create(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset),
MMAP_REGION_SIZE_BYTES);
// 2. Skip APK Signing Block and continue digesting, until the Central Directory offset
@@ -323,7 +323,7 @@ public abstract class VerityBuilder {
long eocdCdOffsetFieldPosition =
signatureInfo.eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET;
consumeByChunk(digester,
- new MemoryMappedFileDataSource(apk.getFD(), signatureInfo.centralDirOffset,
+ DataSource.create(apk.getFD(), signatureInfo.centralDirOffset,
eocdCdOffsetFieldPosition - signatureInfo.centralDirOffset),
MMAP_REGION_SIZE_BYTES);
@@ -338,7 +338,7 @@ public abstract class VerityBuilder {
long offsetAfterEocdCdOffsetField =
eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
consumeByChunk(digester,
- new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField,
+ DataSource.create(apk.getFD(), offsetAfterEocdCdOffsetField,
apk.length() - offsetAfterEocdCdOffsetField),
MMAP_REGION_SIZE_BYTES);
diff --git a/core/java/android/util/imetracing/ImeTracing.java b/core/java/android/util/imetracing/ImeTracing.java
index 49ff237403b2..b28cfb87e28d 100644
--- a/core/java/android/util/imetracing/ImeTracing.java
+++ b/core/java/android/util/imetracing/ImeTracing.java
@@ -23,7 +23,6 @@ import android.inputmethodservice.AbstractInputMethodService;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.ShellCommand;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.InputMethodManager;
@@ -104,12 +103,6 @@ public abstract class ImeTracing {
public abstract void addToBuffer(ProtoOutputStream proto, int source);
/**
- * @param shell The shell command to process
- * @return {@code 0} if the command was successfully processed, {@code -1} otherwise
- */
- public abstract int onShellCommand(ShellCommand shell);
-
- /**
* Starts a proto dump of the client side information.
*
* @param where Place where the trace was triggered.
diff --git a/core/java/android/util/imetracing/ImeTracingClientImpl.java b/core/java/android/util/imetracing/ImeTracingClientImpl.java
index 2c2763988d14..35a81b7aeea5 100644
--- a/core/java/android/util/imetracing/ImeTracingClientImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingClientImpl.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.inputmethodservice.AbstractInputMethodService;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.ShellCommand;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.InputMethodManager;
@@ -45,11 +44,6 @@ class ImeTracingClientImpl extends ImeTracing {
}
@Override
- public int onShellCommand(ShellCommand shell) {
- return -1;
- }
-
- @Override
public void triggerClientDump(String where, @NonNull InputMethodManager immInstance,
ProtoOutputStream icProto) {
if (!isEnabled() || !isAvailable()) {
diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/android/util/imetracing/ImeTracingServerImpl.java
index e793c280afbc..77f017a4654a 100644
--- a/core/java/android/util/imetracing/ImeTracingServerImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingServerImpl.java
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.inputmethodservice.AbstractInputMethodService;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.ShellCommand;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceFileProto;
@@ -106,32 +105,6 @@ class ImeTracingServerImpl extends ImeTracing {
}
}
- /**
- * Responds to a shell command of the format "adb shell cmd input_method ime tracing <command>"
- *
- * @param shell The shell command to process
- * @return {@code 0} if the command was valid and successfully processed, {@code -1} otherwise
- */
- @Override
- public int onShellCommand(ShellCommand shell) {
- PrintWriter pw = shell.getOutPrintWriter();
- String cmd = shell.getNextArgRequired();
- switch (cmd) {
- case "start":
- startTrace(pw);
- return 0;
- case "stop":
- stopTrace(pw);
- return 0;
- default:
- pw.println("Unknown command: " + cmd);
- pw.println("Input method trace options:");
- pw.println(" start: Start tracing");
- pw.println(" stop: Stop tracing");
- return -1;
- }
- }
-
@Override
public void triggerClientDump(String where, InputMethodManager immInstance,
ProtoOutputStream icProto) {
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index a8aaeb7846a2..9aaf5c066073 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -636,7 +636,9 @@ public final class DisplayInfo implements Parcelable {
public void getMaxBoundsMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
Configuration configuration) {
Rect bounds = configuration.windowConfiguration.getMaxBounds();
- getMetricsWithSize(outMetrics, compatInfo, configuration, bounds.width(), bounds.height());
+ // Pass in null configuration to ensure width and height are not overridden to app bounds.
+ getMetricsWithSize(outMetrics, compatInfo, /* configuration= */ null,
+ bounds.width(), bounds.height());
}
public int getNaturalWidth() {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9fc415d6401f..35726c0c1f04 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8572,6 +8572,17 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
+ public void onDragEvent(boolean isExiting, float x, float y) {
+ // force DRAG_EXITED_EVENT if appropriate
+ DragEvent event = DragEvent.obtain(
+ isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION,
+ x, y, 0 /* offsetX */, 0 /* offsetY */, null/* localState */,
+ null/* description */, null /* data */, null /* dragSurface */,
+ null /* dragAndDropPermissions */, false /* result */);
+ dispatchDragEvent(event);
+ }
+
+ @Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 34fe51e82e8f..42d75353e5df 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -200,6 +200,8 @@ public class AnalogClock extends View {
mTimeZone = toZoneId(a.getString(com.android.internal.R.styleable.AnalogClock_timeZone));
createClock();
+ a.recycle();
+
mDialWidth = mDial.getIntrinsicWidth();
mDialHeight = mDial.getIntrinsicHeight();
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 012352d0a0f5..7517b805da69 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3790,7 +3790,7 @@ public class Editor {
}
public SuggestionsPopupWindow() {
- mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+ mCursorWasVisibleBeforeSuggestions = mTextView.isCursorVisibleFromAttr();
}
@Override
@@ -3957,7 +3957,7 @@ public class Editor {
}
if (updateSuggestions()) {
- mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+ mCursorWasVisibleBeforeSuggestions = mTextView.isCursorVisibleFromAttr();
mTextView.setCursorVisible(false);
mIsShowingUp = true;
super.show();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 177a9f164cb3..dba7fa915f35 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -503,7 +503,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private boolean mImeIsConsumingInput;
// Whether cursor is visible without regard to {@link mImeConsumesInput}.
- // {code true} is the default value.
+ // {@code true} is the default value.
private boolean mCursorVisibleFromAttr = true;
static class Drawables {
@@ -10571,6 +10571,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return mEditor == null ? true : mEditor.mCursorVisible;
}
+ /**
+ * @return whether cursor is visible without regard to {@code mImeIsConsumingInput}.
+ * {@code true} is the default value.
+ *
+ * @see #setCursorVisible(boolean)
+ * @hide
+ */
+ public boolean isCursorVisibleFromAttr() {
+ return mCursorVisibleFromAttr;
+ }
+
private boolean canMarquee() {
int width = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
return width > 0 && (mLayout.getLineWidth(0) > width
diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl
index 8f541d0bd194..3eb35c2c5e8a 100644
--- a/core/java/android/window/ITaskOrganizer.aidl
+++ b/core/java/android/window/ITaskOrganizer.aidl
@@ -18,6 +18,7 @@ package android.window;
import android.view.SurfaceControl;
import android.app.ActivityManager;
+import android.graphics.Rect;
import android.window.StartingWindowInfo;
import android.window.WindowContainerToken;
@@ -38,8 +39,12 @@ oneway interface ITaskOrganizer {
/**
* Called when the Task want to remove the starting window.
+ * @param leash A persistent leash for the top window in this task.
+ * @param frame Window frame of the top window.
+ * @param playRevealAnimation Play vanish animation.
*/
- void removeStartingWindow(int taskId);
+ void removeStartingWindow(int taskId, in SurfaceControl leash, in Rect frame,
+ in boolean playRevealAnimation);
/**
* Called when the Task want to copy the splash screen.
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 35ccfca101d3..da445b8b9f33 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -46,6 +46,8 @@ import android.widget.FrameLayout;
import com.android.internal.R;
import com.android.internal.policy.DecorView;
+import java.util.function.Consumer;
+
/**
* <p>The view which allows an activity to customize its splash screen exit animation.</p>
*
@@ -77,7 +79,8 @@ public final class SplashScreenView extends FrameLayout {
private Animatable mAnimatableIcon;
private ValueAnimator mAnimator;
-
+ private Runnable mAnimationFinishListener;
+ private Consumer<Canvas> mOnDrawCallback;
// cache original window and status
private Window mWindow;
private boolean mDrawBarBackground;
@@ -85,7 +88,7 @@ public final class SplashScreenView extends FrameLayout {
private int mNavigationBarColor;
/**
- * Internal builder to create a SplashScreenWindowView object.
+ * Internal builder to create a SplashScreenView object.
* @hide
*/
public static class Builder {
@@ -391,7 +394,7 @@ public final class SplashScreenView extends FrameLayout {
* Get the initial background color of this view.
* @hide
*/
- @ColorInt int getInitBackgroundColor() {
+ public @ColorInt int getInitBackgroundColor() {
return mInitBackgroundColor;
}
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index d1c1e40d1578..c7672dc9fe7d 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -126,6 +126,12 @@ public final class StartingWindowInfo implements Parcelable {
*/
public int splashScreenThemeResId;
+ /**
+ * Is keyguard occluded on default display.
+ * @hide
+ */
+ public boolean isKeyguardOccluded = false;
+
public StartingWindowInfo() {
}
@@ -147,6 +153,7 @@ public final class StartingWindowInfo implements Parcelable {
dest.writeTypedObject(topOpaqueWindowLayoutParams, flags);
dest.writeTypedObject(mainWindowLayoutParams, flags);
dest.writeInt(splashScreenThemeResId);
+ dest.writeBoolean(isKeyguardOccluded);
}
void readFromParcel(@NonNull Parcel source) {
@@ -157,6 +164,7 @@ public final class StartingWindowInfo implements Parcelable {
WindowManager.LayoutParams.CREATOR);
mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR);
splashScreenThemeResId = source.readInt();
+ isKeyguardOccluded = source.readBoolean();
}
@Override
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 04020ec3ee8a..3340cf4fb707 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -24,6 +24,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.app.ActivityManager;
+import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.SurfaceControl;
@@ -100,9 +101,14 @@ public class TaskOrganizer extends WindowOrganizer {
/**
* Called when the Task want to remove the starting window.
+ * @param leash A persistent leash for the top window in this task. Release it once exit
+ * animation has finished.
+ * @param frame Window frame of the top window.
+ * @param playRevealAnimation Play vanish animation.
*/
@BinderThread
- public void removeStartingWindow(int taskId) {}
+ public void removeStartingWindow(int taskId, @Nullable SurfaceControl leash,
+ @Nullable Rect frame, boolean playRevealAnimation) {}
/**
* Called when the Task want to copy the splash screen.
@@ -217,15 +223,16 @@ public class TaskOrganizer extends WindowOrganizer {
private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
@Override
-
public void addStartingWindow(StartingWindowInfo windowInfo,
IBinder appToken) {
mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo, appToken));
}
@Override
- public void removeStartingWindow(int taskId) {
- mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId));
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
+ mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId, leash, frame,
+ playRevealAnimation));
}
@Override
diff --git a/core/jni/android_os_incremental_IncrementalManager.cpp b/core/jni/android_os_incremental_IncrementalManager.cpp
index 2384efaf1a54..413bcef57a64 100644
--- a/core/jni/android_os_incremental_IncrementalManager.cpp
+++ b/core/jni/android_os_incremental_IncrementalManager.cpp
@@ -41,6 +41,10 @@ static jboolean nativeIsIncrementalPath(JNIEnv* env,
return (jboolean)IncFs_IsIncFsPath(path.c_str());
}
+static jboolean nativeIsIncrementalFd(JNIEnv* env, jobject clazz, jint fd) {
+ return (jboolean)IncFs_IsIncFsFd(fd);
+}
+
static jbyteArray nativeUnsafeGetFileSignature(JNIEnv* env, jobject clazz, jstring javaPath) {
ScopedUtfChars path(env, javaPath);
@@ -61,6 +65,7 @@ static const JNINativeMethod method_table[] =
{{"nativeIsEnabled", "()Z", (void*)nativeIsEnabled},
{"nativeIsV2Available", "()Z", (void*)nativeIsV2Available},
{"nativeIsIncrementalPath", "(Ljava/lang/String;)Z", (void*)nativeIsIncrementalPath},
+ {"nativeIsIncrementalFd", "(I)Z", (void*)nativeIsIncrementalFd},
{"nativeUnsafeGetFileSignature", "(Ljava/lang/String;)[B",
(void*)nativeUnsafeGetFileSignature}};
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 96326f591998..9746a07a1b77 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -34,8 +34,6 @@
#include "core_jni_helpers.h"
-using android::base::Result;
-
namespace android {
// Log debug messages about the dispatch cycle.
@@ -199,9 +197,16 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
ScopedLocalRef<jobject> senderObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
- Result<InputPublisher::Finished> result = mInputPublisher.receiveFinishedSignal();
- if (!result.ok()) {
- const status_t status = result.error().code();
+ uint32_t publishedSeq;
+ bool handled;
+ std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)> callback =
+ [&publishedSeq, &handled](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ publishedSeq = inSeq;
+ handled = inHandled;
+ };
+ status_t status = mInputPublisher.receiveFinishedSignal(callback);
+ if (status) {
if (status == WOULD_BLOCK) {
return OK;
}
@@ -210,7 +215,7 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
return status;
}
- auto it = mPublishedSeqMap.find(result->seq);
+ auto it = mPublishedSeqMap.find(publishedSeq);
if (it == mPublishedSeqMap.end()) {
continue;
}
@@ -220,9 +225,9 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, "
- "pendingEvents=%zu.",
- getInputChannelName().c_str(), seq, result->handled ? "true" : "false",
- mPublishedSeqMap.size());
+ "pendingEvents=%zu.",
+ getInputChannelName().c_str(), seq, handled ? "true" : "false",
+ mPublishedSeqMap.size());
}
if (!skipCallbacks) {
@@ -236,9 +241,8 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
}
env->CallVoidMethod(senderObj.get(),
- gInputEventSenderClassInfo.dispatchInputEventFinished,
- static_cast<jint>(result->seq),
- static_cast<jboolean>(result->handled));
+ gInputEventSenderClassInfo.dispatchInputEventFinished,
+ jint(seq), jboolean(handled));
if (env->ExceptionCheck()) {
ALOGE("Exception dispatching finished signal.");
skipCallbacks = true;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index cf96fe63f82c..0bed29b7ba28 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -193,7 +193,7 @@ static constexpr unsigned int STORAGE_DIR_CHECK_MAX_INTERVAL_US = 1000;
* If it exceeds 2s, PROC_START_TIMEOUT_MSG will kill the starting app anyway,
* so it's fine to assume max retries is 5 mins.
*/
-static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 60 * 5;
+static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 1000 * 60 * 5;
/**
* A helper class containing accounting information for USAPs.
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index f26bf7cdb6c1..a7127ad79401 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -346,6 +346,7 @@ message ActivityRecordProto {
optional int32 proc_id = 29;
optional bool translucent = 30;
optional bool pip_auto_enter_enabled = 31;
+ optional bool in_size_compat_mode = 32;
}
/* represents WindowToken */
@@ -406,7 +407,7 @@ message WindowStateProto {
optional int64 finished_seamless_rotation_frame = 40;
optional WindowFramesProto window_frames = 41;
optional bool force_seamless_rotation = 42;
- optional bool in_size_compat_mode = 43;
+ optional bool has_compat_scale = 43;
optional float global_scale = 44;
}
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cc52655ad7d2..601d66ec7b39 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -829,7 +829,6 @@
{@code FLAG_ACTIVITY_MULTIPLE_TASK} is set.-->
<enum name="singleInstancePerTask" value="4" />
</attr>
-
<!-- Specify the orientation an activity should be run in. If not
specified, it will run in the current preferred orientation
of the screen.
@@ -1603,6 +1602,12 @@
<enum name="sync" value="2" />
</attr>
+ <!-- Attribution tag to be used for permission sub-attribution if a
+ permission is checked in {@link android.content.Context#sendBroadcast(Intent, String)}.
+ Multiple tags can be specified separated by '|'.
+ -->
+ <attr name="attributionTags" format="string" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -2825,6 +2830,10 @@
<p> See {@link android.content.pm.ActivityInfo#FLAG_PREFER_MINIMAL_POST_PROCESSING} -->
<attr name="preferMinimalPostProcessing" format="boolean"/>
+ <!-- Specify the attributionTags to be used if a permission is required due to
+ {@link android.content.Context#sendBroadcast(Intent, String)} being used.
+ Multiple tags can be specified separated by '|'. -->
+ <attr name="attributionTags"/>
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a3d0ab52ba57..f6fee880bf2f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4722,4 +4722,97 @@
<!-- Whether to allow the caching of the SIM PIN for verification after unattended reboot -->
<bool name="config_allow_pin_storage_for_unattended_reboot">true</bool>
+
+ <!-- CEC Configuration -->
+ <bool name="config_cecHdmiCecEnabled_userConfigurable">true</bool>
+ <bool name="config_cecHdmiCecControlEnabled_allowed">true</bool>
+ <bool name="config_cecHdmiCecControlEnabled_default">true</bool>
+ <bool name="config_cecHdmiCecControlDisabled_allowed">true</bool>
+ <bool name="config_cecHdmiCecControlDisabled_default">false</bool>
+
+ <bool name="config_cecHdmiCecVersion_userConfigurable">true</bool>
+ <bool name="config_cecHdmiCecVersion14b_allowed">true</bool>
+ <bool name="config_cecHdmiCecVersion14b_default">true</bool>
+ <bool name="config_cecHdmiCecVersion20_allowed">true</bool>
+ <bool name="config_cecHdmiCecVersion20_default">false</bool>
+
+ <bool name="config_cecSendStandbyOnSleep_userConfigurable">true</bool>
+ <bool name="config_cecPowerControlModeTv_allowed">true</bool>
+ <bool name="config_cecPowerControlModeTv_default">true</bool>
+ <bool name="config_cecPowerControlModeBroadcast_allowed">true</bool>
+ <bool name="config_cecPowerControlModeBroadcast_default">false</bool>
+ <bool name="config_cecPowerControlModeNone_allowed">true</bool>
+ <bool name="config_cecPowerControlModeNone_default">false</bool>
+
+ <bool name="config_cecPowerStateChangeOnActiveSourceLost_userConfigurable">true</bool>
+ <bool name="config_cecPowerStateChangeOnActiveSourceLostNone_allowed">true</bool>
+ <bool name="config_cecPowerStateChangeOnActiveSourceLostNone_default">true</bool>
+ <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed">true</bool>
+ <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default">false</bool>
+
+ <bool name="config_cecSystemAudioModeMuting_userConfigurable">true</bool>
+ <bool name="config_cecSystemAudioModeMutingEnabled_allowed">true</bool>
+ <bool name="config_cecSystemAudioModeMutingEnabled_default">true</bool>
+ <bool name="config_cecSystemAudioModeMutingDisabled_allowed">true</bool>
+ <bool name="config_cecSystemAudioModeMutingDisabled_default">false</bool>
+
+ <bool name="config_cecVolumeControlMode_userConfigurable">true</bool>
+ <bool name="config_cecVolumeControlModeEnabled_allowed">true</bool>
+ <bool name="config_cecVolumeControlModeEnabled_default">true</bool>
+ <bool name="config_cecVolumeControlModeDisabled_allowed">true</bool>
+ <bool name="config_cecVolumeControlModeDisabled_default">false</bool>
+
+ <bool name="config_cecTvWakeOnOneTouchPlay_userConfigurable">true</bool>
+ <bool name="config_cecTvWakeOnOneTouchPlayEnabled_allowed">true</bool>
+ <bool name="config_cecTvWakeOnOneTouchPlayEnabled_default">true</bool>
+ <bool name="config_cecTvWakeOnOneTouchPlayDisabled_allowed">true</bool>
+ <bool name="config_cecTvWakeOnOneTouchPlayDisabled_default">false</bool>
+
+ <bool name="config_cecTvSendStandbyOnSleep_userConfigurable">true</bool>
+ <bool name="config_cecTvSendStandbyOnSleepEnabled_allowed">true</bool>
+ <bool name="config_cecTvSendStandbyOnSleepEnabled_default">true</bool>
+ <bool name="config_cecTvSendStandbyOnSleepDisabled_allowed">true</bool>
+ <bool name="config_cecTvSendStandbyOnSleepDisabled_default">false</bool>
+
+ <bool name="config_cecRcProfileTv_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileTvNone_allowed">true</bool>
+ <bool name="config_cecRcProfileTvNone_default">true</bool>
+ <bool name="config_cecRcProfileTvOne_allowed">true</bool>
+ <bool name="config_cecRcProfileTvOne_default">false</bool>
+ <bool name="config_cecRcProfileTvTwo_allowed">true</bool>
+ <bool name="config_cecRcProfileTvTwo_default">false</bool>
+ <bool name="config_cecRcProfileTvThree_allowed">true</bool>
+ <bool name="config_cecRcProfileTvThree_default">false</bool>
+ <bool name="config_cecRcProfileTvFour_allowed">true</bool>
+ <bool name="config_cecRcProfileTvFour_default">false</bool>
+
+ <bool name="config_cecRcProfileSourceRootMenu_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileSourceRootMenuHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceRootMenuHandled_default">true</bool>
+ <bool name="config_cecRcProfileSourceRootMenuNotHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceRootMenuNotHandled_default">false</bool>
+
+ <bool name="config_cecRcProfileSourceSetupMenu_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileSourceSetupMenuHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceSetupMenuHandled_default">true</bool>
+ <bool name="config_cecRcProfileSourceSetupMenuNotHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceSetupMenuNotHandled_default">false</bool>
+
+ <bool name="config_cecRcProfileSourceContentsMenu_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileSourceContentsMenuHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceContentsMenuHandled_default">false</bool>
+ <bool name="config_cecRcProfileSourceContentsMenuNotHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceContentsMenuNotHandled_default">true</bool>
+
+ <bool name="config_cecRcProfileSourceTopMenu_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileSourceTopMenuHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceTopMenuHandled_default">false</bool>
+ <bool name="config_cecRcProfileSourceTopMenuNotHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceTopMenuNotHandled_default">true</bool>
+
+ <bool name="config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default">false</bool>
+ <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default">true</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e0a728c233b2..40c80dbeeb73 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3087,6 +3087,7 @@
<public name="passwordsActivity"/>
<public name="selectableAsDefault"/>
<public name="isAccessibilityTool"/>
+ <public name="attributionTags"/>
</public-group>
<public-group type="drawable" first-id="0x010800b5">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4af561b947cd..387c065175be 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3691,6 +3691,8 @@
<string name="ext_media_checking_notification_title">Checking <xliff:g id="name" example="SD card">%s</xliff:g>\u2026</string>
<!-- Notification body when external media is being checked [CHAR LIMIT=NONE] -->
<string name="ext_media_checking_notification_message">Reviewing current content</string>
+ <!-- TV specific notification body when external media is being checked [CHAR LIMIT=75] -->
+ <string name="ext_media_checking_notification_message" product="tv">Analyzing media storage</string>
<!-- Notification body when new external media is detected [CHAR LIMIT=30] -->
<string name="ext_media_new_notification_title">New <xliff:g id="name" example="SD card">%s</xliff:g></string>
@@ -3698,11 +3700,15 @@
<string name="ext_media_new_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
<!-- Notification body when new external media is detected [CHAR LIMIT=NONE] -->
<string name="ext_media_new_notification_message">Tap to set up</string>
+ <!-- TV specific notification body when new external media is detected [CHAR LIMIT=75] -->
+ <string name="ext_media_new_notification_message" product="tv">Select to set up</string>
<!-- Automotive specific notification body when new external media is detected. [CHAR LIMIT=NONE] -->
<string name="ext_media_new_notification_message" product="automotive">You may need to reformat the device. Tap to eject.</string>
<!-- Notification body when external media is ready for use [CHAR LIMIT=NONE] -->
<string name="ext_media_ready_notification_message">For transferring photos and media</string>
+ <!-- TV specific notification body when external media is ready for use [CHAR LIMIT=75] -->
+ <string name="ext_media_ready_notification_message" product="tv">Browse media files</string>
<!-- Notification title when external media is unmountable (corrupt) [CHAR LIMIT=30] -->
<string name="ext_media_unmountable_notification_title">Issue with <xliff:g id="name" example="SD card">%s</xliff:g></string>
@@ -3721,8 +3727,8 @@
<string name="ext_media_unsupported_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
<!-- Notification body when external media is unsupported [CHAR LIMIT=NONE] -->
<string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Tap to set up in a supported format.</string>
- <!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
- <string name="ext_media_unsupported_notification_message" product="tv">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Select to set up in a supported format.</string>
+ <!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=75] -->
+ <string name="ext_media_unsupported_notification_message" product="tv">Select to set up <xliff:g id="name" example="SD card">%s</xliff:g> in a supported format.</string>
<!-- Automotive specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
<string name="ext_media_unsupported_notification_message" product="automotive">You may need to reformat the device</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f19405260fa8..543dc1564851 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4224,4 +4224,97 @@
<java-symbol type="bool" name="config_voice_data_sms_auto_fallback" />
<java-symbol type="bool" name="config_enableOneHandedKeyguard" />
+
+ <!-- CEC Configuration -->
+ <java-symbol type="bool" name="config_cecHdmiCecEnabled_userConfigurable" />
+ <java-symbol type="bool" name="config_cecHdmiCecControlEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecHdmiCecControlEnabled_default" />
+ <java-symbol type="bool" name="config_cecHdmiCecControlDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecHdmiCecControlDisabled_default" />
+
+ <java-symbol type="bool" name="config_cecHdmiCecVersion_userConfigurable" />
+ <java-symbol type="bool" name="config_cecHdmiCecVersion14b_allowed" />
+ <java-symbol type="bool" name="config_cecHdmiCecVersion14b_default" />
+ <java-symbol type="bool" name="config_cecHdmiCecVersion20_allowed" />
+ <java-symbol type="bool" name="config_cecHdmiCecVersion20_default" />
+
+ <java-symbol type="bool" name="config_cecSendStandbyOnSleep_userConfigurable" />
+ <java-symbol type="bool" name="config_cecPowerControlModeTv_allowed" />
+ <java-symbol type="bool" name="config_cecPowerControlModeTv_default" />
+ <java-symbol type="bool" name="config_cecPowerControlModeBroadcast_allowed" />
+ <java-symbol type="bool" name="config_cecPowerControlModeBroadcast_default" />
+ <java-symbol type="bool" name="config_cecPowerControlModeNone_allowed" />
+ <java-symbol type="bool" name="config_cecPowerControlModeNone_default" />
+
+ <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLost_userConfigurable" />
+ <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostNone_allowed" />
+ <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostNone_default" />
+ <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed" />
+ <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default" />
+
+ <java-symbol type="bool" name="config_cecSystemAudioModeMuting_userConfigurable" />
+ <java-symbol type="bool" name="config_cecSystemAudioModeMutingEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecSystemAudioModeMutingEnabled_default" />
+ <java-symbol type="bool" name="config_cecSystemAudioModeMutingDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecSystemAudioModeMutingDisabled_default" />
+
+ <java-symbol type="bool" name="config_cecVolumeControlMode_userConfigurable" />
+ <java-symbol type="bool" name="config_cecVolumeControlModeEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecVolumeControlModeEnabled_default" />
+ <java-symbol type="bool" name="config_cecVolumeControlModeDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecVolumeControlModeDisabled_default" />
+
+ <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlay_userConfigurable" />
+ <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayEnabled_default" />
+ <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayDisabled_default" />
+
+ <java-symbol type="bool" name="config_cecTvSendStandbyOnSleep_userConfigurable" />
+ <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepEnabled_default" />
+ <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileTv_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileTvNone_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileTvNone_default" />
+ <java-symbol type="bool" name="config_cecRcProfileTvOne_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileTvOne_default" />
+ <java-symbol type="bool" name="config_cecRcProfileTvTwo_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileTvTwo_default" />
+ <java-symbol type="bool" name="config_cecRcProfileTvThree_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileTvThree_default" />
+ <java-symbol type="bool" name="config_cecRcProfileTvFour_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileTvFour_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileSourceRootMenu_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuHandled_default" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuNotHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuNotHandled_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenu_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuHandled_default" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuNotHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuNotHandled_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenu_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuHandled_default" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuNotHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuNotHandled_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileSourceTopMenu_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuHandled_default" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuNotHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuNotHandled_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default" />
</resources>
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index f6e02bc1f48a..28f9ccc10135 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -41,7 +41,9 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import android.content.res.TypedArray;
import android.text.Selection;
@@ -356,4 +358,71 @@ public class SuggestionsPopupWindowTest {
.perform(clearText());
}
}
+
+ @Test
+ public void testCursorVisibility() {
+ final TextView textView = getActivity().findViewById(R.id.textview);
+ final String text = "abc";
+
+ assertTrue(textView.isCursorVisible());
+
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(),
+ new String[]{"ABC"}, SuggestionSpan.FLAG_AUTO_CORRECTION);
+ setSuggestionSpan(suggestionSpan, text.indexOf('a'), text.indexOf('c') + 1);
+ showSuggestionsPopup();
+
+ assertSuggestionsPopupIsDisplayed();
+ assertSuggestionsPopupContainsItem("ABC");
+ assertFalse(textView.isCursorVisible());
+
+ // Delete an item.
+ clickSuggestionsPopupItem(
+ getActivity().getString(com.android.internal.R.string.delete));
+ assertSuggestionsPopupIsNotDisplayed();
+ assertTrue(textView.isCursorVisible());
+ }
+
+ @Test
+ public void testCursorVisibilityWhenImeConsumesInput() {
+ final TextView textView = getActivity().findViewById(R.id.textview);
+ final String text = "abc";
+
+ assertTrue(textView.isCursorVisible());
+
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ setImeConsumesInputWithExpect(textView, true /* imeConsumesInput */,
+ false /* expectedCursorVisibility */);
+ final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(),
+ new String[]{"ABC"}, SuggestionSpan.FLAG_AUTO_CORRECTION);
+ setSuggestionSpan(suggestionSpan, text.indexOf('a'), text.indexOf('c') + 1);
+ showSuggestionsPopup();
+
+ assertSuggestionsPopupIsDisplayed();
+ assertSuggestionsPopupContainsItem("ABC");
+ assertFalse(textView.isCursorVisible());
+
+ // Delete an item.
+ clickSuggestionsPopupItem(
+ getActivity().getString(com.android.internal.R.string.delete));
+ assertSuggestionsPopupIsNotDisplayed();
+ assertFalse(textView.isCursorVisible());
+
+ // Set IME not consumes input, cursor should be back to visible.
+ setImeConsumesInputWithExpect(textView, false /* imeConsumesInput */,
+ true /* expectedCursorVisibility */);
+ }
+
+ private void setImeConsumesInputWithExpect(
+ final TextView textView, boolean imeConsumesInput, boolean expectedCursorVisibility) {
+ textView.post(() -> textView.setImeConsumesInput(imeConsumesInput));
+ getInstrumentation().waitForIdleSync();
+ if (expectedCursorVisibility) {
+ assertTrue(textView.isCursorVisible());
+ } else {
+ assertFalse(textView.isCursorVisible());
+ }
+ }
}
diff --git a/core/tests/mockingcoretests/src/android/view/DisplayTests.java b/core/tests/mockingcoretests/src/android/view/DisplayTests.java
index 678f21fe1211..a036db224a54 100644
--- a/core/tests/mockingcoretests/src/android/view/DisplayTests.java
+++ b/core/tests/mockingcoretests/src/android/view/DisplayTests.java
@@ -73,6 +73,11 @@ public class DisplayTests {
private static Rect sAppBoundsPortrait = buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT);
private static Rect sAppBoundsLandscape = buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH);
+ // Bounds of the device.
+ private static Rect sDeviceBoundsPortrait = new Rect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
+ private static Rect sDeviceBoundsLandscape = new Rect(0, 0, LOGICAL_HEIGHT, LOGICAL_WIDTH);
+
+
private StaticMockitoSession mMockitoSession;
private DisplayManagerGlobal mDisplayManagerGlobal;
@@ -278,29 +283,57 @@ public class DisplayTests {
}
@Test
- public void testGetRealSize_resourcesPortraitSandboxed_matchesSandboxBounds() {
+ public void testGetRealSize_resourcesPortraitSandboxed_matchesAppSandboxBounds() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN app is letterboxed.
- setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
- sAppBoundsPortrait);
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsPortrait);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app bounds.
- verifyRealSizeMatchesApp(display, sAppBoundsPortrait);
+ verifyRealSizeMatchesBounds(display, sAppBoundsPortrait);
}
@Test
- public void testGetRealSize_resourcesLandscapeSandboxed_matchesSandboxBounds() {
+ public void testGetRealSize_resourcesPortraitSandboxed_matchesDisplayAreaSandboxBounds() {
+ // GIVEN display is not rotated.
+ setDisplayInfoPortrait(mDisplayInfo);
+ // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsPortrait);
+ // GIVEN app bounds do not stretch to include the full DisplayArea.
+ mApplicationContext.getResources().getConfiguration().windowConfiguration
+ .setAppBounds(buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT - 10));
+ final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+ mApplicationContext.getResources());
+ // THEN real metrics matches max bounds for the DisplayArea.
+ verifyRealSizeMatchesBounds(display, sDeviceBoundsPortrait);
+ }
+
+ @Test
+ public void testGetRealSize_resourcesLandscapeSandboxed_matchesAppSandboxBounds() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN app is letterboxed.
- setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
- sAppBoundsLandscape);
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsLandscape);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app bounds.
- verifyRealSizeMatchesApp(display, sAppBoundsLandscape);
+ verifyRealSizeMatchesBounds(display, sAppBoundsLandscape);
+ }
+
+ @Test
+ public void testGetRealSize_resourcesLandscapeSandboxed_matchesDisplayAreaSandboxBounds() {
+ // GIVEN display is rotated.
+ setDisplayInfoLandscape(mDisplayInfo);
+ // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsLandscape);
+ // GIVEN app bounds do not stretch to include the full DisplayArea.
+ mApplicationContext.getResources().getConfiguration().windowConfiguration
+ .setAppBounds(buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH - 10));
+ final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+ mApplicationContext.getResources());
+ // THEN real metrics matches max bounds for the DisplayArea.
+ verifyRealSizeMatchesBounds(display, sDeviceBoundsLandscape);
}
@Test
@@ -396,29 +429,57 @@ public class DisplayTests {
}
@Test
- public void testGetRealMetrics_resourcesPortraitSandboxed_matchesSandboxBounds() {
+ public void testGetRealMetrics_resourcesPortraitSandboxed_matchesAppSandboxBounds() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN app is letterboxed.
- setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
- sAppBoundsPortrait);
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsPortrait);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app bounds.
- verifyRealMetricsMatchesApp(display, sAppBoundsPortrait);
+ verifyRealMetricsMatchesBounds(display, sAppBoundsPortrait);
+ }
+
+ @Test
+ public void testGetRealMetrics_resourcesPortraitSandboxed_matchesDisplayAreaSandboxBounds() {
+ // GIVEN display is not rotated.
+ setDisplayInfoPortrait(mDisplayInfo);
+ // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsPortrait);
+ // GIVEN app bounds do not stretch to include the full DisplayArea.
+ mApplicationContext.getResources().getConfiguration().windowConfiguration
+ .setAppBounds(buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT - 10));
+ final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+ mApplicationContext.getResources());
+ // THEN real metrics matches max bounds for the DisplayArea.
+ verifyRealMetricsMatchesBounds(display, sDeviceBoundsPortrait);
}
@Test
- public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesSandboxBounds() {
+ public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesAppSandboxBounds() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN app is letterboxed.
- setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
- sAppBoundsLandscape);
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsLandscape);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app bounds.
- verifyRealMetricsMatchesApp(display, sAppBoundsLandscape);
+ verifyRealMetricsMatchesBounds(display, sAppBoundsLandscape);
+ }
+
+ @Test
+ public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesDisplayAreaSandboxBounds() {
+ // GIVEN display is rotated.
+ setDisplayInfoLandscape(mDisplayInfo);
+ // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsLandscape);
+ // GIVEN app bounds do not stretch to include the full DisplayArea.
+ mApplicationContext.getResources().getConfiguration().windowConfiguration
+ .setAppBounds(buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH - 10));
+ final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+ mApplicationContext.getResources());
+ // THEN real metrics matches max bounds for the DisplayArea.
+ verifyRealMetricsMatchesBounds(display, sDeviceBoundsLandscape);
}
// Given rotated display dimensions, calculate the letterboxed app bounds.
@@ -450,8 +511,8 @@ public class DisplayTests {
* Set max bounds to be sandboxed to the app bounds, indicating the app is in
* size compat mode or letterbox.
*/
- private static void setMaxBoundsSandboxedToMatchAppBounds(Resources resources, Rect appBounds) {
- resources.getConfiguration().windowConfiguration.setMaxBounds(appBounds);
+ private static void setMaxBoundsSandboxed(Resources resources, Rect bounds) {
+ resources.getConfiguration().windowConfiguration.setMaxBounds(bounds);
}
/**
@@ -492,17 +553,17 @@ public class DisplayTests {
assertThat(metrics.heightPixels).isEqualTo(LOGICAL_HEIGHT);
}
- private static void verifyRealSizeMatchesApp(Display display, Rect appBounds) {
+ private static void verifyRealSizeMatchesBounds(Display display, Rect bounds) {
Point size = new Point();
display.getRealSize(size);
- assertThat(size).isEqualTo(new Point(appBounds.width(), appBounds.height()));
+ assertThat(size).isEqualTo(new Point(bounds.width(), bounds.height()));
}
- private static void verifyRealMetricsMatchesApp(Display display, Rect appBounds) {
+ private static void verifyRealMetricsMatchesBounds(Display display, Rect bounds) {
DisplayMetrics metrics = new DisplayMetrics();
display.getRealMetrics(metrics);
- assertThat(metrics.widthPixels).isEqualTo(appBounds.width());
- assertThat(metrics.heightPixels).isEqualTo(appBounds.height());
+ assertThat(metrics.widthPixels).isEqualTo(bounds.width());
+ assertThat(metrics.heightPixels).isEqualTo(bounds.height());
}
private static FixedRotationAdjustments setOverrideFixedRotationAdjustments(
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c49fe8563dab..a7b6636a15de 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -488,6 +488,8 @@ applications that come with the platform
<permission name="android.permission.MANAGE_UI_TRANSLATION" />
<!-- Permission required for CTS test - ClipboardManagerTest -->
<permission name="android.permission.SET_CLIP_SOURCE" />
+ <!-- Permission required for CTS test - FontManagerTest -->
+ <permission name="android.permission.UPDATE_FONTS" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml
index c0bc73dcbd47..d2b3cf6a4fe2 100644
--- a/libs/WindowManager/Shell/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/AndroidManifest.xml
@@ -18,4 +18,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.wm.shell">
<uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
+ <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
</manifest>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 24198659e15d..c2f591b9d7af 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -51,4 +51,10 @@
<!-- maximum animation duration for the icon when entering the starting window -->
<integer name="max_starting_window_intro_icon_anim_duration">1000</integer>
+
+ <!-- Animation duration when exit starting window: icon going away -->
+ <integer name="starting_window_icon_exit_anim_duration">166</integer>
+
+ <!-- Animation duration when exit starting window: reveal app -->
+ <integer name="starting_window_app_reveal_anim_duration">333</integer>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 75bed3777a9d..3ced8d3ec6e7 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -188,4 +188,13 @@
<!-- The height of the brand image on staring surface. -->
<dimen name="starting_surface_brand_image_height">80dp</dimen>
+
+ <!-- The length of the shift of main window when exit starting window. -->
+ <dimen name="starting_surface_exit_animation_window_shift_length">20dp</dimen>
+
+ <!-- The distance of the shift icon when normal exit starting window. -->
+ <dimen name="starting_surface_normal_exit_icon_distance">120dp</dimen>
+
+ <!-- The distance of the shift icon when early exit starting window. -->
+ <dimen name="starting_surface_early_exit_icon_distance">32dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index cb04bd7ce02b..fcb53cd890b7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -31,6 +31,7 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.app.TaskInfo;
import android.content.Context;
import android.content.LocusId;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.util.ArrayMap;
@@ -307,9 +308,10 @@ public class ShellTaskOrganizer extends TaskOrganizer {
}
@Override
- public void removeStartingWindow(int taskId) {
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
if (mStartingSurface != null) {
- mStartingSurface.removeStartingWindow(taskId);
+ mStartingSurface.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
new file mode 100644
index 000000000000..5bc2afd11fe8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2020 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.wm.shell.startingsurface;
+
+import static android.view.View.GONE;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.graphics.BlendMode;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+import android.view.animation.Transformation;
+import android.view.animation.TranslateYAnimation;
+import android.window.SplashScreenView;
+
+import com.android.wm.shell.common.TransactionPool;
+
+/**
+ * Default animation for exiting the splash screen window.
+ * @hide
+ */
+public class SplashScreenExitAnimation implements Animator.AnimatorListener {
+ private static final boolean DEBUG_EXIT_ANIMATION = false;
+ private static final boolean DEBUG_EXIT_ANIMATION_BLEND = false;
+ private static final String TAG = StartingSurfaceDrawer.TAG;
+
+ private static final Interpolator ICON_EXIT_INTERPOLATOR = new PathInterpolator(1f, 0f, 1f, 1f);
+ private static final Interpolator APP_EXIT_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f);
+
+ private static final int EXTRA_REVEAL_DELAY = 133;
+ private final Matrix mTmpTransform = new Matrix();
+ private final float[] mTmpFloat9 = new float[9];
+ private SurfaceControl mFirstWindowSurface;
+ private final Rect mFirstWindowFrame = new Rect();
+ private final SplashScreenView mSplashScreenView;
+ private final int mMainWindowShiftLength;
+ private final int mIconShiftLength;
+ private final int mAppDuration;
+ private final int mIconDuration;
+ private final TransactionPool mTransactionPool;
+
+ private ValueAnimator mMainAnimator;
+ private Animation mShiftUpAnimation;
+ private AnimationSet mIconAnimationSet;
+ private Runnable mFinishCallback;
+
+ SplashScreenExitAnimation(SplashScreenView view, SurfaceControl leash, Rect frame,
+ int appDuration, int iconDuration, int mainWindowShiftLength, int iconShiftLength,
+ TransactionPool pool, Runnable handleFinish) {
+ mSplashScreenView = view;
+ mFirstWindowSurface = leash;
+ if (frame != null) {
+ mFirstWindowFrame.set(frame);
+ }
+ mAppDuration = appDuration;
+ mIconDuration = iconDuration;
+ mMainWindowShiftLength = mainWindowShiftLength;
+ mIconShiftLength = iconShiftLength;
+ mFinishCallback = handleFinish;
+ mTransactionPool = pool;
+ }
+
+ void prepareAnimations() {
+ prepareRevealAnimation();
+ prepareShiftAnimation();
+ }
+
+ void startAnimations() {
+ if (mIconAnimationSet != null) {
+ mIconAnimationSet.start();
+ }
+ if (mMainAnimator != null) {
+ mMainAnimator.start();
+ }
+ if (mShiftUpAnimation != null) {
+ mShiftUpAnimation.start();
+ }
+ }
+
+ // reveal splash screen, shift up main window
+ private void prepareRevealAnimation() {
+ // splash screen
+ mMainAnimator = ValueAnimator.ofFloat(0f, 1f);
+ mMainAnimator.setDuration(mAppDuration);
+ mMainAnimator.setInterpolator(APP_EXIT_INTERPOLATOR);
+ mMainAnimator.addListener(this);
+
+ final int startDelay = mIconDuration + EXTRA_REVEAL_DELAY;
+ final float transparentRatio = 0.95f;
+ final int globalHeight = mSplashScreenView.getHeight();
+ final int verticalCircleCenter = 0;
+ final int finalVerticalLength = globalHeight - verticalCircleCenter;
+ final int halfWidth = mSplashScreenView.getWidth() / 2;
+ final int endRadius = (int) (0.5 + (1f / transparentRatio * (int)
+ Math.sqrt(finalVerticalLength * finalVerticalLength + halfWidth * halfWidth)));
+ final RadialVanishAnimation radialVanishAnimation = new RadialVanishAnimation(
+ mSplashScreenView, mMainAnimator);
+ radialVanishAnimation.setCircleCenter(halfWidth, verticalCircleCenter);
+ radialVanishAnimation.setRadius(0/* initRadius */, endRadius);
+ final int[] colors = {Color.TRANSPARENT, Color.TRANSPARENT, Color.WHITE};
+ final float[] stops = {0f, transparentRatio, 1f};
+ radialVanishAnimation.setRadialPaintParam(colors, stops);
+ radialVanishAnimation.setReady();
+ mMainAnimator.setStartDelay(startDelay);
+
+ if (mFirstWindowSurface != null) {
+ // shift up main window
+ View occludeHoleView = new View(mSplashScreenView.getContext());
+ if (DEBUG_EXIT_ANIMATION_BLEND) {
+ occludeHoleView.setBackgroundColor(Color.BLUE);
+ } else {
+ occludeHoleView.setBackgroundColor(mSplashScreenView.getInitBackgroundColor());
+ }
+ final ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
+ WindowManager.LayoutParams.MATCH_PARENT, mMainWindowShiftLength);
+ mSplashScreenView.addView(occludeHoleView, params);
+
+ mShiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength);
+ mShiftUpAnimation.setDuration(mAppDuration);
+ mShiftUpAnimation.setInterpolator(APP_EXIT_INTERPOLATOR);
+ mShiftUpAnimation.setStartOffset(startDelay);
+
+ occludeHoleView.setAnimation(mShiftUpAnimation);
+ }
+ }
+
+ // shift down icon and branding view
+ private void prepareShiftAnimation() {
+ final View iconView = mSplashScreenView.getIconView();
+ if (iconView == null) {
+ return;
+ }
+ if (mIconShiftLength > 0) {
+ mIconAnimationSet = new AnimationSet(true /* shareInterpolator */);
+ if (DEBUG_EXIT_ANIMATION) {
+ Slog.v(TAG, "first exit animation, shift length: " + mIconShiftLength);
+ }
+ mIconAnimationSet.addAnimation(new TranslateYAnimation(0, mIconShiftLength));
+ mIconAnimationSet.addAnimation(new AlphaAnimation(1, 0));
+ mIconAnimationSet.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (DEBUG_EXIT_ANIMATION) {
+ Slog.v(TAG, "first exit animation finished");
+ }
+ iconView.post(() -> iconView.setVisibility(GONE));
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ // ignore
+ }
+ });
+ mIconAnimationSet.setDuration(mIconDuration);
+ mIconAnimationSet.setInterpolator(ICON_EXIT_INTERPOLATOR);
+ iconView.setAnimation(mIconAnimationSet);
+ final View brandingView = mSplashScreenView.getBrandingView();
+ if (brandingView != null) {
+ brandingView.setAnimation(mIconAnimationSet);
+ }
+ }
+ }
+
+ private static class RadialVanishAnimation extends View {
+ private SplashScreenView mView;
+ private int mInitRadius;
+ private int mFinishRadius;
+ private boolean mReady;
+
+ private final Point mCircleCenter = new Point();
+ private final Matrix mVanishMatrix = new Matrix();
+ private final Paint mVanishPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ RadialVanishAnimation(SplashScreenView target, ValueAnimator animator) {
+ super(target.getContext());
+ mView = target;
+ animator.addUpdateListener((animation) -> {
+ if (mVanishPaint.getShader() == null) {
+ return;
+ }
+ final float value = (float) animation.getAnimatedValue();
+ final float scale = (mFinishRadius - mInitRadius) * value + mInitRadius;
+ mVanishMatrix.setScale(scale, scale);
+ mVanishMatrix.postTranslate(mCircleCenter.x, mCircleCenter.y);
+ mVanishPaint.getShader().setLocalMatrix(mVanishMatrix);
+ mView.postInvalidate();
+ });
+ mView.addView(this);
+ }
+
+ void setRadius(int initRadius, int finishRadius) {
+ if (DEBUG_EXIT_ANIMATION) {
+ Slog.v(TAG, "RadialVanishAnimation setRadius init: " + initRadius
+ + " final " + finishRadius);
+ }
+ mInitRadius = initRadius;
+ mFinishRadius = finishRadius;
+ }
+
+ void setCircleCenter(int x, int y) {
+ if (DEBUG_EXIT_ANIMATION) {
+ Slog.v(TAG, "RadialVanishAnimation setCircleCenter x: " + x + " y " + y);
+ }
+ mCircleCenter.set(x, y);
+ }
+
+ void setRadialPaintParam(int[] colors, float[] stops) {
+ // setup gradient shader
+ final RadialGradient rShader =
+ new RadialGradient(0, 0, 1, colors, stops, Shader.TileMode.CLAMP);
+ mVanishPaint.setShader(rShader);
+ if (!DEBUG_EXIT_ANIMATION_BLEND) {
+ mVanishPaint.setBlendMode(BlendMode.MODULATE);
+ }
+ }
+
+ void setReady() {
+ mReady = true;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mReady) {
+ canvas.drawRect(0, 0, mView.getWidth(), mView.getHeight(), mVanishPaint);
+ }
+ }
+ }
+
+ private final class ShiftUpAnimation extends TranslateYAnimation {
+ ShiftUpAnimation(float fromYDelta, float toYDelta) {
+ super(fromYDelta, toYDelta);
+ }
+
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ super.applyTransformation(interpolatedTime, t);
+
+ if (mFirstWindowSurface == null) {
+ return;
+ }
+ mTmpTransform.set(t.getMatrix());
+ final SurfaceControl.Transaction tx = mTransactionPool.acquire();
+ mTmpTransform.postTranslate(mFirstWindowFrame.left,
+ mFirstWindowFrame.top + mMainWindowShiftLength);
+ tx.setMatrix(mFirstWindowSurface, mTmpTransform, mTmpFloat9);
+ // TODO set the vsyncId to ensure the transaction doesn't get applied too early.
+ // Additionally, do you want to have this synchronized with your view animations?
+ // If so, you'll need to use SyncRtSurfaceTransactionApplier
+ tx.apply();
+ mTransactionPool.release(tx);
+ }
+ }
+
+ private void reset() {
+ if (DEBUG_EXIT_ANIMATION) {
+ Slog.v(TAG, "vanish animation finished");
+ }
+ mSplashScreenView.post(() -> {
+ mSplashScreenView.setVisibility(GONE);
+ if (mFinishCallback != null) {
+ mFinishCallback.run();
+ mFinishCallback = null;
+ }
+ });
+ if (mFirstWindowSurface != null) {
+ final SurfaceControl.Transaction tx = mTransactionPool.acquire();
+ tx.setWindowCrop(mFirstWindowSurface, null);
+ tx.apply();
+ mFirstWindowSurface.release();
+ mFirstWindowSurface = null;
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // ignore
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ reset();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ reset();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ // ignore
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 2973b5080ae6..3f9c2717731a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -31,12 +31,14 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.util.Slog;
+import android.view.SurfaceControl;
import android.window.SplashScreenView;
import com.android.internal.R;
import com.android.internal.graphics.palette.Palette;
import com.android.internal.graphics.palette.Quantizer;
import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
+import com.android.wm.shell.common.TransactionPool;
import java.util.List;
@@ -56,15 +58,25 @@ public class SplashscreenContentDrawer {
// also 108*108 pixels, then do not enlarge this icon if only need to show foreground icon.
private static final float ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f);
private final Context mContext;
- private final int mMaxIconAnimationDuration;
+ private final int mMaxAnimatableIconDuration;
private int mIconSize;
private int mBrandingImageWidth;
private int mBrandingImageHeight;
-
- SplashscreenContentDrawer(Context context, int maxIconAnimationDuration) {
+ private final int mAppRevealDuration;
+ private final int mIconExitDuration;
+ private int mMainWindowShiftLength;
+ private int mIconNormalExitDistance;
+ private int mIconEarlyExitDistance;
+ private final TransactionPool mTransactionPool;
+
+ SplashscreenContentDrawer(Context context, int maxAnimatableIconDuration,
+ int iconExitAnimDuration, int appRevealAnimDuration, TransactionPool pool) {
mContext = context;
- mMaxIconAnimationDuration = maxIconAnimationDuration;
+ mMaxAnimatableIconDuration = maxAnimatableIconDuration;
+ mAppRevealDuration = appRevealAnimDuration;
+ mIconExitDuration = iconExitAnimDuration;
+ mTransactionPool = pool;
}
private void updateDensity() {
@@ -74,6 +86,12 @@ public class SplashscreenContentDrawer {
com.android.wm.shell.R.dimen.starting_surface_brand_image_width);
mBrandingImageHeight = mContext.getResources().getDimensionPixelSize(
com.android.wm.shell.R.dimen.starting_surface_brand_image_height);
+ mMainWindowShiftLength = mContext.getResources().getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.starting_surface_exit_animation_window_shift_length);
+ mIconNormalExitDistance = mContext.getResources().getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.starting_surface_normal_exit_icon_distance);
+ mIconEarlyExitDistance = mContext.getResources().getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.starting_surface_early_exit_icon_distance);
}
private int getSystemBGColor() {
@@ -119,7 +137,7 @@ public class SplashscreenContentDrawer {
if (attrs.mReplaceIcon != null) {
iconDrawable = attrs.mReplaceIcon;
animationDuration = Math.max(0,
- Math.min(attrs.mAnimationDuration, mMaxIconAnimationDuration));
+ Math.min(attrs.mAnimationDuration, mMaxAnimatableIconDuration));
} else {
iconDrawable = iconRes != 0 ? context.getDrawable(iconRes)
: context.getPackageManager().getDefaultActivityIcon();
@@ -439,8 +457,8 @@ public class SplashscreenContentDrawer {
}
/**
- * For ColorDrawable only.
- * There will be only one color so don't spend too much resource for it.
+ * For ColorDrawable only. There will be only one color so don't spend too much resource for
+ * it.
*/
private static class SingleColorTester implements ColorTester {
private final ColorDrawable mColorDrawable;
@@ -472,9 +490,8 @@ public class SplashscreenContentDrawer {
}
/**
- * For any other Drawable except ColorDrawable.
- * This will use the Palette API to check the color information and use a quantizer to
- * filter out transparent colors when needed.
+ * For any other Drawable except ColorDrawable. This will use the Palette API to check the
+ * color information and use a quantizer to filter out transparent colors when needed.
*/
private static class ComplexDrawableTester implements ColorTester {
private static final int MAX_BITMAP_SIZE = 40;
@@ -593,4 +610,17 @@ public class SplashscreenContentDrawer {
}
}
}
+
+ /**
+ * Create and play the default exit animation for splash screen view.
+ */
+ void applyExitAnimation(SplashScreenView view, SurfaceControl leash,
+ Rect frame, boolean isEarlyExit, Runnable finishCallback) {
+ final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(view, leash,
+ frame, mAppRevealDuration, mIconExitDuration, mMainWindowShiftLength,
+ isEarlyExit ? mIconEarlyExitDistance : mIconNormalExitDistance, mTransactionPool,
+ finishCallback);
+ animation.prepareAnimations();
+ animation.startAnimations();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
index a594a9f31dde..f258286f2d17 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -16,7 +16,9 @@
package com.android.wm.shell.startingsurface;
+import android.graphics.Rect;
import android.os.IBinder;
+import android.view.SurfaceControl;
import android.window.StartingWindowInfo;
import java.util.function.BiConsumer;
@@ -31,7 +33,8 @@ public interface StartingSurface {
/**
* Called when the content of a task is ready to show, starting window can be removed.
*/
- void removeStartingWindow(int taskId);
+ void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation);
/**
* Called when the Task wants to copy the splash screen.
* @param taskId
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 2d1d65b87718..14fbaacb9613 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -29,14 +29,18 @@ import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
+import android.os.SystemClock;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.Choreographer;
import android.view.Display;
+import android.view.SurfaceControl;
import android.view.View;
-import android.view.Window;
import android.view.WindowManager;
import android.window.SplashScreenView;
import android.window.SplashScreenView.SplashScreenViewParcelable;
@@ -46,6 +50,7 @@ import android.window.TaskSnapshot;
import com.android.internal.R;
import com.android.internal.policy.PhoneWindow;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TransactionPool;
import java.util.function.Consumer;
@@ -62,23 +67,23 @@ public class StartingSurfaceDrawer {
private final DisplayManager mDisplayManager;
private final ShellExecutor mSplashScreenExecutor;
private final SplashscreenContentDrawer mSplashscreenContentDrawer;
- protected Choreographer mChoreographer;
// TODO(b/131727939) remove this when clearing ActivityRecord
private static final int REMOVE_WHEN_TIMEOUT = 2000;
- public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor) {
+ public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor,
+ TransactionPool pool) {
mContext = context;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mSplashScreenExecutor = splashScreenExecutor;
- final int maxIconAnimDuration = context.getResources().getInteger(
+ final int maxAnimatableIconDuration = context.getResources().getInteger(
com.android.wm.shell.R.integer.max_starting_window_intro_icon_anim_duration);
- mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, maxIconAnimDuration);
- mSplashScreenExecutor.execute(this::initChoreographer);
- }
-
- protected void initChoreographer() {
- mChoreographer = Choreographer.getInstance();
+ final int iconExitAnimDuration = context.getResources().getInteger(
+ com.android.wm.shell.R.integer.starting_window_icon_exit_anim_duration);
+ final int appRevealAnimDuration = context.getResources().getInteger(
+ com.android.wm.shell.R.integer.starting_window_app_reveal_anim_duration);
+ mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext,
+ maxAnimatableIconDuration, iconExitAnimDuration, appRevealAnimDuration, pool);
}
private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
@@ -195,6 +200,7 @@ public class StartingSurfaceDrawer {
}
final PhoneWindow win = new PhoneWindow(context);
+ win.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
win.setIsStartingWindow(true);
CharSequence label = context.getResources().getText(labelRes, null);
@@ -211,7 +217,7 @@ public class StartingSurfaceDrawer {
// the keyguard is being hidden. This is okay because starting windows never show
// secret information.
// TODO(b/113840485): Occluded may not only happen on default display
- if (displayId == DEFAULT_DISPLAY) {
+ if (displayId == DEFAULT_DISPLAY && windowInfo.isKeyguardOccluded) {
windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
}
@@ -247,6 +253,7 @@ public class StartingSurfaceDrawer {
// Setting as trusted overlay to let touches pass through. This is safe because this
// window is controlled by the system.
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+ params.format = PixelFormat.RGBA_8888;
final Resources res = context.getResources();
final boolean supportsScreen = res != null && (res.getCompatibilityInfo() != null
@@ -257,98 +264,25 @@ public class StartingSurfaceDrawer {
params.setTitle("Splash Screen " + activityInfo.packageName);
- // TODO(b/173975965) If the target activity doesn't request FLAG_HARDWARE_ACCELERATED, we
- // cannot replace the content view after first view was drawn, sounds like an issue.
- new AddSplashScreenViewRunnable(taskInfo.taskId, win, context, appToken, params, iconRes,
- splashscreenContentResId[0], enableHardAccelerated).run();
- }
-
- private class AddSplashScreenViewRunnable implements Runnable {
- private final int mTaskId;
- private final Window mWin;
- private final IBinder mAppToken;
- private final WindowManager.LayoutParams mLayoutParams;
- private final Context mContext;
- private final int mIconRes;
- private final int mSplashscreenContentResId;
- private final boolean mReplaceSplashScreenView;
- private int mSequence;
-
- AddSplashScreenViewRunnable(int taskId, Window window, Context context,
- IBinder appToken, WindowManager.LayoutParams params, int iconRes,
- int splashscreenContentResId, boolean replaceSplashScreenView) {
- mTaskId = taskId;
- mWin = window;
- mAppToken = appToken;
- mContext = context;
- mLayoutParams = params;
- mIconRes = iconRes;
- mSplashscreenContentResId = splashscreenContentResId;
- mReplaceSplashScreenView = replaceSplashScreenView;
- }
-
- private void createInitialView() {
- View tempView = new View(mContext);
- mWin.setContentView(tempView);
- mSequence++;
- final View view = mWin.getDecorView();
- final WindowManager wm = mContext.getSystemService(WindowManager.class);
- if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) {
- mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, this, null);
- }
- }
-
- private SplashScreenView replaceRealView() {
- final SplashScreenView sView =
- mSplashscreenContentDrawer.makeSplashScreenContentView(mContext,
- mIconRes, mSplashscreenContentResId);
- mWin.setContentView(sView);
- sView.cacheRootWindow(mWin);
- return sView;
- }
-
- private SplashScreenView initiateOnce() {
- final SplashScreenView sView =
- mSplashscreenContentDrawer.makeSplashScreenContentView(mContext, mIconRes,
- mSplashscreenContentResId);
- final View view = mWin.getDecorView();
+ // TODO(b/173975965) tracking performance
+ final int taskId = taskInfo.taskId;
+ SplashScreenView sView = null;
+ try {
+ sView = mSplashscreenContentDrawer.makeSplashScreenContentView(context, iconRes,
+ splashscreenContentResId[0]);
+ final View view = win.getDecorView();
final WindowManager wm = mContext.getSystemService(WindowManager.class);
- if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) {
- mWin.setContentView(sView);
- sView.cacheRootWindow(mWin);
- }
- return sView;
- }
-
- @Override
- public void run() {
- SplashScreenView view = null;
- boolean setRecord = false;
- try {
- if (mReplaceSplashScreenView) {
- // Tricky way to make animation start faster... create the real content after
- // first window drawn. The first empty window won't been see because wm will
- // still need to wait for transition ready.
- if (mSequence == 0) {
- createInitialView();
- } else if (mSequence == 1) {
- setRecord = true;
- view = replaceRealView();
- }
- } else {
- setRecord = true;
- view = initiateOnce();
- }
- } catch (RuntimeException e) {
- // don't crash if something else bad happens, for example a
- // failure loading resources because we are loading from an app
- // on external storage that has been unmounted.
- Slog.w(TAG, " failed creating starting window", e);
- } finally {
- if (setRecord) {
- setSplashScreenRecord(mTaskId, view);
- }
+ if (postAddWindow(taskId, appToken, view, wm, params)) {
+ win.setContentView(sView);
+ sView.cacheRootWindow(win);
}
+ } catch (RuntimeException e) {
+ // don't crash if something else bad happens, for example a
+ // failure loading resources because we are loading from an app
+ // on external storage that has been unmounted.
+ Slog.w(TAG, " failed creating starting window", e);
+ } finally {
+ setSplashScreenRecord(taskId, sView);
}
}
@@ -359,8 +293,10 @@ public class StartingSurfaceDrawer {
TaskSnapshot snapshot) {
final int taskId = startingWindowInfo.taskInfo.taskId;
final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
- snapshot, mSplashScreenExecutor, () -> removeWindowSynced(taskId));
- mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+ snapshot, mSplashScreenExecutor,
+ () -> removeWindowNoAnimate(taskId));
+ mSplashScreenExecutor.executeDelayed(() -> removeWindowNoAnimate(taskId),
+ REMOVE_WHEN_TIMEOUT);
final StartingWindowRecord tView =
new StartingWindowRecord(null/* decorView */, surface);
mStartingWindowRecords.put(taskId, tView);
@@ -369,11 +305,12 @@ public class StartingSurfaceDrawer {
/**
* Called when the content of a task is ready to show, starting window can be removed.
*/
- public void removeStartingWindow(int taskId) {
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId);
}
- removeWindowSynced(taskId);
+ removeWindowSynced(taskId, leash, frame, playRevealAnimation);
}
/**
@@ -383,13 +320,6 @@ public class StartingSurfaceDrawer {
public void copySplashScreenView(int taskId) {
final StartingWindowRecord preView = mStartingWindowRecords.get(taskId);
SplashScreenViewParcelable parcelable;
- if (preView != null) {
- if (preView.isWaitForContent()) {
- mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
- () -> copySplashScreenView(taskId), null);
- return;
- }
- }
if (preView != null && preView.mContentView != null
&& preView.mContentView.isCopyable()) {
parcelable = new SplashScreenViewParcelable(preView.mContentView);
@@ -413,12 +343,6 @@ public class StartingSurfaceDrawer {
Slog.w(TAG, appToken + " already running, starting window not displayed. "
+ e.getMessage());
shouldSaveView = false;
- } catch (RuntimeException e) {
- // don't crash if something else bad happens, for example a
- // failure loading resources because we are loading from an app
- // on external storage that has been unmounted.
- Slog.w(TAG, appToken + " failed creating starting window", e);
- shouldSaveView = false;
} finally {
if (view != null && view.getParent() == null) {
Slog.w(TAG, "view not successfully added to wm, removing view");
@@ -427,9 +351,9 @@ public class StartingSurfaceDrawer {
}
}
if (shouldSaveView) {
- removeWindowSynced(taskId);
- mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId),
- REMOVE_WHEN_TIMEOUT);
+ removeWindowNoAnimate(taskId);
+ mSplashScreenExecutor.executeDelayed(
+ () -> removeWindowNoAnimate(taskId), REMOVE_WHEN_TIMEOUT);
saveSplashScreenRecord(taskId, view);
}
return shouldSaveView;
@@ -449,24 +373,30 @@ public class StartingSurfaceDrawer {
}
}
- protected void removeWindowSynced(int taskId) {
+ private void removeWindowNoAnimate(int taskId) {
+ removeWindowSynced(taskId, null, null, false);
+ }
+
+ protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
if (record != null) {
- if (record.isWaitForContent()) {
- if (DEBUG_SPLASH_SCREEN) {
- Slog.v(TAG, "splash screen window haven't been draw yet");
- }
- mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
- () -> removeWindowSynced(taskId), null);
- return;
- }
if (record.mDecorView != null) {
if (DEBUG_SPLASH_SCREEN) {
Slog.v(TAG, "Removing splash screen window for task: " + taskId);
}
- final WindowManager wm = record.mDecorView.getContext()
- .getSystemService(WindowManager.class);
- wm.removeView(record.mDecorView);
+ if (record.mContentView != null) {
+ final HandleExitFinish exitFinish = new HandleExitFinish(record.mDecorView);
+ if (leash != null || playRevealAnimation) {
+ mSplashscreenContentDrawer.applyExitAnimation(record.mContentView,
+ leash, frame, record.isEarlyExit(), exitFinish);
+ mSplashScreenExecutor.executeDelayed(exitFinish, REMOVE_WHEN_TIMEOUT);
+ } else {
+ // the SplashScreenView has been copied to client, skip default exit
+ // animation
+ exitFinish.run();
+ }
+ }
}
if (record.mTaskSnapshotWindow != null) {
if (DEBUG_TASK_SNAPSHOT) {
@@ -478,6 +408,26 @@ public class StartingSurfaceDrawer {
}
}
+ private static class HandleExitFinish implements Runnable {
+ private View mDecorView;
+
+ HandleExitFinish(View decorView) {
+ mDecorView = decorView;
+ }
+
+ @Override
+ public void run() {
+ if (mDecorView == null) {
+ return;
+ }
+ final WindowManager wm = mDecorView.getContext().getSystemService(WindowManager.class);
+ if (wm != null) {
+ wm.removeView(mDecorView);
+ }
+ mDecorView = null;
+ }
+ }
+
private void getWindowResFromContext(Context ctx, Consumer<TypedArray> consumer) {
final TypedArray a = ctx.obtainStyledAttributes(R.styleable.Window);
consumer.accept(a);
@@ -488,10 +438,12 @@ public class StartingSurfaceDrawer {
* Record the view or surface for a starting window.
*/
private static class StartingWindowRecord {
+ private static final long EARLY_START_MINIMUM_TIME_MS = 250;
private final View mDecorView;
private final TaskSnapshotWindow mTaskSnapshotWindow;
private SplashScreenView mContentView;
private boolean mSetSplashScreen;
+ private long mContentCreateTime;
StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
mDecorView = decorView;
@@ -503,11 +455,12 @@ public class StartingSurfaceDrawer {
return;
}
mContentView = splashScreenView;
+ mContentCreateTime = SystemClock.uptimeMillis();
mSetSplashScreen = true;
}
- private boolean isWaitForContent() {
- return mDecorView != null && !mSetSplashScreen;
+ boolean isEarlyExit() {
+ return SystemClock.uptimeMillis() - mContentCreateTime < EARLY_START_MINIMUM_TIME_MS;
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index 5eb7071fbd63..a694e525a761 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -28,14 +28,17 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
+import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import android.view.SurfaceControl;
import android.window.StartingWindowInfo;
import android.window.TaskOrganizer;
import android.window.TaskSnapshot;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TransactionPool;
import java.util.function.BiConsumer;
@@ -67,8 +70,16 @@ public class StartingWindowController {
private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
private final ShellExecutor mSplashScreenExecutor;
+ // For Car Launcher
public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) {
- mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor);
+ mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor,
+ new TransactionPool());
+ mSplashScreenExecutor = splashScreenExecutor;
+ }
+
+ public StartingWindowController(Context context, ShellExecutor splashScreenExecutor,
+ TransactionPool pool) {
+ mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool);
mSplashScreenExecutor = splashScreenExecutor;
}
@@ -112,7 +123,8 @@ public class StartingWindowController {
+ " allowTaskSnapshot " + allowTaskSnapshot
+ " activityCreated " + activityCreated);
}
- if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+ if ((newTask || !processRunning || (taskSwitch && !activityCreated))
+ && windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
}
if (taskSwitch && allowTaskSnapshot) {
@@ -198,8 +210,9 @@ public class StartingWindowController {
/**
* Called when the content of a task is ready to show, starting window can be removed.
*/
- void removeStartingWindow(int taskId) {
- mStartingSurfaceDrawer.removeStartingWindow(taskId);
+ void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
+ mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
}
private class StartingSurfaceImpl implements StartingSurface {
@@ -211,9 +224,11 @@ public class StartingWindowController {
}
@Override
- public void removeStartingWindow(int taskId) {
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
mSplashScreenExecutor.execute(() ->
- StartingWindowController.this.removeStartingWindow(taskId));
+ StartingWindowController.this.removeStartingWindow(taskId, leash, frame,
+ playRevealAnimation));
}
@Override
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index f06d57c6c789..ad4ccc0288ad 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -11,6 +11,8 @@
<option name="force-skip-system-props" value="true" />
<!-- set WM tracing verbose level to all -->
<option name="run-command" value="cmd window tracing level all" />
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame" />
<!-- restart launcher to activate TAPL -->
<option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
</target_preparer>
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index a531ef58725d..207db9e80511 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package unittest.src.com.android.wm.shell.startingsurface;
+package com.android.wm.shell.startingsurface;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -33,11 +33,12 @@ import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.testing.TestableContext;
-import android.view.Choreographer;
+import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowMetrics;
@@ -49,7 +50,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
+import com.android.wm.shell.common.TransactionPool;
import org.junit.Before;
import org.junit.Test;
@@ -68,7 +69,7 @@ public class StartingSurfaceDrawerTests {
@Mock
private WindowManager mMockWindowManager;
@Mock
- private static Choreographer sFakeChoreographer;
+ private TransactionPool mTransactionPool;
TestStartingSurfaceDrawer mStartingSurfaceDrawer;
@@ -76,13 +77,9 @@ public class StartingSurfaceDrawerTests {
int mAddWindowForTask = 0;
int mViewThemeResId;
- TestStartingSurfaceDrawer(Context context, ShellExecutor executor) {
- super(context, executor);
- }
-
- @Override
- protected void initChoreographer() {
- mChoreographer = sFakeChoreographer;
+ TestStartingSurfaceDrawer(Context context, ShellExecutor animExecutor,
+ TransactionPool pool) {
+ super(context, animExecutor, pool);
}
@Override
@@ -95,7 +92,8 @@ public class StartingSurfaceDrawerTests {
}
@Override
- protected void removeWindowSynced(int taskId) {
+ protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
// listen for removeView
if (mAddWindowForTask == taskId) {
mAddWindowForTask = 0;
@@ -123,7 +121,8 @@ public class StartingSurfaceDrawerTests {
doNothing().when(mMockWindowManager).addView(any(), any());
mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context,
- new HandlerExecutor(new Handler(Looper.getMainLooper()))));
+ new HandlerExecutor(new Handler(Looper.getMainLooper())),
+ mTransactionPool));
}
@Test
@@ -137,9 +136,9 @@ public class StartingSurfaceDrawerTests {
verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
- mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId);
+ mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId, null, null, false);
waitHandlerIdle(mainLoop);
- verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId));
+ verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId), any(), any(), eq(false));
assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, 0);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
index 27e5f51d88b8..b908df20d3c0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package unittest.src.com.android.wm.shell.startingsurface;
+package com.android.wm.shell.startingsurface;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -48,7 +48,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.TestShellExecutor;
-import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index a8f1a4d2a7f8..243e4ca4295a 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -143,6 +143,7 @@ package android.net {
public static class ConnectivityManager.NetworkCallback {
ctor public ConnectivityManager.NetworkCallback();
+ ctor public ConnectivityManager.NetworkCallback(int);
method public void onAvailable(@NonNull android.net.Network);
method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
@@ -150,6 +151,7 @@ package android.net {
method public void onLosing(@NonNull android.net.Network, int);
method public void onLost(@NonNull android.net.Network);
method public void onUnavailable();
+ field public static final int FLAG_INCLUDE_LOCATION_INFO = 1; // 0x1
}
public static interface ConnectivityManager.OnNetworkActiveListener {
@@ -293,6 +295,7 @@ package android.net {
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
method public int getOwnerUid();
method public int getSignalStrength();
+ method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @Nullable public android.net.TransportInfo getTransportInfo();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
@@ -399,6 +402,11 @@ package android.net {
method public android.net.NetworkRequest.Builder removeTransportType(int);
method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
+ method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ field public String response;
}
public class ProxyInfo implements android.os.Parcelable {
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index 5b64d5239cda..4b3336644ef9 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -7,6 +7,7 @@ package android.net {
public class ConnectivityManager {
method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshot();
+ method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index a732430e6a9c..a98f14ea9408 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -296,6 +296,7 @@ package android.net {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
+ method @NonNull public android.net.NetworkCapabilities.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 3314af530e9b..7189be10d8f4 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -16,7 +16,6 @@
package android.net;
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.IpSecManager.INVALID_RESOURCE_ID;
import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
import static android.net.NetworkRequest.Type.LISTEN;
import static android.net.NetworkRequest.Type.REQUEST;
@@ -44,6 +43,7 @@ import android.net.SocketKeepalive.Callback;
import android.net.TetheringManager.StartTetheringCallback;
import android.net.TetheringManager.TetheringEventCallback;
import android.net.TetheringManager.TetheringRequest;
+import android.net.wifi.WifiNetworkSuggestion;
import android.os.Binder;
import android.os.Build;
import android.os.Build.VERSION_CODES;
@@ -1315,7 +1315,7 @@ public class ConnectivityManager {
}
/**
- * Returns an array of {@link android.net.NetworkCapabilities} objects, representing
+ * Returns an array of {@link NetworkCapabilities} objects, representing
* the Networks that applications run by the given user will use by default.
* @hide
*/
@@ -1395,11 +1395,19 @@ public class ConnectivityManager {
}
/**
- * Get the {@link android.net.NetworkCapabilities} for the given {@link Network}. This
+ * Get the {@link NetworkCapabilities} for the given {@link Network}. This
* will return {@code null} if the network is unknown.
*
+ * This will remove any location sensitive data in {@link TransportInfo} embedded in
+ * {@link NetworkCapabilities#getTransportInfo()}. Some transport info instances like
+ * {@link android.net.wifi.WifiInfo} contain location sensitive information. Retrieving
+ * this location sensitive information (subject to app's location permissions) will be
+ * noted by system. To include any location sensitive data in {@link TransportInfo},
+ * use a {@link NetworkCallback} with
+ * {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} flag.
+ *
* @param network The {@link Network} object identifying the network in question.
- * @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}.
+ * @return The {@link NetworkCapabilities} for the network, or {@code null}.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@Nullable
@@ -1997,7 +2005,7 @@ public class ConnectivityManager {
dup = createInvalidFd();
}
return new NattSocketKeepalive(mService, network, dup,
- INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback);
+ -1 /* Unused */, source, destination, executor, callback);
}
/**
@@ -3245,6 +3253,54 @@ public class ConnectivityManager {
*/
public static class NetworkCallback {
/**
+ * No flags associated with this callback.
+ * @hide
+ */
+ public static final int FLAG_NONE = 0;
+ /**
+ * Use this flag to include any location sensitive data in {@link NetworkCapabilities} sent
+ * via {@link #onCapabilitiesChanged(Network, NetworkCapabilities)}.
+ * <p>
+ * These include:
+ * <li> Some transport info instances (retrieved via
+ * {@link NetworkCapabilities#getTransportInfo()}) like {@link android.net.wifi.WifiInfo}
+ * contain location sensitive information.
+ * <li> OwnerUid (retrieved via {@link NetworkCapabilities#getOwnerUid()} is location
+ * sensitive for wifi suggestor apps (i.e using {@link WifiNetworkSuggestion}).</li>
+ * </p>
+ * <p>
+ * Note:
+ * <li> Retrieving this location sensitive information (subject to app's location
+ * permissions) will be noted by system. </li>
+ * <li> Without this flag any {@link NetworkCapabilities} provided via the callback does
+ * not include location sensitive info.
+ * </p>
+ */
+ public static final int FLAG_INCLUDE_LOCATION_INFO = 1 << 0;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = "FLAG_", value = {
+ FLAG_NONE,
+ FLAG_INCLUDE_LOCATION_INFO
+ })
+ public @interface Flag { }
+
+ /**
+ * All the valid flags for error checking.
+ */
+ private static final int VALID_FLAGS = FLAG_INCLUDE_LOCATION_INFO;
+
+ public NetworkCallback() {
+ this(FLAG_NONE);
+ }
+
+ public NetworkCallback(@Flag int flags) {
+ Preconditions.checkArgument((flags & VALID_FLAGS) == flags);
+ mFlags = flags;
+ }
+
+ /**
* Called when the framework connects to a new network to evaluate whether it satisfies this
* request. If evaluation succeeds, this callback may be followed by an {@link #onAvailable}
* callback. There is no guarantee that this new network will satisfy any requests, or that
@@ -3381,7 +3437,7 @@ public class ConnectivityManager {
* calling these methods while in a callback may return an outdated or even a null object.
*
* @param network The {@link Network} whose capabilities have changed.
- * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this
+ * @param networkCapabilities The new {@link NetworkCapabilities} for this
* network.
*/
public void onCapabilitiesChanged(@NonNull Network network,
@@ -3450,6 +3506,7 @@ public class ConnectivityManager {
public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {}
private NetworkRequest networkRequest;
+ private final int mFlags;
}
/**
@@ -3639,14 +3696,15 @@ public class ConnectivityManager {
}
Messenger messenger = new Messenger(handler);
Binder binder = new Binder();
+ final int callbackFlags = callback.mFlags;
if (reqType == LISTEN) {
request = mService.listenForNetwork(
- need, messenger, binder, callingPackageName,
+ need, messenger, binder, callbackFlags, callingPackageName,
getAttributionTag());
} else {
request = mService.requestNetwork(
need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
- callingPackageName, getAttributionTag());
+ callbackFlags, callingPackageName, getAttributionTag());
}
if (request != null) {
sCallbacks.put(request, callback);
@@ -3693,7 +3751,7 @@ public class ConnectivityManager {
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* <p>This method will attempt to find the best network that matches the passed
* {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
@@ -3777,7 +3835,7 @@ public class ConnectivityManager {
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* This method behaves identically to {@link #requestNetwork(NetworkRequest, NetworkCallback)}
* but runs all the callbacks on the passed Handler.
@@ -3799,7 +3857,7 @@ public class ConnectivityManager {
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+ * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
* by a timeout.
*
* This function behaves identically to the non-timed-out version
@@ -3834,7 +3892,7 @@ public class ConnectivityManager {
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+ * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
* by a timeout.
*
* This method behaves identically to
@@ -3879,7 +3937,7 @@ public class ConnectivityManager {
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* This function behaves identically to the version that takes a NetworkCallback, but instead
* of {@link NetworkCallback} a {@link PendingIntent} is used. This means
@@ -4911,7 +4969,7 @@ public class ConnectivityManager {
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but
+ * Request a network to satisfy a set of {@link NetworkCapabilities}, but
* does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can
* be used to request that the system provide a network without causing the network to be
* in the foreground.
@@ -5053,4 +5111,21 @@ public class ConnectivityManager {
throw e.rethrowFromSystemServer();
}
}
+
+ // The first network ID of IPSec tunnel interface.
+ private static final int TUN_INTF_NETID_START = 0xFC00;
+ // The network ID range of IPSec tunnel interface.
+ private static final int TUN_INTF_NETID_RANGE = 0x0400;
+
+ /**
+ * Get the network ID range reserved for IPSec tunnel interfaces.
+ *
+ * @return A Range which indicates the network ID range of IPSec tunnel interface.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @NonNull
+ public static Range<Integer> getIpSecNetIdRange() {
+ return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1);
+ }
}
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index cd49258d1c47..f9393e315b83 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -143,7 +143,7 @@ interface IConnectivityManager
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType,
in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
- String callingPackageName, String callingAttributionTag);
+ int callbackFlags, String callingPackageName, String callingAttributionTag);
NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
in PendingIntent operation, String callingPackageName, String callingAttributionTag);
@@ -151,7 +151,7 @@ interface IConnectivityManager
void releasePendingNetworkRequest(in PendingIntent operation);
NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
- in Messenger messenger, in IBinder binder, String callingPackageName,
+ in Messenger messenger, in IBinder binder, int callbackFlags, String callingPackageName,
String callingAttributionTag);
void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index c82cd3b4f357..058f3c999dd7 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.wifi.WifiNetworkSuggestion;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -131,6 +132,7 @@ public final class NetworkCapabilities implements Parcelable {
mPrivateDnsBroken = false;
mRequestorUid = Process.INVALID_UID;
mRequestorPackageName = null;
+ mSubIds = new ArraySet<>();
}
/**
@@ -159,6 +161,7 @@ public final class NetworkCapabilities implements Parcelable {
mPrivateDnsBroken = nc.mPrivateDnsBroken;
mRequestorUid = nc.mRequestorUid;
mRequestorPackageName = nc.mRequestorPackageName;
+ mSubIds = new ArraySet<>(nc.mSubIds);
}
/**
@@ -1048,6 +1051,16 @@ public final class NetworkCapabilities implements Parcelable {
*
* Instances of NetworkCapabilities sent to apps without the appropriate permissions will have
* this field cleared out.
+ *
+ * <p>
+ * This field will only be populated for VPN and wifi network suggestor apps (i.e using
+ * {@link WifiNetworkSuggestion}), and only for the network they own.
+ * In the case of wifi network suggestors apps, this field is also location sensitive, so the
+ * app needs to hold {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. If the
+ * app targets SDK version greater than or equal to {@link Build.VERSION_CODES#S}, then they
+ * also need to use {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} to get the info in their
+ * callback. The app will be blamed for location access if this field is included.
+ * </p>
*/
public int getOwnerUid() {
return mOwnerUid;
@@ -1655,6 +1668,7 @@ public final class NetworkCapabilities implements Parcelable {
combineSSIDs(nc);
combineRequestor(nc);
combineAdministratorUids(nc);
+ combineSubIds(nc);
}
/**
@@ -1674,8 +1688,9 @@ public final class NetworkCapabilities implements Parcelable {
&& satisfiedBySpecifier(nc)
&& (onlyImmutable || satisfiedBySignalStrength(nc))
&& (onlyImmutable || satisfiedByUids(nc))
- && (onlyImmutable || satisfiedBySSID(nc)))
- && (onlyImmutable || satisfiedByRequestor(nc));
+ && (onlyImmutable || satisfiedBySSID(nc))
+ && (onlyImmutable || satisfiedByRequestor(nc))
+ && (onlyImmutable || satisfiedBySubIds(nc)));
}
/**
@@ -1771,7 +1786,8 @@ public final class NetworkCapabilities implements Parcelable {
&& equalsOwnerUid(that)
&& equalsPrivateDnsBroken(that)
&& equalsRequestor(that)
- && equalsAdministratorUids(that);
+ && equalsAdministratorUids(that)
+ && equalsSubIds(that);
}
@Override
@@ -1793,7 +1809,8 @@ public final class NetworkCapabilities implements Parcelable {
+ Objects.hashCode(mPrivateDnsBroken) * 47
+ Objects.hashCode(mRequestorUid) * 53
+ Objects.hashCode(mRequestorPackageName) * 59
- + Arrays.hashCode(mAdministratorUids) * 61;
+ + Arrays.hashCode(mAdministratorUids) * 61
+ + Objects.hashCode(mSubIds) * 67;
}
@Override
@@ -1827,6 +1844,7 @@ public final class NetworkCapabilities implements Parcelable {
dest.writeInt(mOwnerUid);
dest.writeInt(mRequestorUid);
dest.writeString(mRequestorPackageName);
+ dest.writeIntArray(CollectionUtils.toIntArray(mSubIds));
}
public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1850,6 +1868,11 @@ public final class NetworkCapabilities implements Parcelable {
netCap.mOwnerUid = in.readInt();
netCap.mRequestorUid = in.readInt();
netCap.mRequestorPackageName = in.readString();
+ netCap.mSubIds = new ArraySet<>();
+ final int[] subIdInts = Objects.requireNonNull(in.createIntArray());
+ for (int i = 0; i < subIdInts.length; i++) {
+ netCap.mSubIds.add(subIdInts[i]);
+ }
return netCap;
}
@Override
@@ -1933,11 +1956,14 @@ public final class NetworkCapabilities implements Parcelable {
sb.append(" SSID: ").append(mSSID);
}
-
if (mPrivateDnsBroken) {
sb.append(" PrivateDnsBroken");
}
+ if (!mSubIds.isEmpty()) {
+ sb.append(" SubscriptionIds: ").append(mSubIds);
+ }
+
sb.append("]");
return sb.toString();
}
@@ -2251,6 +2277,67 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Set of the subscription IDs that identifies the network or request, empty if none.
+ */
+ @NonNull
+ private ArraySet<Integer> mSubIds = new ArraySet<>();
+
+ /**
+ * Sets the subscription ID set that associated to this network or request.
+ *
+ * @hide
+ */
+ @NonNull
+ public NetworkCapabilities setSubIds(@NonNull Set<Integer> subIds) {
+ mSubIds = new ArraySet(Objects.requireNonNull(subIds));
+ return this;
+ }
+
+ /**
+ * Gets the subscription ID set that associated to this network or request.
+ * @return
+ */
+ @NonNull
+ public Set<Integer> getSubIds() {
+ return new ArraySet<>(mSubIds);
+ }
+
+ /**
+ * Tests if the subscription ID set of this network is the same as that of the passed one.
+ */
+ private boolean equalsSubIds(@NonNull NetworkCapabilities nc) {
+ return Objects.equals(mSubIds, nc.mSubIds);
+ }
+
+ /**
+ * Check if the subscription ID set requirements of this object are matched by the passed one.
+ * If specified in the request, the passed one need to have at least one subId and at least
+ * one of them needs to be in the request set.
+ */
+ private boolean satisfiedBySubIds(@NonNull NetworkCapabilities nc) {
+ if (mSubIds.isEmpty()) return true;
+ if (nc.mSubIds.isEmpty()) return false;
+ for (final Integer subId : nc.mSubIds) {
+ if (mSubIds.contains(subId)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Combine subscription ID set of the capabilities.
+ *
+ * <p>This is only legal if the subscription Ids are equal.
+ *
+ * <p>If both subscription IDs are not equal, they belong to different subscription
+ * (or no subscription). In this case, it would not make sense to add them together.
+ */
+ private void combineSubIds(@NonNull NetworkCapabilities nc) {
+ if (!Objects.equals(mSubIds, nc.mSubIds)) {
+ throw new IllegalStateException("Can't combine two subscription ID sets");
+ }
+ }
+
+ /**
* Builder class for NetworkCapabilities.
*
* This class is mainly for for {@link NetworkAgent} instances to use. Many fields in
@@ -2556,6 +2643,18 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Set the subscription ID set.
+ *
+ * @param subIds a set that represent the subscription IDs. Empty if clean up.
+ * @return this builder.
+ */
+ @NonNull
+ public Builder setSubIds(@NonNull final Set<Integer> subIds) {
+ mCaps.setSubIds(subIds);
+ return this;
+ }
+
+ /**
* Builds the instance of the capabilities.
*
* @return the built instance of NetworkCapabilities.
diff --git a/packages/Connectivity/framework/src/android/net/NetworkInfo.java b/packages/Connectivity/framework/src/android/net/NetworkInfo.java
index d752901e2eb0..bb2349459331 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkInfo.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkInfo.java
@@ -21,7 +21,6 @@ import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.Annotation.NetworkType;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -164,7 +163,7 @@ public class NetworkInfo implements Parcelable {
* @param typeName a human-readable string for the network type, or an empty string or null.
* @param subtypeName a human-readable string for the subtype, or an empty string or null.
*/
- public NetworkInfo(int type, @NetworkType int subtype,
+ public NetworkInfo(int type, int subtype,
@Nullable String typeName, @Nullable String subtypeName) {
if (!ConnectivityManager.isNetworkTypeValid(type)
&& type != ConnectivityManager.TYPE_NONE) {
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index aa6975678adc..3fd95ee58df2 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -461,6 +461,21 @@ public class NetworkRequest implements Parcelable {
}
nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
}
+
+ /**
+ * Sets the optional subscription ID set.
+ * <p>
+ * This specify the subscription IDs requirement.
+ * A network will satisfy this request only if it matches one of the subIds in this set.
+ * An empty set matches all networks, including those without a subId.
+ *
+ * @param subIds A {@code Set} that represents subscription IDs.
+ */
+ @NonNull
+ public Builder setSubIds(@NonNull Set<Integer> subIds) {
+ mNetworkCapabilities.setSubIds(subIds);
+ return this;
+ }
}
// implement the Parcelable interface
diff --git a/packages/Connectivity/framework/src/android/net/NetworkState.java b/packages/Connectivity/framework/src/android/net/NetworkState.java
index d01026566ca0..9b69674728a8 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkState.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkState.java
@@ -22,7 +22,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Slog;
+import android.util.Log;
/**
* Snapshot of network state.
@@ -83,7 +83,7 @@ public class NetworkState implements Parcelable {
if (VALIDATE_ROAMING_STATE && networkInfo != null && networkCapabilities != null) {
if (networkInfo.isRoaming() == networkCapabilities
.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
- Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
+ Log.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
+ " and " + networkCapabilities);
}
}
diff --git a/core/java/android/net/ParseException.java b/packages/Connectivity/framework/src/android/net/ParseException.java
index bcfdd7ef09cc..bcfdd7ef09cc 100644
--- a/core/java/android/net/ParseException.java
+++ b/packages/Connectivity/framework/src/android/net/ParseException.java
diff --git a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
index d37c4691ddde..53d966937a70 100644
--- a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
+++ b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
@@ -92,7 +92,7 @@ public final class QosSocketInfo implements Parcelable {
Objects.requireNonNull(socket, "socket cannot be null");
mNetwork = Objects.requireNonNull(network, "network cannot be null");
- mParcelFileDescriptor = ParcelFileDescriptor.dup(socket.getFileDescriptor$());
+ mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket);
mLocalSocketAddress =
new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
}
@@ -114,10 +114,10 @@ public final class QosSocketInfo implements Parcelable {
try {
return new InetSocketAddress(InetAddress.getByAddress(address), port);
} catch (final UnknownHostException e) {
- /* The catch block was purposely left empty. UnknownHostException will never be thrown
+ /* This can never happen. UnknownHostException will never be thrown
since the address provided is numeric and non-null. */
+ throw new RuntimeException("UnknownHostException on numeric address", e);
}
- return new InetSocketAddress();
}
@Override
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index c1dca5df1b2f..16a946dc7bc6 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -138,9 +138,6 @@ public class DynamicSystemInstallationService extends Service
private long mCurrentPartitionSize;
private long mCurrentPartitionInstalledSize;
- private boolean mJustCancelledByUser;
- private boolean mKeepNotification;
-
// This is for testing only now
private boolean mEnableWhenCompleted;
@@ -174,11 +171,6 @@ public class DynamicSystemInstallationService extends Service
if (cache != null) {
cache.flush();
}
-
- if (!mKeepNotification) {
- // Cancel the persistent notification.
- mNM.cancel(NOTIFICATION_ID);
- }
}
@Override
@@ -231,9 +223,11 @@ public class DynamicSystemInstallationService extends Service
return;
}
+ boolean removeNotification = false;
switch (result) {
case RESULT_CANCELLED:
postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
+ removeNotification = true;
break;
case RESULT_ERROR_IO:
@@ -251,7 +245,7 @@ public class DynamicSystemInstallationService extends Service
}
// if it's not successful, reset the task and stop self.
- resetTaskAndStop();
+ resetTaskAndStop(removeNotification);
}
private void executeInstallCommand(Intent intent) {
@@ -302,12 +296,12 @@ public class DynamicSystemInstallationService extends Service
return;
}
- stopForeground(true);
- mJustCancelledByUser = true;
-
if (mInstallTask.cancel(false)) {
- // Will stopSelf() in onResult()
+ // onResult() would call resetTaskAndStop() upon task completion.
Log.d(TAG, "Cancel request filed successfully");
+ // Dismiss the notification as soon as possible as DynamicSystemManager.remove() may
+ // block.
+ stopForeground(STOP_FOREGROUND_REMOVE);
} else {
Log.e(TAG, "Trying to cancel installation while it's already completed.");
}
@@ -322,8 +316,7 @@ public class DynamicSystemInstallationService extends Service
if (!isDynamicSystemInstalled() && (getStatus() != STATUS_READY)) {
Log.e(TAG, "Trying to discard AOT while there is no complete installation");
// Stop foreground state and dismiss stale notification.
- stopForeground(STOP_FOREGROUND_REMOVE);
- resetTaskAndStop();
+ resetTaskAndStop(true);
return;
}
@@ -331,8 +324,8 @@ public class DynamicSystemInstallationService extends Service
getString(R.string.toast_dynsystem_discarded),
Toast.LENGTH_LONG).show();
- resetTaskAndStop();
postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
+ resetTaskAndStop(true);
mDynSystem.remove();
}
@@ -412,12 +405,13 @@ public class DynamicSystemInstallationService extends Service
}
private void resetTaskAndStop() {
- mInstallTask = null;
+ resetTaskAndStop(/* removeNotification= */ false);
+ }
- new Handler().postDelayed(() -> {
- stopForeground(STOP_FOREGROUND_DETACH);
- stopSelf();
- }, 50);
+ private void resetTaskAndStop(boolean removeNotification) {
+ mInstallTask = null;
+ stopForeground(removeNotification ? STOP_FOREGROUND_REMOVE : STOP_FOREGROUND_DETACH);
+ stopSelf();
}
private void prepareNotification() {
@@ -525,7 +519,7 @@ public class DynamicSystemInstallationService extends Service
private void postStatus(int status, int cause, Throwable detail) {
String statusString;
String causeString;
- mKeepNotification = false;
+ boolean notifyOnNotificationBar = true;
switch (status) {
case STATUS_NOT_STARTED:
@@ -551,18 +545,16 @@ public class DynamicSystemInstallationService extends Service
break;
case CAUSE_INSTALL_CANCELLED:
causeString = "INSTALL_CANCELLED";
+ notifyOnNotificationBar = false;
break;
case CAUSE_ERROR_IO:
causeString = "ERROR_IO";
- mKeepNotification = true;
break;
case CAUSE_ERROR_INVALID_URL:
causeString = "ERROR_INVALID_URL";
- mKeepNotification = true;
break;
case CAUSE_ERROR_EXCEPTION:
causeString = "ERROR_EXCEPTION";
- mKeepNotification = true;
break;
default:
causeString = "CAUSE_NOT_SPECIFIED";
@@ -571,16 +563,6 @@ public class DynamicSystemInstallationService extends Service
Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail);
- boolean notifyOnNotificationBar = true;
-
- if (status == STATUS_NOT_STARTED
- && cause == CAUSE_INSTALL_CANCELLED
- && mJustCancelledByUser) {
- // if task is cancelled by user, do not notify them
- notifyOnNotificationBar = false;
- mJustCancelledByUser = false;
- }
-
if (notifyOnNotificationBar) {
mNM.notify(NOTIFICATION_ID, buildNotification(status, cause, detail));
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a28a1e32a2a5..b4194fd5bbf9 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -426,6 +426,9 @@
<!-- Permission required for CTS test - ClipboardManagerTest -->
<uses-permission android:name="android.permission.SET_CLIP_SOURCE" />
+ <!-- Permission required for CTS test - FontManagerTest -->
+ <uses-permission android:name="android.permission.UPDATE_FONTS" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index ebb6e30d4b3b..e9e9b2421d4a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -289,15 +289,19 @@ public class Task {
/**
* Returns the visible width to height ratio. Returns 0f if snapshot data is not available.
*/
- public float getVisibleThumbnailRatio() {
+ public float getVisibleThumbnailRatio(boolean clipInsets) {
if (lastSnapshotData.taskSize == null || lastSnapshotData.contentInsets == null) {
return 0f;
}
- float availableWidth = lastSnapshotData.taskSize.x - (lastSnapshotData.contentInsets.left
- + lastSnapshotData.contentInsets.right);
- float availableHeight = lastSnapshotData.taskSize.y - (lastSnapshotData.contentInsets.top
- + lastSnapshotData.contentInsets.bottom);
+ float availableWidth = lastSnapshotData.taskSize.x;
+ float availableHeight = lastSnapshotData.taskSize.y;
+ if (clipInsets) {
+ availableWidth -=
+ (lastSnapshotData.contentInsets.left + lastSnapshotData.contentInsets.right);
+ availableHeight -=
+ (lastSnapshotData.contentInsets.top + lastSnapshotData.contentInsets.bottom);
+ }
return availableWidth / availableHeight;
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index a12326961b08..1b6c61237e29 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -480,8 +480,8 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static StartingWindowController provideStartingWindowController(Context context,
- @ShellSplashscreenThread ShellExecutor executor) {
- return new StartingWindowController(context, executor);
+ @ShellAnimationThread ShellExecutor executor, TransactionPool pool) {
+ return new StartingWindowController(context, executor, pool);
}
//
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 0eb7dafe2612..b00689be3656 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -98,7 +98,6 @@ java_library_static {
":platform-compat-overrides",
":display-device-config",
":display-layout-config",
- ":cec-config",
":device-state-config",
"java/com/android/server/EventLogTags.logtags",
"java/com/android/server/am/EventLogTags.logtags",
@@ -119,7 +118,6 @@ java_library_static {
],
required: [
- "cec_config.xml",
"gps_debug.conf",
"protolog.conf.json.gz",
],
@@ -185,11 +183,6 @@ java_library_host {
}
prebuilt_etc {
- name: "cec_config.xml",
- src: "java/com/android/server/hdmi/cec_config.xml",
-}
-
-prebuilt_etc {
name: "gps_debug.conf",
src: "java/com/android/server/location/gnss/gps_debug.conf",
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 72d32636f645..b4fcaeedd845 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -85,6 +85,7 @@ import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.DataStallReportParcelable;
import android.net.DnsResolverServiceManager;
import android.net.ICaptivePortal;
@@ -189,7 +190,6 @@ import android.util.SparseIntArray;
import com.android.connectivity.aidl.INetworkAgent;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
@@ -345,8 +345,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private String mCurrentTcpBufferSizes;
private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
- new Class[] { AsyncChannel.class, ConnectivityService.class, NetworkAgent.class,
- NetworkAgentInfo.class });
+ new Class[] { ConnectivityService.class, NetworkAgent.class, NetworkAgentInfo.class });
private enum ReapUnvalidatedNetworks {
// Tear down networks that have no chance (e.g. even if validated) of becoming
@@ -1108,7 +1107,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetworkRanker = new NetworkRanker();
final NetworkRequest defaultInternetRequest = createDefaultRequest();
mDefaultRequest = new NetworkRequestInfo(
- defaultInternetRequest, null, new Binder(),
+ defaultInternetRequest, null,
+ new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
mDefaultNetworkRequests.add(mDefaultRequest);
@@ -1358,7 +1358,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- networkRequest, null, new Binder(),
+ networkRequest, null,
+ new Binder(),
+ NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */));
} else {
handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
@@ -1719,8 +1721,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
result.put(
nai.network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, mDeps.getCallingUid(), callingPackageName,
- callingAttributionTag));
+ nc, false /* includeLocationSensitiveInfo */,
+ mDeps.getCallingUid(), callingPackageName, callingAttributionTag));
}
}
@@ -1733,7 +1735,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
result.put(
network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, mDeps.getCallingUid(), callingPackageName,
+ nc,
+ false /* includeLocationSensitiveInfo */,
+ mDeps.getCallingUid(), callingPackageName,
callingAttributionTag));
}
}
@@ -1815,6 +1819,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
enforceAccessPermission();
return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
getNetworkCapabilitiesInternal(network),
+ false /* includeLocationSensitiveInfo */,
mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
}
@@ -1848,8 +1853,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
@VisibleForTesting
@Nullable
NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName,
- @Nullable String callingAttributionTag) {
+ @Nullable NetworkCapabilities nc, boolean includeLocationSensitiveInfo,
+ int callerUid, @NonNull String callerPkgName, @Nullable String callingAttributionTag) {
if (nc == null) {
return null;
}
@@ -1857,7 +1862,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkCapabilities newNc;
// Avoid doing location permission check if the transport info has no location sensitive
// data.
- if (nc.getTransportInfo() != null && nc.getTransportInfo().hasLocationSensitiveFields()) {
+ if (includeLocationSensitiveInfo
+ && nc.getTransportInfo() != null
+ && nc.getTransportInfo().hasLocationSensitiveFields()) {
hasLocationPermission =
hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
newNc = new NetworkCapabilities(nc, hasLocationPermission);
@@ -1874,6 +1881,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Owner UIDs already checked above. No need to re-check.
return newNc;
}
+ // If the caller does not want location sensitive data & target SDK >= S, then mask info.
+ // Else include the owner UID iff the caller has location permission to provide backwards
+ // compatibility for older apps.
+ if (!includeLocationSensitiveInfo
+ && isTargetSdkAtleast(
+ Build.VERSION_CODES.S, callerUid, callerPkgName)) {
+ newNc.setOwnerUid(INVALID_UID);
+ return newNc;
+ }
+
if (hasLocationPermission == null) {
// Location permission not checked yet, check now for masking owner UID.
hasLocationPermission =
@@ -2892,22 +2909,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
super(looper);
}
- private boolean maybeHandleAsyncChannelMessage(Message msg) {
- switch (msg.what) {
- default:
- return false;
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
- handleAsyncChannelHalfConnect(msg);
- break;
- }
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
- handleAsyncChannelDisconnected(msg);
- break;
- }
- }
- return true;
- }
-
private void maybeHandleNetworkAgentMessage(Message msg) {
final Pair<NetworkAgentInfo, Object> arg = (Pair<NetworkAgentInfo, Object>) msg.obj;
final NetworkAgentInfo nai = arg.first;
@@ -3199,8 +3200,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public void handleMessage(Message msg) {
- if (!maybeHandleAsyncChannelMessage(msg)
- && !maybeHandleNetworkMonitorMessage(msg)
+ if (!maybeHandleNetworkMonitorMessage(msg)
&& !maybeHandleNetworkAgentInfoMessage(msg)) {
maybeHandleNetworkAgentMessage(msg);
}
@@ -3464,21 +3464,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return false;
}
- private void handleAsyncChannelHalfConnect(Message msg) {
- ensureRunningOnConnectivityServiceThread();
- if (mNetworkProviderInfos.containsKey(msg.replyTo)) {
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- if (VDBG) log("NetworkFactory connected");
- // Finish setting up the full connection
- NetworkProviderInfo npi = mNetworkProviderInfos.get(msg.replyTo);
- sendAllRequestsToProvider(npi);
- } else {
- loge("Error connecting NetworkFactory");
- mNetworkProviderInfos.remove(msg.obj);
- }
- }
- }
-
private void handleNetworkAgentRegistered(Message msg) {
final NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
if (!mNetworkAgentInfos.contains(nai)) {
@@ -3509,14 +3494,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- // This is a no-op if it's called with a message designating a provider that has
- // already been destroyed, because its reference will not be found in the relevant
- // maps.
- private void handleAsyncChannelDisconnected(Message msg) {
- NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo);
- if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name);
- }
-
// Destroys a network, remove references to it from the internal state managed by
// ConnectivityService, free its interfaces and clean up.
// Must be called on the Handler thread.
@@ -5159,8 +5136,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final IBinder.DeathRecipient mDeathRecipient;
public final int providerId;
- NetworkProviderInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
- int providerId, @NonNull IBinder.DeathRecipient deathRecipient) {
+ NetworkProviderInfo(String name, Messenger messenger, int providerId,
+ @NonNull IBinder.DeathRecipient deathRecipient) {
this.name = name;
this.messenger = messenger;
this.providerId = providerId;
@@ -5254,6 +5231,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final IBinder mBinder;
final int mPid;
final int mUid;
+ final @NetworkCallback.Flag int mCallbackFlags;
@Nullable
final String mCallingAttributionTag;
// In order to preserve the mapping of NetworkRequest-to-callback when apps register
@@ -5301,17 +5279,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ /**
+ * Location sensitive data not included in pending intent. Only included in
+ * {@link NetworkCallback}.
+ */
+ mCallbackFlags = NetworkCallback.FLAG_NONE;
mCallingAttributionTag = callingAttributionTag;
}
NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
- @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
- this(Collections.singletonList(r), r, m, binder, callingAttributionTag);
+ @Nullable final IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
+ @Nullable String callingAttributionTag) {
+ this(Collections.singletonList(r), r, m, binder, callbackFlags, callingAttributionTag);
}
NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
@NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m,
- @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
+ @Nullable final IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
+ @Nullable String callingAttributionTag) {
super();
ensureAllNetworkRequestsHaveType(r);
mRequests = initializeRequests(r);
@@ -5322,6 +5309,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mUid = mDeps.getCallingUid();
mPendingIntent = null;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mCallbackFlags = callbackFlags;
mCallingAttributionTag = callingAttributionTag;
try {
@@ -5363,6 +5351,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mUid = nri.mUid;
mPendingIntent = nri.mPendingIntent;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
}
@@ -5412,7 +5401,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
+ " callback request Id: "
+ mNetworkRequestForCallback.requestId
+ " " + mRequests
- + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
+ + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
+ + "callback flags: " + mCallbackFlags;
}
}
@@ -5496,13 +5486,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private boolean checkUnsupportedStartingFrom(int version, String callingPackageName) {
- final UserHandle user = UserHandle.getUserHandleForUid(mDeps.getCallingUid());
+ private boolean isTargetSdkAtleast(int version, int callingUid,
+ @NonNull String callingPackageName) {
+ final UserHandle user = UserHandle.getUserHandleForUid(callingUid);
final PackageManager pm =
mContext.createContextAsUser(user, 0 /* flags */).getPackageManager();
try {
- final int callingVersion = pm.getApplicationInfo(
- callingPackageName, 0 /* flags */).targetSdkVersion;
+ final int callingVersion = pm.getTargetSdkVersion(callingPackageName);
if (callingVersion < version) return false;
} catch (PackageManager.NameNotFoundException e) { }
return true;
@@ -5511,10 +5501,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder,
- int legacyType, @NonNull String callingPackageName,
+ int legacyType, int callbackFlags, @NonNull String callingPackageName,
@Nullable String callingAttributionTag) {
if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) {
- if (checkUnsupportedStartingFrom(Build.VERSION_CODES.M, callingPackageName)) {
+ if (isTargetSdkAtleast(Build.VERSION_CODES.M, mDeps.getCallingUid(),
+ callingPackageName)) {
throw new SecurityException("Insufficient permissions to specify legacy type");
}
}
@@ -5576,7 +5567,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
final NetworkRequestInfo nri = getNriToRegister(
- networkRequest, messenger, binder, callingAttributionTag);
+ networkRequest, messenger, binder, callbackFlags, callingAttributionTag);
if (DBG) log("requestNetwork for " + nri);
// For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
@@ -5611,6 +5602,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
*/
private NetworkRequestInfo getNriToRegister(@NonNull final NetworkRequest nr,
@Nullable final Messenger msgr, @Nullable final IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
@Nullable String callingAttributionTag) {
final List<NetworkRequest> requests;
if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) {
@@ -5619,7 +5611,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else {
requests = Collections.singletonList(nr);
}
- return new NetworkRequestInfo(requests, nr, msgr, binder, callingAttributionTag);
+ return new NetworkRequestInfo(
+ requests, nr, msgr, binder, callbackFlags, callingAttributionTag);
}
private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
@@ -5745,8 +5738,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, IBinder binder, @NonNull String callingPackageName,
- @Nullable String callingAttributionTag) {
+ Messenger messenger, IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
+ @NonNull String callingPackageName, @NonNull String callingAttributionTag) {
final int callingUid = mDeps.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
@@ -5767,7 +5761,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
+ new NetworkRequestInfo(networkRequest, messenger, binder, callbackFlags,
+ callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -5836,8 +5831,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public int registerNetworkProvider(Messenger messenger, String name) {
enforceNetworkFactoryOrSettingsPermission();
NetworkProviderInfo npi = new NetworkProviderInfo(name, messenger,
- null /* asyncChannel */, nextNetworkProviderId(),
- () -> unregisterNetworkProvider(messenger));
+ nextNetworkProviderId(), () -> unregisterNetworkProvider(messenger));
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_PROVIDER, npi));
return npi.providerId;
}
@@ -7101,6 +7095,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {
putParcelable(bundle, networkAgent.network);
}
+ final boolean includeLocationSensitiveInfo =
+ (nri.mCallbackFlags & NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) != 0;
switch (notificationType) {
case ConnectivityManager.CALLBACK_AVAILABLE: {
final NetworkCapabilities nc =
@@ -7109,7 +7105,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, nri.mUid, nrForCallback.getRequestorPackageName(),
+ nc, includeLocationSensitiveInfo, nri.mUid,
+ nrForCallback.getRequestorPackageName(),
nri.mCallingAttributionTag));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid));
@@ -7129,7 +7126,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, nri.mUid, nrForCallback.getRequestorPackageName(),
+ netCap, includeLocationSensitiveInfo, nri.mUid,
+ nrForCallback.getRequestorPackageName(),
nri.mCallingAttributionTag));
break;
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 81d4b9da63c8..4c3c6ef21fc5 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -56,6 +56,7 @@ import android.system.Os;
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Range;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -756,13 +757,9 @@ public class IpSecService extends IIpSecService.Stub {
}
}
- // These values have been reserved in NetIdManager
- @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00;
-
- public static final int TUN_INTF_NETID_RANGE = 0x0400;
-
private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray();
- private int mNextTunnelNetIdIndex = 0;
+ final Range<Integer> mNetIdRange = ConnectivityManager.getIpSecNetIdRange();
+ private int mNextTunnelNetId = mNetIdRange.getLower();
/**
* Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces
@@ -775,11 +772,13 @@ public class IpSecService extends IIpSecService.Stub {
*/
@VisibleForTesting
int reserveNetId() {
+ final int range = mNetIdRange.getUpper() - mNetIdRange.getLower() + 1;
synchronized (mTunnelNetIds) {
- for (int i = 0; i < TUN_INTF_NETID_RANGE; i++) {
- int index = mNextTunnelNetIdIndex;
- int netId = index + TUN_INTF_NETID_START;
- if (++mNextTunnelNetIdIndex >= TUN_INTF_NETID_RANGE) mNextTunnelNetIdIndex = 0;
+ for (int i = 0; i < range; i++) {
+ final int netId = mNextTunnelNetId;
+ if (++mNextTunnelNetId > mNetIdRange.getUpper()) {
+ mNextTunnelNetId = mNetIdRange.getLower();
+ }
if (!mTunnelNetIds.get(netId)) {
mTunnelNetIds.put(netId, true);
return netId;
diff --git a/services/core/java/com/android/server/NetIdManager.java b/services/core/java/com/android/server/NetIdManager.java
index 097fb3ae47e3..61925c80a22b 100644
--- a/services/core/java/com/android/server/NetIdManager.java
+++ b/services/core/java/com/android/server/NetIdManager.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.annotation.NonNull;
+import android.net.ConnectivityManager;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
@@ -31,7 +32,7 @@ public class NetIdManager {
// Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
public static final int MIN_NET_ID = 100; // some reserved marks
// Top IDs reserved by IpSecService
- public static final int MAX_NET_ID = 65535 - IpSecService.TUN_INTF_NETID_RANGE;
+ public static final int MAX_NET_ID = ConnectivityManager.getIpSecNetIdRange().getLower() - 1;
@GuardedBy("mNetIdInUse")
private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8ea6194a9535..06a1abb72607 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -44,11 +44,11 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
-import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Process.BLUETOOTH_UID;
@@ -273,6 +273,9 @@ import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
+import android.os.incremental.IIncrementalService;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalMetrics;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
@@ -7697,18 +7700,32 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
- boolean isPackageLoading = false;
+ boolean isIncremental = false;
+ float loadingProgress = 1;
+ long millisSinceOldestPendingRead = 0;
// Notify package manager service to possibly update package state
if (r != null && r.info != null && r.info.packageName != null) {
+ final String codePath = r.info.getCodePath();
mPackageManagerInt.notifyPackageCrashOrAnr(r.info.packageName);
IncrementalStatesInfo incrementalStatesInfo =
mPackageManagerInt.getIncrementalStatesInfo(r.info.packageName, r.uid,
r.userId);
- isPackageLoading = incrementalStatesInfo.isLoading();
- if (isPackageLoading) {
- // Report in the main log that the package is still loading
- Slog.e(TAG, "App crashed when package " + r.info.packageName + " is "
- + ((int) (incrementalStatesInfo.getProgress() * 100)) + "% loaded.");
+ if (incrementalStatesInfo != null) {
+ loadingProgress = incrementalStatesInfo.getProgress();
+ }
+ isIncremental = IncrementalManager.isIncrementalPath(codePath);
+ if (isIncremental) {
+ // Report in the main log about the incremental package
+ Slog.e(TAG, "App crashed on incremental package " + r.info.packageName
+ + " which is " + ((int) (loadingProgress * 100)) + "% loaded.");
+ final IBinder incrementalService = ServiceManager.getService(
+ Context.INCREMENTAL_SERVICE);
+ if (incrementalService != null) {
+ final IncrementalManager incrementalManager = new IncrementalManager(
+ IIncrementalService.Stub.asInterface(incrementalService));
+ IncrementalMetrics metrics = incrementalManager.getMetrics(codePath);
+ millisSinceOldestPendingRead = metrics.getMillisSinceOldestPendingRead();
+ }
}
}
@@ -7737,7 +7754,7 @@ public class ActivityManagerService extends IActivityManager.Stub
processName.equals("system_server") ? ServerProtoEnums.SYSTEM_SERVER
: (r != null) ? r.getProcessClassEnum()
: ServerProtoEnums.ERROR_SOURCE_UNKNOWN,
- isPackageLoading
+ isIncremental, loadingProgress, millisSinceOldestPendingRead
);
final int relaunchReason = r == null ? RELAUNCH_REASON_NONE
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 81c4c8605fb4..e79f09665153 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1416,7 +1416,7 @@ public final class BroadcastQueue {
}
}
if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
- r.requiredPermissions != null && r.requiredPermissions.length > 0) {
+ r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
String requiredPermission = r.requiredPermissions[i];
try {
@@ -1424,7 +1424,7 @@ public final class BroadcastQueue {
checkPermission(requiredPermission,
info.activityInfo.applicationInfo.packageName,
UserHandle
- .getUserId(info.activityInfo.applicationInfo.uid));
+ .getUserId(info.activityInfo.applicationInfo.uid));
} catch (RemoteException e) {
perm = PackageManager.PERMISSION_DENIED;
}
@@ -1439,36 +1439,18 @@ public final class BroadcastQueue {
break;
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
- if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
- && mService.getAppOpsManager().noteOpNoThrow(appOp,
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
- null /* default featureId */,
- "Broadcast delivered to " + info.activityInfo.name)
- != AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: receiving "
- + r.intent + " to "
- + component.flattenToShortString()
- + " requires appop " + AppOpsManager.permissionToOp(
- requiredPermission)
- + " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- skip = true;
- break;
+ if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) {
+ if (!noteOpForManifestReceiver(appOp, r, info, component)) {
+ skip = true;
+ break;
+ }
}
}
}
- if (!skip && r.appOp != AppOpsManager.OP_NONE
- && mService.getAppOpsManager().noteOpNoThrow(r.appOp,
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
- null /* default featureId */, "Broadcast delivered to " + info.activityInfo.name)
- != AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: receiving "
- + r.intent + " to "
- + component.flattenToShortString()
- + " requires appop " + AppOpsManager.opToName(r.appOp)
- + " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- skip = true;
+ if (!skip && r.appOp != AppOpsManager.OP_NONE) {
+ if (!noteOpForManifestReceiver(r.appOp, r, info, component)) {
+ skip = true;
+ }
}
boolean isSingleton = false;
try {
@@ -1717,6 +1699,40 @@ public final class BroadcastQueue {
mPendingBroadcastRecvIndex = recIdx;
}
+ private boolean noteOpForManifestReceiver(int appOp, BroadcastRecord r, ResolveInfo info,
+ ComponentName component) {
+ if (info.activityInfo.attributionTags == null) {
+ return noteOpForManifestReceiverInner(appOp, r, info, component, null);
+ } else {
+ // Attribution tags provided, noteOp each tag
+ for (String tag : info.activityInfo.attributionTags) {
+ if (!noteOpForManifestReceiverInner(appOp, r, info, component, tag)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private boolean noteOpForManifestReceiverInner(int appOp, BroadcastRecord r, ResolveInfo info,
+ ComponentName component, String tag) {
+ if (mService.getAppOpsManager().noteOpNoThrow(appOp,
+ info.activityInfo.applicationInfo.uid,
+ info.activityInfo.packageName,
+ tag,
+ "Broadcast delivered to " + info.activityInfo.name)
+ != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(TAG, "Appop Denial: receiving "
+ + r.intent + " to "
+ + component.flattenToShortString()
+ + " requires appop " + AppOpsManager.opToName(appOp)
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ return false;
+ }
+ return true;
+ }
+
private void maybeAddAllowBackgroundActivityStartsToken(ProcessRecord proc, BroadcastRecord r) {
if (r == null || proc == null || !r.allowBackgroundActivityStarts) {
return;
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index d03a47afed8a..93f30cc8ac5e 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -26,12 +26,18 @@ import android.app.AnrController;
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.PackageManagerInternal;
+import android.os.IBinder;
import android.os.Message;
import android.os.Process;
+import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.incremental.IIncrementalService;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalMetrics;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Slog;
@@ -294,14 +300,31 @@ class ProcessErrorStateRecord {
}
// Check if package is still being loaded
- boolean isPackageLoading = false;
+ boolean isIncremental = false;
+ float loadingProgress = 1;
+ long millisSinceOldestPendingRead = 0;
final PackageManagerInternal packageManagerInternal = mService.getPackageManagerInternal();
if (aInfo != null && aInfo.packageName != null) {
IncrementalStatesInfo incrementalStatesInfo =
packageManagerInternal.getIncrementalStatesInfo(
aInfo.packageName, mApp.uid, mApp.userId);
if (incrementalStatesInfo != null) {
- isPackageLoading = incrementalStatesInfo.isLoading();
+ loadingProgress = incrementalStatesInfo.getProgress();
+ }
+ final String codePath = aInfo.getCodePath();
+ isIncremental = IncrementalManager.isIncrementalPath(codePath);
+ if (isIncremental) {
+ // Report in the main log that the incremental package is still loading
+ Slog.e(TAG, "App crashed on incremental package " + aInfo.packageName
+ + " which is " + ((int) (loadingProgress * 100)) + "% loaded.");
+ final IBinder incrementalService = ServiceManager.getService(
+ Context.INCREMENTAL_SERVICE);
+ if (incrementalService != null) {
+ final IncrementalManager incrementalManager = new IncrementalManager(
+ IIncrementalService.Stub.asInterface(incrementalService));
+ IncrementalMetrics metrics = incrementalManager.getMetrics(codePath);
+ millisSinceOldestPendingRead = metrics.getMillisSinceOldestPendingRead();
+ }
}
}
@@ -322,10 +345,8 @@ class ProcessErrorStateRecord {
info.append("Parent: ").append(parentShortComponentName).append("\n");
}
- if (isPackageLoading) {
- // Report in the main log that the package is still loading
- final float loadingProgress = packageManagerInternal.getIncrementalStatesInfo(
- aInfo.packageName, mApp.uid, mApp.userId).getProgress();
+ if (isIncremental) {
+ // Report in the main log about the incremental package
info.append("Package is ").append((int) (loadingProgress * 100)).append("% loaded.\n");
}
@@ -412,7 +433,8 @@ class ProcessErrorStateRecord {
? FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
: FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND,
mApp.getProcessClassEnum(),
- (mApp.info != null) ? mApp.info.packageName : "", isPackageLoading);
+ (mApp.info != null) ? mApp.info.packageName : "",
+ isIncremental, loadingProgress, millisSinceOldestPendingRead);
final ProcessRecord parentPr = parentProcess != null
? (ProcessRecord) parentProcess.mOwner : null;
mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName,
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index e0d1375b4069..6712c5474921 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -950,34 +950,36 @@ public class ClipboardService extends SystemService {
}
clipboard.mNotifiedUids.put(uid, true);
- // Retrieve the app label of the source of the clip data
- CharSequence sourceAppLabel = null;
- if (clipboard.mPrimaryClipPackage != null) {
- try {
- sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser(
- clipboard.mPrimaryClipPackage, 0, userId));
- } catch (PackageManager.NameNotFoundException e) {
- // leave label as null
+ Binder.withCleanCallingIdentity(() -> {
+ // Retrieve the app label of the source of the clip data
+ CharSequence sourceAppLabel = null;
+ if (clipboard.mPrimaryClipPackage != null) {
+ try {
+ sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser(
+ clipboard.mPrimaryClipPackage, 0, userId));
+ } catch (PackageManager.NameNotFoundException e) {
+ // leave label as null
+ }
}
- }
- try {
- CharSequence callingAppLabel = mPm.getApplicationLabel(
- mPm.getApplicationInfoAsUser(callingPackage, 0, userId));
- String message;
- if (sourceAppLabel != null) {
- message = getContext().getString(
- R.string.pasted_from_app, callingAppLabel, sourceAppLabel);
- } else {
- message = getContext().getString(R.string.pasted_from_clipboard, callingAppLabel);
+ try {
+ CharSequence callingAppLabel = mPm.getApplicationLabel(
+ mPm.getApplicationInfoAsUser(callingPackage, 0, userId));
+ String message;
+ if (sourceAppLabel != null) {
+ message = getContext().getString(
+ R.string.pasted_from_app, callingAppLabel, sourceAppLabel);
+ } else {
+ message = getContext().getString(
+ R.string.pasted_from_clipboard, callingAppLabel);
+ }
+ Slog.i(TAG, message);
+ Toast.makeText(
+ getContext(), UiThread.get().getLooper(), message, Toast.LENGTH_SHORT)
+ .show();
+ } catch (PackageManager.NameNotFoundException e) {
+ // do nothing
}
- Slog.i(TAG, message);
- Binder.withCleanCallingIdentity(() ->
- Toast.makeText(getContext(), UiThread.get().getLooper(), message,
- Toast.LENGTH_SHORT)
- .show());
- } catch (PackageManager.NameNotFoundException e) {
- // do nothing
- }
+ });
}
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 9411e33434d8..488677ac1b59 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -31,14 +31,17 @@ import static android.os.Process.SYSTEM_UID;
import static com.android.net.module.util.CollectionUtils.toIntArray;
import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageManagerInternal;
import android.net.INetd;
import android.net.UidRange;
+import android.net.Uri;
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -54,7 +57,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.CollectionUtils;
-import com.android.server.LocalServices;
import java.util.ArrayList;
import java.util.HashMap;
@@ -71,7 +73,7 @@ import java.util.Set;
*
* @hide
*/
-public class PermissionMonitor implements PackageManagerInternal.PackageListObserver {
+public class PermissionMonitor {
private static final String TAG = "PermissionMonitor";
private static final boolean DBG = true;
protected static final Boolean SYSTEM = Boolean.TRUE;
@@ -83,6 +85,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
private final SystemConfigManager mSystemConfigManager;
private final INetd mNetd;
private final Dependencies mDeps;
+ private final Context mContext;
@GuardedBy("this")
private final Set<UserHandle> mUsers = new HashSet<>();
@@ -102,6 +105,25 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
@GuardedBy("this")
private final Set<Integer> mAllApps = new HashSet<>();
+ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final Uri packageData = intent.getData();
+ final String packageName =
+ packageData != null ? packageData.getSchemeSpecificPart() : null;
+
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ onPackageAdded(packageName, uid);
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ onPackageRemoved(packageName, uid);
+ } else {
+ Log.wtf(TAG, "received unexpected intent: " + action);
+ }
+ }
+ };
+
/**
* Dependencies of PermissionMonitor, for injection in tests.
*/
@@ -127,6 +149,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
mNetd = netd;
mDeps = deps;
+ mContext = context;
}
// Intended to be called only once at startup, after the system is ready. Installs a broadcast
@@ -134,12 +157,14 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
public synchronized void startMonitoring() {
log("Monitoring");
- PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
- if (pmi != null) {
- pmi.getPackageList(this);
- } else {
- loge("failed to get the PackageManagerInternal service");
- }
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addDataScheme("package");
+ mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */).registerReceiver(
+ mIntentReceiver, intentFilter, null /* broadcastPermission */,
+ null /* scheduler */);
+
List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
| MATCH_ANY_USER);
if (apps == null) {
@@ -347,9 +372,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
*
* @hide
*/
- @Override
public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+ // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
+ // using appId instead of uid actually
+ sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
@@ -384,9 +410,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
*
* @hide
*/
- @Override
public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+ // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
+ // using appId instead of uid actually
+ sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
// If the newly-removed package falls within some VPN's uid range, update Netd with it.
// This needs to happen before the mApps update below, since removeBypassingUids() depends
@@ -432,19 +459,6 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
}
- /**
- * Called when a package is changed.
- *
- * @param packageName The name of the changed package.
- * @param uid The uid of the changed package.
- *
- * @hide
- */
- @Override
- public synchronized void onPackageChanged(@NonNull final String packageName, final int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
- }
-
private static int getNetdPermissionMask(String[] requestedPermissions,
int[] requestedPermissionsFlags) {
int permissions = 0;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 027b9afba392..0e714969a69b 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -791,12 +791,13 @@ public final class ContentService extends IContentService.Stub {
public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
enforceCrossUserPermission(userId,
"no permission to read sync settings for user " + userId);
+ final int callingUid = Binder.getCallingUid();
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- return syncManager.getSyncAdapterTypes(userId);
+ return syncManager.getSyncAdapterTypes(callingUid, userId);
} finally {
restoreCallingIdentity(identityToken);
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index df870125e253..ac7e01ed4d72 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -89,6 +89,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
import android.provider.Settings;
+import android.text.TextUtils;
import android.text.format.TimeMigrationUtils;
import android.util.EventLog;
import android.util.Log;
@@ -1257,16 +1258,19 @@ public class SyncManager {
syncExemptionFlag, callingUid, callingPid, callingPackage);
}
- public SyncAdapterType[] getSyncAdapterTypes(int userId) {
+ public SyncAdapterType[] getSyncAdapterTypes(int callingUid, int userId) {
final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
serviceInfos = mSyncAdapters.getAllServices(userId);
- SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
- int i = 0;
+ final List<SyncAdapterType> types = new ArrayList<>(serviceInfos.size());
for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
- types[i] = serviceInfo.type;
- ++i;
+ final String packageName = serviceInfo.type.getPackageName();
+ if (!TextUtils.isEmpty(packageName) && mPackageManagerInternal.filterAppAccess(
+ packageName, callingUid, userId)) {
+ continue;
+ }
+ types.add(serviceInfo.type);
}
- return types;
+ return types.toArray(new SyncAdapterType[] {});
}
public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index c4663a122321..2b7d2074a7e0 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -67,6 +67,8 @@ public final class FontManagerService extends IFontManager.Stub {
@Override
public FontConfig getFontConfig() {
+ getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS,
+ "UPDATE_FONTS permission required.");
return getSystemFontConfig();
}
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index c23e2e691b55..947ee24f8e02 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -97,11 +97,16 @@ final class DeviceSelectAction extends HdmiCecFeatureAction {
@Override
public boolean start() {
- // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0.
- // The message is re-sent at the end of the action for devices that don't support 2.0.
- sendSetStreamPath();
- int targetPowerStatus = localDevice().mService.getHdmiCecNetwork()
- .getCecDeviceInfo(getTargetAddress()).getDevicePowerStatus();
+ // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0.
+ // The message is re-sent at the end of the action for devices that don't support 2.0.
+ sendSetStreamPath();
+ int targetPowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
+ HdmiDeviceInfo targetDevice = localDevice().mService.getHdmiCecNetwork().getCecDeviceInfo(
+ getTargetAddress());
+ if (targetDevice != null) {
+ targetPowerStatus = targetDevice.getDevicePowerStatus();
+ }
+
if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) {
queryDevicePowerStatus();
} else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index 624af30854dc..6fbb26c4a5ee 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -35,33 +35,19 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.util.ArrayMap;
-import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ConcurrentUtils;
-import com.android.server.hdmi.cec.config.CecSettings;
-import com.android.server.hdmi.cec.config.Setting;
-import com.android.server.hdmi.cec.config.Value;
-import com.android.server.hdmi.cec.config.XmlParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
-import java.util.Set;
import java.util.concurrent.Executor;
-import javax.xml.datatype.DatatypeConfigurationException;
-
/**
* The {@link HdmiCecConfig} class is used for getting information about
* available HDMI CEC settings.
@@ -74,6 +60,10 @@ public class HdmiCecConfig {
private static final String SHARED_PREFS_DIR = "shared_prefs";
private static final String SHARED_PREFS_NAME = "cec_config.xml";
+ private static final int STORAGE_SYSPROPS = 0;
+ private static final int STORAGE_GLOBAL_SETTINGS = 1;
+ private static final int STORAGE_SHARED_PREFS = 2;
+
@IntDef({
STORAGE_SYSPROPS,
STORAGE_GLOBAL_SETTINGS,
@@ -81,10 +71,6 @@ public class HdmiCecConfig {
})
private @interface Storage {}
- private static final int STORAGE_SYSPROPS = 0;
- private static final int STORAGE_GLOBAL_SETTINGS = 1;
- private static final int STORAGE_SHARED_PREFS = 2;
-
private static final String VALUE_TYPE_STRING = "string";
private static final String VALUE_TYPE_INT = "int";
@@ -96,8 +82,6 @@ public class HdmiCecConfig {
@NonNull private final Context mContext;
@NonNull private final StorageAdapter mStorageAdapter;
- @Nullable private final CecSettings mSystemConfig;
- @Nullable private final CecSettings mVendorOverride;
private final Object mLock = new Object();
@@ -107,6 +91,18 @@ public class HdmiCecConfig {
private SettingsObserver mSettingsObserver;
+ private LinkedHashMap<String, Setting> mSettings = new LinkedHashMap<>();
+
+ /**
+ * Exception thrown when the CEC Configuration setup verification fails.
+ * This usually means a settings lacks default value or storage/storage key.
+ */
+ public static class VerificationException extends RuntimeException {
+ public VerificationException(String message) {
+ super(message);
+ }
+ }
+
/**
* Listener used to get notifications when value of a setting changes.
*/
@@ -202,91 +198,297 @@ public class HdmiCecConfig {
}
}
- @VisibleForTesting
- HdmiCecConfig(@NonNull Context context,
- @NonNull StorageAdapter storageAdapter,
- @Nullable CecSettings systemConfig,
- @Nullable CecSettings vendorOverride) {
- mContext = context;
- mStorageAdapter = storageAdapter;
- mSystemConfig = systemConfig;
- mVendorOverride = vendorOverride;
- if (mSystemConfig == null) {
- Slog.i(TAG, "CEC system configuration XML missing.");
+ private class Value {
+ private final String mStringValue;
+ private final Integer mIntValue;
+
+ Value(@NonNull String value) {
+ mStringValue = value;
+ mIntValue = null;
}
- if (mVendorOverride == null) {
- Slog.i(TAG, "CEC OEM configuration override XML missing.");
+
+ Value(@NonNull Integer value) {
+ mStringValue = null;
+ mIntValue = value;
}
- }
- HdmiCecConfig(@NonNull Context context) {
- this(context, new StorageAdapter(context),
- readSettingsFromFile(Environment.buildPath(Environment.getRootDirectory(),
- ETC_DIR, CONFIG_FILE)),
- readSettingsFromFile(Environment.buildPath(Environment.getVendorDirectory(),
- ETC_DIR, CONFIG_FILE)));
+ String getStringValue() {
+ return mStringValue;
+ }
+
+ Integer getIntValue() {
+ return mIntValue;
+ }
}
- @Nullable
- private static CecSettings readSettingsFromFile(@NonNull File file) {
- if (!file.exists()) {
- return null;
+ private class Setting {
+ @NonNull private final Context mContext;
+ @NonNull private final @CecSettingName String mName;
+ private final boolean mUserConfigurable;
+
+ private Value mDefaultValue = null;
+ private List<Value> mAllowedValues = new ArrayList<>();
+
+ Setting(@NonNull Context context,
+ @NonNull @CecSettingName String name,
+ int userConfResId) {
+ mContext = context;
+ mName = name;
+ mUserConfigurable = mContext.getResources().getBoolean(userConfResId);
}
- if (!file.isFile()) {
- Slog.e(TAG, "CEC configuration is not a file: " + file + ", skipping.");
- return null;
+
+ public @CecSettingName String getName() {
+ return mName;
}
- try (InputStream in = new BufferedInputStream(new FileInputStream(file))) {
- return XmlParser.read(in);
- } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
- Slog.e(TAG, "Encountered an error while reading/parsing CEC config file: " + file, e);
+
+ public @ValueType String getValueType() {
+ return getDefaultValue().getStringValue() != null
+ ? VALUE_TYPE_STRING
+ : VALUE_TYPE_INT;
}
- return null;
- }
- @NonNull
- @VisibleForTesting
- static HdmiCecConfig createFromStrings(@NonNull Context context,
- @NonNull StorageAdapter storageAdapter,
- @Nullable String productConfigXml,
- @Nullable String vendorOverrideXml) {
- CecSettings productConfig = null;
- CecSettings vendorOverride = null;
- try {
- if (productConfigXml != null) {
- productConfig = XmlParser.read(
- new ByteArrayInputStream(productConfigXml.getBytes()));
- }
- if (vendorOverrideXml != null) {
- vendorOverride = XmlParser.read(
- new ByteArrayInputStream(vendorOverrideXml.getBytes()));
+ public Value getDefaultValue() {
+ if (mDefaultValue == null) {
+ throw new VerificationException("Invalid CEC setup for '"
+ + this.getName() + "' setting. "
+ + "Setting has no default value.");
}
- } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
- Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e);
+ return mDefaultValue;
}
- return new HdmiCecConfig(context, storageAdapter, productConfig, vendorOverride);
- }
- @Nullable
- private Setting getSetting(@NonNull String name) {
- if (mSystemConfig == null) {
- return null;
- }
- if (mVendorOverride != null) {
- // First read from the vendor override.
- for (Setting setting : mVendorOverride.getSetting()) {
- if (setting.getName().equals(name)) {
- return setting;
+ public boolean getUserConfigurable() {
+ return mUserConfigurable;
+ }
+
+ private void registerValue(@NonNull Value value,
+ int allowedResId, int defaultResId) {
+ if (mContext.getResources().getBoolean(allowedResId)) {
+ mAllowedValues.add(value);
+ if (mContext.getResources().getBoolean(defaultResId)) {
+ if (mDefaultValue != null) {
+ throw new VerificationException("Invalid CEC setup for '"
+ + this.getName() + "' setting. "
+ + "Setting already has a default value.");
+ }
+ mDefaultValue = value;
}
}
}
- // If not found, try the system config.
- for (Setting setting : mSystemConfig.getSetting()) {
- if (setting.getName().equals(name)) {
- return setting;
- }
+
+ public void registerValue(@NonNull String value, int allowedResId,
+ int defaultResId) {
+ registerValue(new Value(value), allowedResId, defaultResId);
}
- return null;
+
+ public void registerValue(int value, int allowedResId,
+ int defaultResId) {
+ registerValue(new Value(value), allowedResId, defaultResId);
+ }
+
+
+ public List<Value> getAllowedValues() {
+ return mAllowedValues;
+ }
+ }
+
+ @VisibleForTesting
+ HdmiCecConfig(@NonNull Context context,
+ @NonNull StorageAdapter storageAdapter) {
+ mContext = context;
+ mStorageAdapter = storageAdapter;
+
+ Setting hdmiCecEnabled = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ R.bool.config_cecHdmiCecEnabled_userConfigurable);
+ hdmiCecEnabled.registerValue(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED,
+ R.bool.config_cecHdmiCecControlEnabled_allowed,
+ R.bool.config_cecHdmiCecControlEnabled_default);
+ hdmiCecEnabled.registerValue(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
+ R.bool.config_cecHdmiCecControlDisabled_allowed,
+ R.bool.config_cecHdmiCecControlDisabled_default);
+
+ Setting hdmiCecVersion = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ R.bool.config_cecHdmiCecVersion_userConfigurable);
+ hdmiCecVersion.registerValue(HdmiControlManager.HDMI_CEC_VERSION_1_4_B,
+ R.bool.config_cecHdmiCecVersion14b_allowed,
+ R.bool.config_cecHdmiCecVersion14b_default);
+ hdmiCecVersion.registerValue(HdmiControlManager.HDMI_CEC_VERSION_2_0,
+ R.bool.config_cecHdmiCecVersion20_allowed,
+ R.bool.config_cecHdmiCecVersion20_default);
+
+ Setting powerControlMode = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ R.bool.config_cecSendStandbyOnSleep_userConfigurable);
+ powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_TV,
+ R.bool.config_cecPowerControlModeTv_allowed,
+ R.bool.config_cecPowerControlModeTv_default);
+ powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST,
+ R.bool.config_cecPowerControlModeBroadcast_allowed,
+ R.bool.config_cecPowerControlModeBroadcast_default);
+ powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_NONE,
+ R.bool.config_cecPowerControlModeNone_allowed,
+ R.bool.config_cecPowerControlModeNone_default);
+
+ Setting powerStateChangeOnActiveSourceLost = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ R.bool.config_cecPowerStateChangeOnActiveSourceLost_userConfigurable);
+ powerStateChangeOnActiveSourceLost.registerValue(
+ HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE,
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_allowed,
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_default);
+ powerStateChangeOnActiveSourceLost.registerValue(
+ HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW,
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed,
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default);
+
+ Setting systemAudioModeMuting = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+ R.bool.config_cecSystemAudioModeMuting_userConfigurable);
+ systemAudioModeMuting.registerValue(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED,
+ R.bool.config_cecSystemAudioModeMutingEnabled_allowed,
+ R.bool.config_cecSystemAudioModeMutingEnabled_default);
+ systemAudioModeMuting.registerValue(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED,
+ R.bool.config_cecSystemAudioModeMutingDisabled_allowed,
+ R.bool.config_cecSystemAudioModeMutingDisabled_default);
+
+ Setting volumeControlMode = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+ R.bool.config_cecVolumeControlMode_userConfigurable);
+ volumeControlMode.registerValue(HdmiControlManager.VOLUME_CONTROL_ENABLED,
+ R.bool.config_cecVolumeControlModeEnabled_allowed,
+ R.bool.config_cecVolumeControlModeEnabled_default);
+ volumeControlMode.registerValue(HdmiControlManager.VOLUME_CONTROL_DISABLED,
+ R.bool.config_cecVolumeControlModeDisabled_allowed,
+ R.bool.config_cecVolumeControlModeDisabled_default);
+
+ Setting tvWakeOnOneTouchPlay = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+ R.bool.config_cecTvWakeOnOneTouchPlay_userConfigurable);
+ tvWakeOnOneTouchPlay.registerValue(HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED,
+ R.bool.config_cecTvWakeOnOneTouchPlayEnabled_allowed,
+ R.bool.config_cecTvWakeOnOneTouchPlayEnabled_default);
+ tvWakeOnOneTouchPlay.registerValue(HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED,
+ R.bool.config_cecTvWakeOnOneTouchPlayDisabled_allowed,
+ R.bool.config_cecTvWakeOnOneTouchPlayDisabled_default);
+
+ Setting tvSendStandbyOnSleep = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ R.bool.config_cecTvSendStandbyOnSleep_userConfigurable);
+ tvSendStandbyOnSleep.registerValue(HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED,
+ R.bool.config_cecTvSendStandbyOnSleepEnabled_allowed,
+ R.bool.config_cecTvSendStandbyOnSleepEnabled_default);
+ tvSendStandbyOnSleep.registerValue(HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_DISABLED,
+ R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed,
+ R.bool.config_cecTvSendStandbyOnSleepDisabled_default);
+
+ Setting rcProfileTv = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+ R.bool.config_cecRcProfileTv_userConfigurable);
+ rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_NONE,
+ R.bool.config_cecRcProfileTvNone_allowed,
+ R.bool.config_cecRcProfileTvNone_default);
+ rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_ONE,
+ R.bool.config_cecRcProfileTvOne_allowed,
+ R.bool.config_cecRcProfileTvOne_default);
+ rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_TWO,
+ R.bool.config_cecRcProfileTvTwo_allowed,
+ R.bool.config_cecRcProfileTvTwo_default);
+ rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_THREE,
+ R.bool.config_cecRcProfileTvThree_allowed,
+ R.bool.config_cecRcProfileTvThree_default);
+ rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_FOUR,
+ R.bool.config_cecRcProfileTvFour_allowed,
+ R.bool.config_cecRcProfileTvFour_default);
+
+ Setting rcProfileSourceRootMenu = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ R.bool.config_cecRcProfileSourceRootMenu_userConfigurable);
+ rcProfileSourceRootMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_ROOT_MENU_HANDLED,
+ R.bool.config_cecRcProfileSourceRootMenuHandled_allowed,
+ R.bool.config_cecRcProfileSourceRootMenuHandled_default);
+ rcProfileSourceRootMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_ROOT_MENU_NOT_HANDLED,
+ R.bool.config_cecRcProfileSourceRootMenuNotHandled_allowed,
+ R.bool.config_cecRcProfileSourceRootMenuNotHandled_default);
+
+ Setting rcProfileSourceSetupMenu = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ R.bool.config_cecRcProfileSourceSetupMenu_userConfigurable);
+ rcProfileSourceSetupMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_SETUP_MENU_HANDLED,
+ R.bool.config_cecRcProfileSourceSetupMenuHandled_allowed,
+ R.bool.config_cecRcProfileSourceSetupMenuHandled_default);
+ rcProfileSourceSetupMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_SETUP_MENU_NOT_HANDLED,
+ R.bool.config_cecRcProfileSourceSetupMenuNotHandled_allowed,
+ R.bool.config_cecRcProfileSourceSetupMenuNotHandled_default);
+
+ Setting rcProfileSourceContentsMenu = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ R.bool.config_cecRcProfileSourceContentsMenu_userConfigurable);
+ rcProfileSourceContentsMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_CONTENTS_MENU_HANDLED,
+ R.bool.config_cecRcProfileSourceContentsMenuHandled_allowed,
+ R.bool.config_cecRcProfileSourceContentsMenuHandled_default);
+ rcProfileSourceContentsMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_CONTENTS_MENU_NOT_HANDLED,
+ R.bool.config_cecRcProfileSourceContentsMenuNotHandled_allowed,
+ R.bool.config_cecRcProfileSourceContentsMenuNotHandled_default);
+
+ Setting rcProfileSourceTopMenu = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ R.bool.config_cecRcProfileSourceTopMenu_userConfigurable);
+ rcProfileSourceTopMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_TOP_MENU_HANDLED,
+ R.bool.config_cecRcProfileSourceTopMenuHandled_allowed,
+ R.bool.config_cecRcProfileSourceTopMenuHandled_default);
+ rcProfileSourceTopMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_TOP_MENU_NOT_HANDLED,
+ R.bool.config_cecRcProfileSourceTopMenuNotHandled_allowed,
+ R.bool.config_cecRcProfileSourceTopMenuNotHandled_default);
+
+ Setting rcProfileSourceMediaContextSensitiveMenu = registerSetting(
+ HdmiControlManager
+ .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU,
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable);
+ rcProfileSourceMediaContextSensitiveMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_MEDIA_CONTEXT_SENSITIVE_MENU_HANDLED,
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed,
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default);
+ rcProfileSourceMediaContextSensitiveMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_MEDIA_CONTEXT_SENSITIVE_MENU_NOT_HANDLED,
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed,
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default);
+
+ verifySettings();
+ }
+
+ HdmiCecConfig(@NonNull Context context) {
+ this(context, new StorageAdapter(context));
+ }
+
+ private Setting registerSetting(@NonNull @CecSettingName String name,
+ int userConfResId) {
+ Setting setting = new Setting(mContext, name, userConfResId);
+ mSettings.put(name, setting);
+ return setting;
+ }
+
+ private void verifySettings() {
+ for (Setting setting: mSettings.values()) {
+ // This will throw an exception when a setting
+ // doesn't have a default value assigned.
+ setting.getDefaultValue();
+ getStorage(setting);
+ getStorageKey(setting);
+ }
+ }
+
+ @Nullable
+ private Setting getSetting(@NonNull String name) {
+ return mSettings.containsKey(name) ? mSettings.get(name) : null;
}
@Storage
@@ -322,7 +524,7 @@ public class HdmiCecConfig {
.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU:
return STORAGE_SHARED_PREFS;
default:
- throw new RuntimeException("Invalid CEC setting '" + setting.getName()
+ throw new VerificationException("Invalid CEC setting '" + setting.getName()
+ "' storage.");
}
}
@@ -359,7 +561,7 @@ public class HdmiCecConfig {
.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU:
return setting.getName();
default:
- throw new RuntimeException("Invalid CEC setting '" + setting.getName()
+ throw new VerificationException("Invalid CEC setting '" + setting.getName()
+ "' storage key.");
}
}
@@ -396,10 +598,6 @@ public class HdmiCecConfig {
}
}
- private int getIntValue(@NonNull Value value) {
- return Integer.decode(value.getIntValue());
- }
-
private void notifyGlobalSettingChanged(String setting) {
switch (setting) {
case Global.HDMI_CONTROL_ENABLED:
@@ -533,41 +731,20 @@ public class HdmiCecConfig {
* Returns a list of all settings based on the XML metadata.
*/
public @CecSettingName List<String> getAllSettings() {
- if (mSystemConfig == null) {
- return new ArrayList<String>();
- }
- List<String> allSettings = new ArrayList<String>();
- for (Setting setting : mSystemConfig.getSetting()) {
- allSettings.add(setting.getName());
- }
- return allSettings;
+ return new ArrayList<>(mSettings.keySet());
}
/**
* Returns a list of user-modifiable settings based on the XML metadata.
*/
public @CecSettingName List<String> getUserSettings() {
- if (mSystemConfig == null) {
- return new ArrayList<String>();
- }
- Set<String> userSettings = new HashSet<String>();
- // First read from the system config.
- for (Setting setting : mSystemConfig.getSetting()) {
+ List<String> settings = new ArrayList<>();
+ for (Setting setting: mSettings.values()) {
if (setting.getUserConfigurable()) {
- userSettings.add(setting.getName());
- }
- }
- if (mVendorOverride != null) {
- // Next either add or remove based on the vendor override.
- for (Setting setting : mVendorOverride.getSetting()) {
- if (setting.getUserConfigurable()) {
- userSettings.add(setting.getName());
- } else {
- userSettings.remove(setting.getName());
- }
+ settings.add(setting.getName());
}
}
- return new ArrayList(userSettings);
+ return settings;
}
/**
@@ -607,7 +784,7 @@ public class HdmiCecConfig {
+ "' is not a string-type setting.");
}
List<String> allowedValues = new ArrayList<String>();
- for (Value allowedValue : setting.getAllowedValues().getValue()) {
+ for (Value allowedValue : setting.getAllowedValues()) {
allowedValues.add(allowedValue.getStringValue());
}
return allowedValues;
@@ -626,8 +803,8 @@ public class HdmiCecConfig {
+ "' is not a string-type setting.");
}
List<Integer> allowedValues = new ArrayList<Integer>();
- for (Value allowedValue : setting.getAllowedValues().getValue()) {
- allowedValues.add(getIntValue(allowedValue));
+ for (Value allowedValue : setting.getAllowedValues()) {
+ allowedValues.add(allowedValue.getIntValue());
}
return allowedValues;
}
@@ -659,7 +836,7 @@ public class HdmiCecConfig {
throw new IllegalArgumentException("Setting '" + name
+ "' is not a string-type setting.");
}
- return getIntValue(getSetting(name).getDefaultValue());
+ return getSetting(name).getDefaultValue().getIntValue();
}
/**
@@ -691,7 +868,7 @@ public class HdmiCecConfig {
+ "' is not a int-type setting.");
}
HdmiLogger.debug("Getting CEC setting value '" + name + "'.");
- String defaultValue = Integer.toString(getIntValue(setting.getDefaultValue()));
+ String defaultValue = Integer.toString(setting.getDefaultValue().getIntValue());
String value = retrieveValue(setting, defaultValue);
return Integer.parseInt(value);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index d8914b389191..bdc4e66cf7f9 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -500,7 +500,8 @@ abstract class HdmiCecLocalDevice {
HdmiDeviceInfo cecDeviceInfo = mService.getHdmiCecNetwork().getCecDeviceInfo(address);
// If no non-default display name is available for the device, request the devices OSD name.
- if (cecDeviceInfo.getDisplayName().equals(HdmiUtils.getDefaultDeviceName(address))) {
+ if (cecDeviceInfo != null && cecDeviceInfo.getDisplayName().equals(
+ HdmiUtils.getDefaultDeviceName(address))) {
mService.sendCecCommand(
HdmiCecMessageBuilder.buildGiveOsdNameCommand(mAddress, address));
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 7235a921254d..90d64339eac0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -30,6 +30,7 @@ import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANAL
import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL;
import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
+import android.annotation.Nullable;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPortInfo;
@@ -1147,6 +1148,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
&& getAvrDeviceInfo() != null;
}
+ @Nullable
@ServiceThreadOnly
HdmiDeviceInfo getAvrDeviceInfo() {
assertRunOnServiceThread();
@@ -1157,6 +1159,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
return getSafeAvrDeviceInfo() != null;
}
+ @Nullable
HdmiDeviceInfo getSafeAvrDeviceInfo() {
return mService.getHdmiCecNetwork().getSafeCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index b748ae026cfc..7ceaa959212e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -185,6 +185,12 @@ public class HdmiCecNetwork {
mLocalDevices.clear();
}
+ /**
+ * Get the device info of a local device or a device in the CEC network by a device id.
+ * @param id id of the device to get
+ * @return the device with the given id, or {@code null}
+ */
+ @Nullable
public HdmiDeviceInfo getDeviceInfo(int id) {
return mDeviceInfos.get(id);
}
@@ -717,6 +723,7 @@ public class HdmiCecNetwork {
* @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}.
* Returns null if no logical address matched
*/
+ @Nullable
HdmiDeviceInfo getSafeCecDeviceInfo(int logicalAddress) {
for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
if (info.isCecDevice() && info.getLogicalAddress() == logicalAddress) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 115cafedca93..e6e2f9631d45 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -988,6 +988,7 @@ public class HdmiControlService extends SystemService {
return mCecController.getVendorId();
}
+ @Nullable
@ServiceThreadOnly
HdmiDeviceInfo getDeviceInfo(int logicalAddress) {
assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 73ecbe0432b7..9d2db94cac8e 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -16,6 +16,7 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
import android.hardware.hdmi.IHdmiControlCallback;
import android.util.Slog;
@@ -62,8 +63,7 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
Slog.e(TAG, "Wrong arguments");
return null;
}
- return new OneTouchPlayAction(source, targetAddress,
- callback);
+ return new OneTouchPlayAction(source, targetAddress, callback);
}
private OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress,
@@ -71,8 +71,8 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
this(localDevice, targetAddress, callback,
localDevice.getDeviceInfo().getCecVersion()
>= HdmiControlManager.HDMI_CEC_VERSION_2_0
- && localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo(
- targetAddress).getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0);
+ && getTargetCecVersion(localDevice, targetAddress)
+ >= HdmiControlManager.HDMI_CEC_VERSION_2_0);
}
@VisibleForTesting
@@ -88,9 +88,9 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
// Because only source device can create this action, it's safe to cast.
mSource = source();
sendCommand(HdmiCecMessageBuilder.buildTextViewOn(getSourceAddress(), mTargetAddress));
- boolean targetOnBefore = localDevice().mService.getHdmiCecNetwork()
- .getCecDeviceInfo(mTargetAddress).getDevicePowerStatus()
- == HdmiControlManager.POWER_STATUS_ON;
+
+ boolean targetOnBefore = getTargetDevicePowerStatus(mSource, mTargetAddress,
+ HdmiControlManager.POWER_STATUS_UNKNOWN) == HdmiControlManager.POWER_STATUS_ON;
broadcastActiveSource();
// If the device is not an audio system itself, request the connected audio system to
// turn on.
@@ -98,8 +98,8 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
sendCommand(HdmiCecMessageBuilder.buildSystemAudioModeRequest(getSourceAddress(),
Constants.ADDR_AUDIO_SYSTEM, getSourcePath(), true));
}
- int targetPowerStatus = localDevice().mService.getHdmiCecNetwork()
- .getCecDeviceInfo(mTargetAddress).getDevicePowerStatus();
+ int targetPowerStatus = getTargetDevicePowerStatus(mSource, mTargetAddress,
+ HdmiControlManager.POWER_STATUS_UNKNOWN);
if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) {
queryDevicePowerStatus();
} else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) {
@@ -179,4 +179,23 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
return sendStandbyOnSleep.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
}
+ private static int getTargetCecVersion(HdmiCecLocalDevice localDevice,
+ int targetLogicalAddress) {
+ HdmiDeviceInfo targetDevice = localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo(
+ targetLogicalAddress);
+ if (targetDevice != null) {
+ return targetDevice.getCecVersion();
+ }
+ return HdmiControlManager.HDMI_CEC_VERSION_1_4_B;
+ }
+
+ private static int getTargetDevicePowerStatus(HdmiCecLocalDevice localDevice,
+ int targetLogicalAddress, int defaultPowerStatus) {
+ HdmiDeviceInfo targetDevice = localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo(
+ targetLogicalAddress);
+ if (targetDevice != null) {
+ return targetDevice.getDevicePowerStatus();
+ }
+ return defaultPowerStatus;
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/cec_config.xml b/services/core/java/com/android/server/hdmi/cec_config.xml
deleted file mode 100644
index 191e725181ca..000000000000
--- a/services/core/java/com/android/server/hdmi/cec_config.xml
+++ /dev/null
@@ -1,133 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<cec-settings>
- <setting name="hdmi_cec_enabled"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="hdmi_cec_version"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0x05" />
- <value int-value="0x06" />
- </allowed-values>
- <default-value int-value="0x05" />
- </setting>
- <setting name="send_standby_on_sleep"
- value-type="string"
- user-configurable="true">
- <allowed-values>
- <value string-value="to_tv" />
- <value string-value="broadcast" />
- <value string-value="none" />
- </allowed-values>
- <default-value string-value="to_tv" />
- </setting>
- <setting name="power_state_change_on_active_source_lost"
- value-type="string"
- user-configurable="true">
- <allowed-values>
- <value string-value="none" />
- <value string-value="standby_now" />
- </allowed-values>
- <default-value string-value="none" />
- </setting>
- <setting name="system_audio_mode_muting"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="volume_control_enabled"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="tv_wake_on_one_touch_play"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="tv_send_standby_on_sleep"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="rc_profile_tv"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0x0" />
- <value int-value="0x2" />
- <value int-value="0x6" />
- <value int-value="0xA" />
- <value int-value="0xE" />
- </allowed-values>
- <default-value int-value="0x0" />
- </setting>
- <setting name="rc_profile_source_handles_root_menu"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="rc_profile_source_handles_setup_menu"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="rc_profile_source_handles_contents_menu"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="0" />
- </setting>
- <setting name="rc_profile_source_handles_top_menu"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="0" />
- </setting>
- <setting name="rc_profile_source_handles_media_context_sensitive_menu"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="0" />
- </setting>
-</cec-settings>
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 7dc9a0b2a364..cbe6e69cbef3 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -304,7 +304,7 @@ public class InputManagerService extends IInputManager.Stub
int displayId, InputApplicationHandle application);
private static native void nativeSetFocusedDisplay(long ptr, int displayId);
private static native boolean nativeTransferTouchFocus(long ptr,
- IBinder fromChannelToken, IBinder toChannelToken);
+ IBinder fromChannelToken, IBinder toChannelToken, boolean isDragDrop);
private static native void nativeSetPointerSpeed(long ptr, int speed);
private static native void nativeSetShowTouches(long ptr, boolean enabled);
private static native void nativeSetInteractive(long ptr, boolean interactive);
@@ -1727,12 +1727,14 @@ public class InputManagerService extends IInputManager.Stub
* @param fromChannel The channel of a window that currently has touch focus.
* @param toChannel The channel of the window that should receive touch focus in
* place of the first.
+ * @param isDragDrop True if transfer touch focus for drag and drop.
* @return True if the transfer was successful. False if the window with the
* specified channel did not actually have touch focus at the time of the request.
*/
public boolean transferTouchFocus(@NonNull InputChannel fromChannel,
- @NonNull InputChannel toChannel) {
- return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken());
+ @NonNull InputChannel toChannel, boolean isDragDrop) {
+ return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken(),
+ isDragDrop);
}
/**
@@ -1752,7 +1754,8 @@ public class InputManagerService extends IInputManager.Stub
@NonNull IBinder toChannelToken) {
Objects.nonNull(fromChannelToken);
Objects.nonNull(toChannelToken);
- return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken);
+ return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken,
+ false /* isDragDrop */);
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index a89cb5554825..672ed3d00344 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5838,7 +5838,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
@ShellCommandResult
private int handleShellCommandTraceInputMethod(@NonNull ShellCommand shellCommand) {
- int result = ImeTracing.getInstance().onShellCommand(shellCommand);
+ final String cmd = shellCommand.getNextArgRequired();
+ final PrintWriter pw = shellCommand.getOutPrintWriter();
+ switch (cmd) {
+ case "start":
+ ImeTracing.getInstance().getInstance().startTrace(pw);
+ break;
+ case "stop":
+ ImeTracing.getInstance().stopTrace(pw);
+ break;
+ default:
+ pw.println("Unknown command: " + cmd);
+ pw.println("Input method trace options:");
+ pw.println(" start: Start tracing");
+ pw.println(" stop: Stop tracing");
+ return ShellCommandResult.FAILURE;
+ }
boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
ArrayMap<IBinder, ClientState> clients;
synchronized (mMethodMap) {
@@ -5854,7 +5869,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
}
- return result;
+ return ShellCommandResult.SUCCESS;
}
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 047e3b362b7a..ffea6a743a42 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -345,6 +345,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
*/
private final Object mLock = new Object();
+ /** List of {@link ScreenOnListener}s which do not belong to the default display. */
+ private final SparseArray<ScreenOnListener> mScreenOnListeners = new SparseArray<>();
+
Context mContext;
IWindowManager mWindowManager;
WindowManagerFuncs mWindowManagerFuncs;
@@ -434,8 +437,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
volatile boolean mBeganFromNonInteractive;
volatile boolean mEndCallKeyHandled;
volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
- volatile boolean mGoingToSleep;
- volatile boolean mRequestedOrGoingToSleep;
+
+ /**
+ * {@code true} if the device is entering a low-power state; {@code false otherwise}.
+ *
+ * <p>This differs from {@link #mRequestedOrSleepingDefaultDisplay} which tracks the power state
+ * of the {@link #mDefaultDisplay default display} versus the power state of the entire device.
+ */
+ volatile boolean mDeviceGoingToSleep;
+
+ /**
+ * {@code true} if the {@link #mDefaultDisplay default display} is entering or was requested to
+ * enter a low-power state; {@code false otherwise}.
+ *
+ * <p>This differs from {@link #mDeviceGoingToSleep} which tracks the power state of the entire
+ * device versus the power state of the {@link #mDefaultDisplay default display}.
+ */
+ // TODO(b/178103325): Track sleep/requested sleep for every display.
+ volatile boolean mRequestedOrSleepingDefaultDisplay;
+
volatile boolean mRecentsVisible;
volatile boolean mNavBarVirtualKeyHapticFeedbackEnabled = true;
volatile boolean mPictureInPictureVisible;
@@ -917,13 +937,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case SHORT_PRESS_POWER_NOTHING:
break;
case SHORT_PRESS_POWER_GO_TO_SLEEP:
- goToSleepFromPowerButton(eventTime, 0);
+ sleepDefaultDisplayFromPowerButton(eventTime, 0);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
- goToSleepFromPowerButton(eventTime, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ sleepDefaultDisplayFromPowerButton(eventTime,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
- if (goToSleepFromPowerButton(eventTime,
+ if (sleepDefaultDisplayFromPowerButton(eventTime,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE)) {
launchHomeFromHotKey(DEFAULT_DISPLAY);
}
@@ -951,11 +972,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/**
- * Sends the device to sleep as a result of a power button press.
+ * Sends the default display to sleep as a result of a power button press.
*
- * @return True if the was device was sent to sleep, false if sleep was suppressed.
+ * @return {@code true} if the device was sent to sleep, {@code false} if the device did not
+ * sleep.
*/
- private boolean goToSleepFromPowerButton(long eventTime, int flags) {
+ private boolean sleepDefaultDisplayFromPowerButton(long eventTime, int flags) {
// Before we actually go to sleep, we check the last wakeup reason.
// If the device very recently woke up from a gesture (like user lifting their device)
// then ignore the sleep instruction. This is because users have developed
@@ -975,12 +997,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);
return true;
}
- private void goToSleep(long eventTime, int reason, int flags) {
- mRequestedOrGoingToSleep = true;
+ private void sleepDefaultDisplay(long eventTime, int reason, int flags) {
+ mRequestedOrSleepingDefaultDisplay = true;
mPowerManager.goToSleep(eventTime, reason, flags);
}
@@ -1017,7 +1039,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Global.THEATER_MODE_ON, 1);
if (mGoToSleepOnButtonPressTheaterMode && interactive) {
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+ 0);
}
}
break;
@@ -1126,7 +1149,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case SHORT_PRESS_SLEEP_GO_TO_SLEEP:
case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME:
Slog.i(TAG, "sleepRelease() calling goToSleep(GO_TO_SLEEP_REASON_SLEEP_BUTTON)");
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
break;
}
}
@@ -3511,7 +3534,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
- goToSleep(event.getEventTime(),
+ sleepDefaultDisplay(event.getEventTime(),
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
isWakeKey = false;
}
@@ -3538,10 +3561,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Any activity on the power button stops the accessibility shortcut
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
+ final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState());
+ final boolean interactiveAndOn = interactive && isDefaultDisplayOn;
if (down) {
- interceptPowerKeyDown(event, interactive);
+ interceptPowerKeyDown(event, interactiveAndOn);
} else {
- interceptPowerKeyUp(event, interactive, canceled);
+ interceptPowerKeyUp(event, interactiveAndOn, canceled);
}
break;
}
@@ -3746,7 +3771,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final MutableBoolean outLaunched = new MutableBoolean(false);
final boolean gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event,
interactive, outLaunched);
- if (outLaunched.value && mRequestedOrGoingToSleep) {
+ if (outLaunched.value && mRequestedOrSleepingDefaultDisplay) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
return gesturedServiceIntercepted;
@@ -4088,8 +4113,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pmSleepReason)) + ")");
}
- mGoingToSleep = true;
- mRequestedOrGoingToSleep = true;
+ mDeviceGoingToSleep = true;
+ mRequestedOrSleepingDefaultDisplay = true;
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onStartedGoingToSleep(pmSleepReason);
@@ -4108,8 +4133,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);
- mGoingToSleep = false;
- mRequestedOrGoingToSleep = false;
+ mDeviceGoingToSleep = false;
+ mRequestedOrSleepingDefaultDisplay = false;
mDefaultDisplayPolicy.setAwake(false);
// We must get this work done here because the power manager will drop
@@ -4253,21 +4278,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Called on the DisplayManager's DisplayPowerController thread.
@Override
public void screenTurnedOff(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
-
- if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Display" + displayId + " turned off...");
- updateScreenOffSleepToken(true);
- mDefaultDisplayPolicy.screenTurnedOff();
- synchronized (mLock) {
- if (mKeyguardDelegate != null) {
- mKeyguardDelegate.onScreenTurnedOff();
+ if (displayId == DEFAULT_DISPLAY) {
+ updateScreenOffSleepToken(true);
+ mRequestedOrSleepingDefaultDisplay = false;
+ mDefaultDisplayPolicy.screenTurnedOff();
+ synchronized (mLock) {
+ if (mKeyguardDelegate != null) {
+ mKeyguardDelegate.onScreenTurnedOff();
+ }
+ }
+ mDefaultDisplayRotation.updateOrientationListener();
+ reportScreenStateToVrManager(false);
+ if (mCameraGestureTriggeredDuringGoingToSleep) {
+ wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromPowerKey,
+ PowerManager.WAKE_REASON_CAMERA_LAUNCH,
+ "com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");
}
}
- mDefaultDisplayRotation.updateOrientationListener();
- reportScreenStateToVrManager(false);
}
private long getKeyguardDrawnTimeout() {
@@ -4280,27 +4309,28 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Called on the DisplayManager's DisplayPowerController thread.
@Override
public void screenTurningOn(int displayId, final ScreenOnListener screenOnListener) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
-
- if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Display " + displayId + " turning on...");
- Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
- updateScreenOffSleepToken(false);
- mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
+ if (displayId == DEFAULT_DISPLAY) {
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn",
+ 0 /* cookie */);
+ updateScreenOffSleepToken(false);
+ mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
- synchronized (mLock) {
- if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
- mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
- mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
- getKeyguardDrawnTimeout());
- mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
- } else {
- if (DEBUG_WAKEUP) Slog.d(TAG,
- "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
- mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
+ synchronized (mLock) {
+ if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
+ mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
+ mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
+ getKeyguardDrawnTimeout());
+ mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
+ } else {
+ if (DEBUG_WAKEUP) Slog.d(TAG,
+ "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
+ mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
+ }
}
+ } else {
+ mScreenOnListeners.put(displayId, screenOnListener);
}
}
@@ -4321,11 +4351,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void screenTurningOff(int displayId, ScreenOffListener screenOffListener) {
+ mWindowManagerFuncs.screenTurningOff(displayId, screenOffListener);
if (displayId != DEFAULT_DISPLAY) {
return;
}
- mWindowManagerFuncs.screenTurningOff(screenOffListener);
+ mRequestedOrSleepingDefaultDisplay = true;
synchronized (mLock) {
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onScreenTurningOff();
@@ -4380,6 +4411,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
listener.onScreenOn();
}
+ for (int i = mScreenOnListeners.size() - 1; i >= 0; i--) {
+ final ScreenOnListener screenOnListener = mScreenOnListeners.valueAt(i);
+ if (screenOnListener != null) {
+ screenOnListener.onScreenOn();
+ }
+ }
+ mScreenOnListeners.clear();
+
if (enableScreen) {
try {
mWindowManager.enableScreenIfNeeded();
@@ -4410,7 +4449,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public boolean okToAnimate() {
- return mDefaultDisplayPolicy.isAwake() && !mGoingToSleep;
+ return mDefaultDisplayPolicy.isAwake() && !mDeviceGoingToSleep;
}
/** {@inheritDoc} */
@@ -4777,7 +4816,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mWindowManagerFuncs.lockDeviceNow();
break;
case LID_BEHAVIOR_SLEEP:
- goToSleep(SystemClock.uptimeMillis(),
+ sleepDefaultDisplay(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
break;
diff --git a/services/core/java/com/android/server/policy/SplashScreenSurface.java b/services/core/java/com/android/server/policy/SplashScreenSurface.java
index b9202c334fec..72933a0ad309 100644
--- a/services/core/java/com/android/server/policy/SplashScreenSurface.java
+++ b/services/core/java/com/android/server/policy/SplashScreenSurface.java
@@ -45,7 +45,7 @@ class SplashScreenSurface implements StartingSurface {
}
@Override
- public void remove() {
+ public void remove(boolean animate) {
if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + mAppToken + ": "
+ this + " Callers=" + Debug.getCallers(4));
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index b5a9acacec83..0735977be72a 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -238,8 +238,9 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
/**
* Removes the starting window surface. Do not hold the window manager lock when calling
* this method!
+ * @param animate Whether need to play the default exit animation for starting window.
*/
- void remove();
+ void remove(boolean animate);
}
/**
@@ -303,9 +304,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
/**
* Notifies the window manager that screen is being turned off.
*
+ * @param displayId the ID of the display which is turning off
* @param listener callback to call when display can be turned off
*/
- void screenTurningOff(ScreenOffListener listener);
+ void screenTurningOff(int displayId, ScreenOffListener listener);
/**
* Convert the lid state to a human readable format.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index aeeabe21460c..db3d7ad0c398 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -137,6 +137,7 @@ import static com.android.server.wm.ActivityRecordProto.CLIENT_VISIBLE;
import static com.android.server.wm.ActivityRecordProto.DEFER_HIDING_CLIENT;
import static com.android.server.wm.ActivityRecordProto.FILLS_PARENT;
import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK;
+import static com.android.server.wm.ActivityRecordProto.IN_SIZE_COMPAT_MODE;
import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
@@ -2114,7 +2115,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
if (abort) {
- surface.remove();
+ surface.remove(false /* prepareAnimation */);
}
} else {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s",
@@ -2128,7 +2129,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated,
TaskSnapshot snapshot) {
- if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+ if ((newTask || !processRunning || (taskSwitch && !activityCreated))
+ && !isActivityTypeHome()) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
if (isSnapshotCompatible(snapshot)) {
@@ -2179,7 +2181,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
+ ActivityRecord.this + " state " + mTransferringSplashScreenState);
if (isTransferringSplashScreen()) {
mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
- // TODO show default exit splash screen animation
removeStartingWindow();
}
}
@@ -2196,6 +2197,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
private boolean transferSplashScreenIfNeeded() {
+ if (!mWmService.mStartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER) {
+ return false;
+ }
if (!mHandleExitSplashScreen || mStartingSurface == null || mStartingWindow == null
|| mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH) {
return false;
@@ -2265,10 +2269,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// no matter what, remove the starting window.
mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
- removeStartingWindow();
+ removeStartingWindowAnimation(false /* prepareAnimation */);
}
void removeStartingWindow() {
+ removeStartingWindowAnimation(true /* prepareAnimation */);
+ }
+
+ void removeStartingWindowAnimation(boolean prepareAnimation) {
if (transferSplashScreenIfNeeded()) {
return;
}
@@ -2313,7 +2321,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mWmService.mAnimationHandler.post(() -> {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing startingView=%s", surface);
try {
- surface.remove();
+ surface.remove(prepareAnimation);
} catch (Exception e) {
Slog.w(TAG_WM, "Exception when removing starting window", e);
}
@@ -6190,7 +6198,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Remove orphaned starting window.
if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
mStartingWindowState = STARTING_WINDOW_REMOVED;
- removeStartingWindow();
+ removeStartingWindowAnimation(false /* prepareAnimation */);
}
if (isState(INITIALIZING) && !shouldBeVisible(
true /* behindFullscreenActivity */, true /* ignoringKeyguard */)) {
@@ -8255,6 +8263,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
proto.write(PROC_ID, app.getPid());
}
proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled());
+ proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
}
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 32152ec85493..01f0359fa548 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1410,9 +1410,9 @@ public class DisplayPolicy {
boolean localClient) {
final InsetsState state =
mDisplayContent.getInsetsPolicy().getInsetsForWindowMetrics(attrs);
- final boolean inSizeCompatMode = WindowState.inSizeCompatMode(attrs, windowToken);
- outInsetsState.set(state, inSizeCompatMode || localClient);
- if (inSizeCompatMode) {
+ final boolean hasCompatScale = WindowState.hasCompatScale(attrs, windowToken);
+ outInsetsState.set(state, hasCompatScale || localClient);
+ if (hasCompatScale) {
final float compatScale = windowToken != null
? windowToken.getSizeCompatScale()
: mDisplayContent.mCompatibleScreenScale;
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 627af9149fe5..1120a074aa8c 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -182,8 +182,6 @@ class DragDropController {
if (SHOW_LIGHT_TRANSACTIONS) {
Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
}
-
- mDragState.notifyLocationLocked(touchX, touchY);
} finally {
if (surface != null) {
surface.release();
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 0b3c065e0e73..08d5e800a808 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -515,50 +515,6 @@ class DragState {
mTransaction.setPosition(mSurfaceControl, x - mThumbOffsetX, y - mThumbOffsetY).apply();
ProtoLog.i(WM_SHOW_TRANSACTIONS, "DRAG %s: pos=(%d,%d)", mSurfaceControl,
(int) (x - mThumbOffsetX), (int) (y - mThumbOffsetY));
-
- notifyLocationLocked(x, y);
- }
-
- void notifyLocationLocked(float x, float y) {
- // Tell the affected window
- WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
- if (touchedWin != null && !isWindowNotified(touchedWin)) {
- // The drag point is over a window which was not notified about a drag start.
- // Pretend it's over empty space.
- touchedWin = null;
- }
-
- try {
- final int myPid = Process.myPid();
-
- // have we dragged over a new window?
- if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) {
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "sending DRAG_EXITED to " + mTargetWindow);
- }
- // force DRAG_EXITED_EVENT if appropriate
- DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
- 0, 0, 0, 0, null, null, null, null, null, false);
- mTargetWindow.mClient.dispatchDragEvent(evt);
- if (myPid != mTargetWindow.mSession.mPid) {
- evt.recycle();
- }
- }
- if (touchedWin != null) {
- if (false && DEBUG_DRAG) {
- Slog.d(TAG_WM, "sending DRAG_LOCATION to " + touchedWin);
- }
- DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
- x, y, mThumbOffsetX, mThumbOffsetY, null, null, null, null, null, false);
- touchedWin.mClient.dispatchDragEvent(evt);
- if (myPid != touchedWin.mSession.mPid) {
- evt.recycle();
- }
- }
- } catch (RemoteException e) {
- Slog.w(TAG_WM, "can't send drag notification to windows");
- }
- mTargetWindow = touchedWin;
}
/**
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 45c4233b40aa..35e54912b33e 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -30,7 +30,6 @@ import static com.android.server.wm.InsetsSourceProviderProto.CONTROLLABLE;
import static com.android.server.wm.InsetsSourceProviderProto.CONTROL_TARGET;
import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL;
import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL_TARGET;
-import static com.android.server.wm.InsetsSourceProviderProto.FINISH_SEAMLESS_ROTATE_FRAME_NUMBER;
import static com.android.server.wm.InsetsSourceProviderProto.FRAME;
import static com.android.server.wm.InsetsSourceProviderProto.IME_OVERRIDDEN_FRAME;
import static com.android.server.wm.InsetsSourceProviderProto.IS_LEASH_READY_FOR_DISPATCHING;
@@ -59,6 +58,7 @@ import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* Controller for a specific inset source on the server. It's called provider as it provides the
@@ -84,6 +84,16 @@ class InsetsSourceProvider {
private final Rect mImeOverrideFrame = new Rect();
private boolean mIsLeashReadyForDispatching;
+ private final Consumer<Transaction> mSetLeashPositionConsumer = t -> {
+ if (mControl != null) {
+ final SurfaceControl leash = mControl.getLeash();
+ if (leash != null) {
+ final Point position = mControl.getSurfacePosition();
+ t.setPosition(leash, position.x, position.y);
+ }
+ }
+ };
+
/** The visibility override from the current controlling window. */
private boolean mClientVisible;
@@ -149,7 +159,6 @@ class InsetsSourceProvider {
// TODO: Ideally, we should wait for the animation to finish so previous window can
// animate-out as new one animates-in.
mWin.cancelAnimation();
- mWin.mPendingPositionChanged = null;
mWin.mProvidedInsetsSources.remove(mSource.getType());
}
ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
@@ -248,31 +257,16 @@ class InsetsSourceProvider {
if (mControl != null) {
final Point position = getWindowFrameSurfacePosition();
if (mControl.setSurfacePosition(position.x, position.y) && mControlTarget != null) {
- if (!mWin.getWindowFrames().didFrameSizeChange()) {
- updateLeashPosition(-1 /* frameNumber */);
- } else if (mWin.mInRelayout) {
- updateLeashPosition(mWin.getFrameNumber());
+ if (mWin.getWindowFrames().didFrameSizeChange()) {
+ mWin.applyWithNextDraw(mSetLeashPositionConsumer);
} else {
- mWin.mPendingPositionChanged = this;
+ mSetLeashPositionConsumer.accept(mWin.getPendingTransaction());
}
mStateController.notifyControlChanged(mControlTarget);
}
}
}
- void updateLeashPosition(long frameNumber) {
- if (mControl == null) {
- return;
- }
- final SurfaceControl leash = mControl.getLeash();
- if (leash != null) {
- final Transaction t = mDisplayContent.getPendingTransaction();
- final Point position = mControl.getSurfacePosition();
- t.setPosition(leash, position.x, position.y);
- deferTransactionUntil(t, leash, frameNumber);
- }
- }
-
private Point getWindowFrameSurfacePosition() {
final Rect frame = mWin.getFrame();
final Point position = new Point();
@@ -280,14 +274,6 @@ class InsetsSourceProvider {
return position;
}
- private void deferTransactionUntil(Transaction t, SurfaceControl leash, long frameNumber) {
- if (frameNumber >= 0) {
- final SurfaceControl barrier = mWin.getClientViewRootSurface();
- t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
- t.deferTransactionUntil(leash, barrier, frameNumber);
- }
- }
-
/**
* @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
*/
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index ef4a40f4837c..6c4613526e88 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -40,9 +40,8 @@ public class StartingSurfaceController {
private static final String TAG = TAG_WITH_CLASS_NAME
? StartingSurfaceController.class.getSimpleName() : TAG_WM;
/** Set to {@code true} to enable shell starting surface drawer. */
- private static final boolean DEBUG_ENABLE_SHELL_DRAWER =
- SystemProperties.getBoolean("persist.debug.shell_starting_surface", false);
-
+ static final boolean DEBUG_ENABLE_SHELL_DRAWER =
+ SystemProperties.getBoolean("persist.debug.shell_starting_surface", true);
private final WindowManagerService mService;
public StartingSurfaceController(WindowManagerService wm) {
@@ -139,8 +138,9 @@ public class StartingSurfaceController {
}
@Override
- public void remove() {
- mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask);
+ public void remove(boolean animate) {
+ mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask,
+ animate);
}
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 04a254c2aabf..a4b4726fe070 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4135,6 +4135,8 @@ class Task extends WindowContainer<WindowContainer> {
final StartingWindowInfo info = new StartingWindowInfo();
info.taskInfo = getTaskInfo();
+ info.isKeyguardOccluded =
+ mAtmService.mKeyguardController.isDisplayOccluded(DEFAULT_DISPLAY);
final ActivityRecord topActivity = getTopMostActivity();
if (topActivity != null) {
info.startingWindowTypeParameter =
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index fc6db61bdbcd..385dc79567fa 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -32,6 +32,7 @@ import android.app.WindowConfiguration;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ParceledListSlice;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
@@ -131,10 +132,28 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
});
}
- void removeStartingWindow(Task task) {
+ void removeStartingWindow(Task task, boolean prepareAnimation) {
mDeferTaskOrgCallbacksConsumer.accept(() -> {
+ SurfaceControl firstWindowLeash = null;
+ Rect mainFrame = null;
+ // TODO enable shift up animation once we fix flicker test
+// final boolean playShiftUpAnimation = !task.inMultiWindowMode();
+// if (prepareAnimation && playShiftUpAnimation) {
+// final ActivityRecord topActivity = task.topActivityWithStartingWindow();
+// if (topActivity != null) {
+// final WindowState mainWindow =
+// topActivity.findMainWindow(false/* includeStartingApp */);
+// if (mainWindow != null) {
+ // TODO create proper leash instead of the copied SC
+// firstWindowLeash = new SurfaceControl(mainWindow.getSurfaceControl(),
+// "TaskOrganizerController.removeStartingWindow");
+// mainFrame = mainWindow.getRelativeFrame();
+// }
+// }
+// }
try {
- mTaskOrganizer.removeStartingWindow(task.mTaskId);
+ mTaskOrganizer.removeStartingWindow(task.mTaskId, firstWindowLeash, mainFrame,
+ prepareAnimation);
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
}
@@ -249,8 +268,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
mOrganizer.addStartingWindow(t, appToken, launchTheme);
}
- void removeStartingWindow(Task t) {
- mOrganizer.removeStartingWindow(t);
+ void removeStartingWindow(Task t, boolean prepareAnimation) {
+ mOrganizer.removeStartingWindow(t, prepareAnimation);
}
void copySplashScreenView(Task t) {
@@ -495,14 +514,14 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return true;
}
- void removeStartingWindow(Task task) {
+ void removeStartingWindow(Task task, boolean prepareAnimation) {
final Task rootTask = task.getRootTask();
if (rootTask == null || rootTask.mTaskOrganizer == null) {
return;
}
final TaskOrganizerState state =
mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
- state.removeStartingWindow(task);
+ state.removeStartingWindow(task, prepareAnimation);
}
boolean copySplashScreenView(Task task) {
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index 9d35c25fc546..525420e045b5 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -188,7 +188,8 @@ class TaskPositioningController {
transferFocusFromWin = displayContent.mCurrentFocus;
}
if (!mInputManager.transferTouchFocus(
- transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel)) {
+ transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel,
+ false /* isDragDrop */)) {
Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
cleanUpTaskPositioner();
return false;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index b810de99ee10..8915eba3d509 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -37,6 +37,7 @@ import android.os.Handler;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
+import android.view.Display;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.ThreadedRenderer;
@@ -624,7 +625,7 @@ class TaskSnapshotController {
/**
* Called when screen is being turned off.
*/
- void screenTurningOff(ScreenOffListener listener) {
+ void screenTurningOff(int displayId, ScreenOffListener listener) {
if (shouldDisableSnapshots()) {
listener.onScreenOff();
return;
@@ -635,7 +636,7 @@ class TaskSnapshotController {
try {
synchronized (mService.mGlobalLock) {
mTmpTasks.clear();
- mService.mRoot.forAllTasks(task -> {
+ mService.mRoot.getDisplayContent(displayId).forAllTasks(task -> {
// Since RecentsAnimation will handle task snapshot while switching apps
// with the best capture timing (e.g. IME window capture), No need
// additional task capture while task is controlled by RecentsAnimation.
@@ -645,7 +646,7 @@ class TaskSnapshotController {
});
// Allow taking snapshot of home when turning screen off to reduce the delay of
// waking from secure lock to home.
- final boolean allowSnapshotHome =
+ final boolean allowSnapshotHome = displayId == Display.DEFAULT_DISPLAY &&
mService.mPolicy.isKeyguardSecure(mService.mCurrentUserId);
snapshotTasks(mTmpTasks, allowSnapshotHome);
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 07610ab6d546..79a6bd7dcd2c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -281,13 +281,14 @@ class TaskSnapshotSurface implements StartingSurface {
}
@Override
- public void remove() {
+ public void remove(boolean animate) {
synchronized (mService.mGlobalLock) {
final long now = SystemClock.uptimeMillis();
if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
// Show the latest content as soon as possible for unlocking to home.
&& mActivityType != ACTIVITY_TYPE_HOME) {
- mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
+ mHandler.postAtTime(() -> remove(false /* prepareAnimation */),
+ mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"Defer removing snapshot surface in %dms", (now - mShownTime));
@@ -517,7 +518,7 @@ class TaskSnapshotSurface implements StartingSurface {
// The orientation of the screen is changing. We better remove the snapshot ASAP as
// we are going to wait on the new window in any case to unfreeze the screen, and
// the starting window is not needed anymore.
- sHandler.post(mOuter::remove);
+ sHandler.post(() -> mOuter.remove(false /* prepareAnimation */));
}
if (reportDraw) {
sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 9245f8c3efe5..ffd6d21c1026 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -113,7 +113,7 @@ public class WindowFrames {
}
/**
- * @return true if the width or height has changed since last reported to the client.
+ * @return true if the width or height has changed since last updating resizing window.
*/
boolean didFrameSizeChange() {
return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
@@ -135,6 +135,13 @@ public class WindowFrames {
}
/**
+ * @return true if the width or height has changed since last reported to the client.
+ */
+ boolean isFrameSizeChangeReported() {
+ return mFrameSizeChanged || didFrameSizeChange();
+ }
+
+ /**
* Resets the size changed flags so they're all set to false again. This should be called
* after the frames are reported to client.
*/
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 7450782364f4..53ebfb2c6e0e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -221,7 +221,8 @@ public abstract class WindowManagerInternal {
DragState state, Display display, InputManagerService service,
InputChannel source) {
state.register(display);
- return service.transferTouchFocus(source, state.getInputChannel());
+ return service.transferTouchFocus(source, state.getInputChannel(),
+ true /* isDragDrop */);
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0a75924b0266..3007f0fed2a0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2234,11 +2234,6 @@ public class WindowManagerService extends IWindowManager.Stub
final DisplayContent dc = win.getDisplayContent();
- if (win.mPendingPositionChanged != null) {
- win.mPendingPositionChanged.updateLeashPosition(frameNumber);
- win.mPendingPositionChanged = null;
- }
-
if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE) {
win.prepareDrawHandlers();
result |= RELAYOUT_RES_BLAST_SYNC;
@@ -2985,8 +2980,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void screenTurningOff(ScreenOffListener listener) {
- mTaskSnapshotController.screenTurningOff(listener);
+ public void screenTurningOff(int displayId, ScreenOffListener listener) {
+ mTaskSnapshotController.screenTurningOff(displayId, listener);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4313ea4039fc..7ebc1cc6d5c1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -168,8 +168,8 @@ import static com.android.server.wm.WindowStateProto.FINISHED_SEAMLESS_ROTATION_
import static com.android.server.wm.WindowStateProto.FORCE_SEAMLESS_ROTATION;
import static com.android.server.wm.WindowStateProto.GIVEN_CONTENT_INSETS;
import static com.android.server.wm.WindowStateProto.GLOBAL_SCALE;
+import static com.android.server.wm.WindowStateProto.HAS_COMPAT_SCALE;
import static com.android.server.wm.WindowStateProto.HAS_SURFACE;
-import static com.android.server.wm.WindowStateProto.IN_SIZE_COMPAT_MODE;
import static com.android.server.wm.WindowStateProto.IS_ON_SCREEN;
import static com.android.server.wm.WindowStateProto.IS_READY_FOR_DISPLAY;
import static com.android.server.wm.WindowStateProto.IS_VISIBLE;
@@ -726,8 +726,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
private InsetsState mFrozenInsetsState;
- @Nullable InsetsSourceProvider mPendingPositionChanged;
-
private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
private KeyInterceptionInfo mKeyInterceptionInfo;
@@ -774,6 +772,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
updateSurfacePosition(t);
};
+ private final Consumer<SurfaceControl.Transaction> mSetSurfacePositionConsumer = t -> {
+ if (mSurfaceControl != null && mSurfaceControl.isValid()) {
+ t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+ }
+ };
+
/**
* @see #setSurfaceTranslationY(int)
*/
@@ -1089,18 +1093,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* scaling override set.
* @see CompatModePackages#getCompatScale
* @see android.content.res.CompatibilityInfo#supportsScreen
- * @see ActivityRecord#inSizeCompatMode()
+ * @see ActivityRecord#hasSizeCompatBounds()
*/
- boolean inSizeCompatMode() {
- return mOverrideScale != 1f || inSizeCompatMode(mAttrs, mActivityRecord);
+ boolean hasCompatScale() {
+ return mOverrideScale != 1f || hasCompatScale(mAttrs, mActivityRecord);
}
/**
* @return {@code true} if the application runs in size compatibility mode.
* @see android.content.res.CompatibilityInfo#supportsScreen
- * @see ActivityRecord#inSizeCompatMode()
+ * @see ActivityRecord#hasSizeCompatBounds()
*/
- static boolean inSizeCompatMode(WindowManager.LayoutParams attrs, WindowToken windowToken) {
+ static boolean hasCompatScale(WindowManager.LayoutParams attrs, WindowToken windowToken) {
return (attrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0
|| (windowToken != null && windowToken.hasSizeCompatBounds()
// Exclude starting window because it is not displayed by the application.
@@ -1305,7 +1309,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
windowFrames.offsetFrames(-layoutXDiff, -layoutYDiff);
windowFrames.mCompatFrame.set(windowFrames.mFrame);
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
// Also the scaled frame that we report to the app needs to be
// adjusted to be in its coordinate space.
windowFrames.mCompatFrame.scale(mInvGlobalScale);
@@ -1577,7 +1581,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
InsetsState getCompatInsetsState() {
InsetsState state = getInsetsState();
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
state = new InsetsState(state, true);
state.scale(mInvGlobalScale);
}
@@ -1715,7 +1719,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
void prelayout() {
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
if (mOverrideScale != 1f) {
mGlobalScale = mToken.hasSizeCompatBounds()
? mToken.getSizeCompatScale() * mOverrideScale
@@ -2129,6 +2133,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
: getTask().getWindowConfiguration().hasMovementAnimations();
if (mToken.okToAnimate()
&& (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
+ && !mWindowFrames.didFrameSizeChange()
+ && !surfaceInsetsChanging()
&& !isDragResizing()
&& hasMovementAnimation
&& !mWinAnimator.mLastHidden
@@ -3629,7 +3635,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void fillClientWindowFrames(ClientWindowFrames outFrames) {
outFrames.frame.set(mWindowFrames.mCompatFrame);
outFrames.displayFrame.set(mWindowFrames.mDisplayFrame);
- if (mInvGlobalScale != 1.0f && inSizeCompatMode()) {
+ if (mInvGlobalScale != 1.0f && hasCompatScale()) {
outFrames.displayFrame.scale(mInvGlobalScale);
}
@@ -4029,7 +4035,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
proto.write(PENDING_SEAMLESS_ROTATION, mPendingSeamlessRotate != null);
proto.write(FINISHED_SEAMLESS_ROTATION_FRAME, mFinishSeamlessRotateFrameNumber);
proto.write(FORCE_SEAMLESS_ROTATION, mForceSeamlesslyRotate);
- proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
+ proto.write(HAS_COMPAT_SCALE, hasCompatScale());
proto.write(GLOBAL_SCALE, mGlobalScale);
proto.end(token);
}
@@ -4131,7 +4137,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
pw.println(prefix + "mHasSurface=" + mHasSurface
+ " isReadyForDisplay()=" + isReadyForDisplay()
+ " mWindowRemovalAllowed=" + mWindowRemovalAllowed);
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
pw.println(prefix + "mCompatFrame=" + mWindowFrames.mCompatFrame.toShortString(sTmpSB));
}
if (dumpAll) {
@@ -4254,18 +4260,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
float x, y;
int w,h;
- final boolean inSizeCompatMode = inSizeCompatMode();
+ final boolean hasCompatScale = hasCompatScale();
if ((mAttrs.flags & FLAG_SCALED) != 0) {
if (mAttrs.width < 0) {
w = pw;
- } else if (inSizeCompatMode) {
+ } else if (hasCompatScale) {
w = (int)(mAttrs.width * mGlobalScale + .5f);
} else {
w = mAttrs.width;
}
if (mAttrs.height < 0) {
h = ph;
- } else if (inSizeCompatMode) {
+ } else if (hasCompatScale) {
h = (int)(mAttrs.height * mGlobalScale + .5f);
} else {
h = mAttrs.height;
@@ -4273,21 +4279,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
} else {
if (mAttrs.width == MATCH_PARENT) {
w = pw;
- } else if (inSizeCompatMode) {
+ } else if (hasCompatScale) {
w = (int)(mRequestedWidth * mGlobalScale + .5f);
} else {
w = mRequestedWidth;
}
if (mAttrs.height == MATCH_PARENT) {
h = ph;
- } else if (inSizeCompatMode) {
+ } else if (hasCompatScale) {
h = (int)(mRequestedHeight * mGlobalScale + .5f);
} else {
h = mRequestedHeight;
}
}
- if (inSizeCompatMode) {
+ if (hasCompatScale) {
x = mAttrs.x * mGlobalScale;
y = mAttrs.y * mGlobalScale;
} else {
@@ -4315,7 +4321,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// We need to make sure we update the CompatFrame as it is used for
// cropping decisions, etc, on systems where we lack a decor layer.
windowFrames.mCompatFrame.set(windowFrames.mFrame);
- if (inSizeCompatMode) {
+ if (hasCompatScale) {
// See comparable block in computeFrameLw.
windowFrames.mCompatFrame.scale(mInvGlobalScale);
}
@@ -4433,7 +4439,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
float translateToWindowX(float x) {
float winX = x - mWindowFrames.mFrame.left;
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
winX *= mGlobalScale;
}
return winX;
@@ -4441,7 +4447,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
float translateToWindowY(float y) {
float winY = y - mWindowFrames.mFrame.top;
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
winY *= mGlobalScale;
}
return winY;
@@ -5318,13 +5324,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// prior to the rotation.
if (!mSurfaceAnimator.hasLeash() && mPendingSeamlessRotate == null
&& !mLastSurfacePosition.equals(mSurfacePosition)) {
- t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+ final boolean frameSizeChanged = mWindowFrames.isFrameSizeChangeReported();
+ final boolean surfaceInsetsChanged = surfaceInsetsChanging();
+ final boolean surfaceSizeChanged = frameSizeChanged || surfaceInsetsChanged;
mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
- if (surfaceInsetsChanging() && mWinAnimator.hasSurface()) {
+ if (surfaceInsetsChanged) {
mLastSurfaceInsets.set(mAttrs.surfaceInsets);
- t.deferTransactionUntil(mSurfaceControl,
- mWinAnimator.mSurfaceController.mSurfaceControl,
- getFrameNumber());
+ }
+ if (surfaceSizeChanged) {
+ applyWithNextDraw(mSetSurfacePositionConsumer);
+ } else {
+ mSetSurfacePositionConsumer.accept(t);
}
}
}
@@ -5372,7 +5382,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* scaled, the insets also need to be scaled for surface position in global coordinate.
*/
private void transformSurfaceInsetsPosition(Point outPos, Rect surfaceInsets) {
- if (!inSizeCompatMode()) {
+ if (!hasCompatScale()) {
outPos.x = surfaceInsets.left;
outPos.y = surfaceInsets.top;
return;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 10705af9ac38..be06d0395499 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1783,8 +1783,9 @@ static void nativeSetSystemUiLightsOut(JNIEnv* /* env */, jclass /* clazz */, jl
im->setSystemUiLightsOut(lightsOut);
}
-static jboolean nativeTransferTouchFocus(JNIEnv* env,
- jclass /* clazz */, jlong ptr, jobject fromChannelTokenObj, jobject toChannelTokenObj) {
+static jboolean nativeTransferTouchFocus(JNIEnv* env, jclass /* clazz */, jlong ptr,
+ jobject fromChannelTokenObj, jobject toChannelTokenObj,
+ jboolean isDragDrop) {
if (fromChannelTokenObj == nullptr || toChannelTokenObj == nullptr) {
return JNI_FALSE;
}
@@ -1793,8 +1794,8 @@ static jboolean nativeTransferTouchFocus(JNIEnv* env,
sp<IBinder> toChannelToken = ibinderForJavaObject(env, toChannelTokenObj);
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- if (im->getInputManager()->getDispatcher()->transferTouchFocus(
- fromChannelToken, toChannelToken)) {
+ if (im->getInputManager()->getDispatcher()->transferTouchFocus(fromChannelToken, toChannelToken,
+ isDragDrop)) {
return JNI_TRUE;
} else {
return JNI_FALSE;
@@ -2267,7 +2268,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
(void*)nativeRequestPointerCapture},
{"nativeSetInputDispatchMode", "(JZZ)V", (void*)nativeSetInputDispatchMode},
{"nativeSetSystemUiLightsOut", "(JZ)V", (void*)nativeSetSystemUiLightsOut},
- {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)Z",
+ {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;Z)Z",
(void*)nativeTransferTouchFocus},
{"nativeSetPointerSpeed", "(JI)V", (void*)nativeSetPointerSpeed},
{"nativeSetShowTouches", "(JZ)V", (void*)nativeSetShowTouches},
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index 6a8f6d419786..d43cf3f59170 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -45,13 +45,6 @@ xsd_config {
}
xsd_config {
- name: "cec-config",
- srcs: ["cec-config/cec-config.xsd"],
- api_dir: "cec-config/schema",
- package_name: "com.android.server.hdmi.cec.config",
-}
-
-xsd_config {
name: "device-state-config",
srcs: ["device-state-config/device-state-config.xsd"],
api_dir: "device-state-config/schema",
diff --git a/services/core/xsd/cec-config/cec-config.xsd b/services/core/xsd/cec-config/cec-config.xsd
deleted file mode 100644
index b59c93cce332..000000000000
--- a/services/core/xsd/cec-config/cec-config.xsd
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema version="2.0"
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xs:element name="cec-settings">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="setting" type="setting" minOccurs="0" maxOccurs="unbounded"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:complexType name="setting">
- <xs:attribute name="name" type="xs:string"/>
- <xs:attribute name="value-type" type="xs:string"/>
- <xs:attribute name="user-configurable" type="xs:boolean"/>
- <xs:element name="allowed-values" type="value-list" minOccurs="1" maxOccurs="1"/>
- <xs:element name="default-value" type="value" minOccurs="1" maxOccurs="1"/>
- </xs:complexType>
- <xs:complexType name="value-list">
- <xs:sequence>
- <xs:element name="value" type="value" minOccurs="1" maxOccurs="unbounded"/>
- </xs:sequence>
- </xs:complexType>
- <xs:complexType name="value">
- <xs:attribute name="string-value" type="xs:string"/>
- <xs:attribute name="int-value" type="xs:string"/>
- </xs:complexType>
-</xs:schema>
diff --git a/services/core/xsd/cec-config/schema/current.txt b/services/core/xsd/cec-config/schema/current.txt
deleted file mode 100644
index 75872d4fb8a7..000000000000
--- a/services/core/xsd/cec-config/schema/current.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-// Signature format: 2.0
-package com.android.server.hdmi.cec.config {
-
- public class CecSettings {
- ctor public CecSettings();
- method public java.util.List<com.android.server.hdmi.cec.config.Setting> getSetting();
- }
-
- public class Setting {
- ctor public Setting();
- method public com.android.server.hdmi.cec.config.ValueList getAllowedValues();
- method public com.android.server.hdmi.cec.config.Value getDefaultValue();
- method public String getName();
- method public boolean getUserConfigurable();
- method public String getValueType();
- method public void setAllowedValues(com.android.server.hdmi.cec.config.ValueList);
- method public void setDefaultValue(com.android.server.hdmi.cec.config.Value);
- method public void setName(String);
- method public void setUserConfigurable(boolean);
- method public void setValueType(String);
- }
-
- public class Value {
- ctor public Value();
- method public String getIntValue();
- method public String getStringValue();
- method public void setIntValue(String);
- method public void setStringValue(String);
- }
-
- public class ValueList {
- ctor public ValueList();
- method public java.util.List<com.android.server.hdmi.cec.config.Value> getValue();
- }
-
- public class XmlParser {
- ctor public XmlParser();
- method public static com.android.server.hdmi.cec.config.CecSettings read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- }
-
-}
-
diff --git a/services/core/xsd/cec-config/schema/last_current.txt b/services/core/xsd/cec-config/schema/last_current.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/services/core/xsd/cec-config/schema/last_current.txt
+++ /dev/null
diff --git a/services/core/xsd/cec-config/schema/last_removed.txt b/services/core/xsd/cec-config/schema/last_removed.txt
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/services/core/xsd/cec-config/schema/last_removed.txt
+++ /dev/null
diff --git a/services/core/xsd/cec-config/schema/removed.txt b/services/core/xsd/cec-config/schema/removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/services/core/xsd/cec-config/schema/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1590ef1c4cb9..6e63454385c5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2969,7 +2969,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider {
@Override
- public boolean isUserDeviceOwner(int userId, ComponentName who) {
+ public boolean isDeviceOwner(int userId, ComponentName who) {
return mOwners.isDeviceOwnerUserId(userId)
&& mOwners.getDeviceOwnerComponent().equals(who);
}
@@ -2999,14 +2999,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return component -> findAdmin(component, userId, /* throwForMissingPermission= */
false);
}
+
+ @Override
+ public int[] getUsersForUpgrade() {
+ List<UserInfo> allUsers = mUserManager.getUsers();
+ return allUsers.stream().mapToInt(u -> u.id).toArray();
+ }
}
private void performPolicyVersionUpgrade() {
- List<UserInfo> allUsers = mUserManager.getUsers();
PolicyVersionUpgrader upgrader = new PolicyVersionUpgrader(
new DpmsUpgradeDataProvider());
- upgrader.upgradePolicy(allUsers.stream().mapToInt(u -> u.id).toArray(), DPMS_VERSION);
+ upgrader.upgradePolicy(DPMS_VERSION);
}
private void revertTransferOwnershipIfNecessaryLocked() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
index c20d0f5f5f5f..19a7659f4d60 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
@@ -33,7 +33,7 @@ public interface PolicyUpgraderDataProvider {
* Returns true if the provided {@code userId} is a device owner. May affect some policy
* defaults.
*/
- boolean isUserDeviceOwner(int userId, ComponentName who);
+ boolean isDeviceOwner(int userId, ComponentName who);
/**
* Returns true if the storage manager indicates file-based encryption is enabled.
@@ -60,4 +60,9 @@ public interface PolicyUpgraderDataProvider {
* user.
*/
Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId);
+
+ /**
+ * Returns the users to upgrade.
+ */
+ int[] getUsersForUpgrade();
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
index 2ab4b66a6831..6bc7ba6499ac 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
@@ -62,7 +62,7 @@ public class PolicyVersionUpgrader {
* managed profile user IDs.
* @param dpmsVersion The version to upgrade to.
*/
- public void upgradePolicy(int[] allUsers, int dpmsVersion) {
+ public void upgradePolicy(int dpmsVersion) {
int oldVersion = readVersion();
if (oldVersion >= dpmsVersion) {
Slog.i(LOG_TAG, String.format("Current version %d, latest version %d, not upgrading.",
@@ -70,6 +70,8 @@ public class PolicyVersionUpgrader {
return;
}
+ final int[] allUsers = mProvider.getUsersForUpgrade();
+
//NOTE: The current version is provided in case the XML file format changes in a
// non-backwards-compatible way, so that DeviceAdminData could load it with
// old tags, for example.
@@ -94,7 +96,7 @@ public class PolicyVersionUpgrader {
continue;
}
for (ActiveAdmin admin : userData.mAdminList) {
- if (mProvider.isUserDeviceOwner(userId, admin.info.getComponent())) {
+ if (mProvider.isDeviceOwner(userId, admin.info.getComponent())) {
Slog.i(LOG_TAG, String.format(
"Marking Device Owner in user %d for permission grant ", userId));
admin.mAdminCanGrantSensorsPermissions = true;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index 2fe47d3ff184..2fe2f40f34be 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -65,9 +65,10 @@ public class PolicyVersionUpgraderTest {
Map<Integer, ComponentName> mUserToComponent = new HashMap<>();
Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo = new HashMap<>();
File mDataDir;
+ int[] mUsers;
@Override
- public boolean isUserDeviceOwner(int userId, ComponentName who) {
+ public boolean isDeviceOwner(int userId, ComponentName who) {
return userId == mDeviceOwnerUserId && mDeviceOwnerComponent.equals(who);
}
@@ -105,6 +106,11 @@ public class PolicyVersionUpgraderTest {
public Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId) {
return componentName -> mComponentToDeviceAdminInfo.get(componentName);
}
+
+ @Override
+ public int[] getUsersForUpgrade() {
+ return mUsers;
+ }
}
private final Context mRealTestContext = InstrumentationRegistry.getTargetContext();
@@ -126,16 +132,17 @@ public class PolicyVersionUpgraderTest {
ActivityInfo activityInfo = createActivityInfo(mFakeAdmin);
DeviceAdminInfo dai = createDeviceAdminInfo(activityInfo);
mProvider.mComponentToDeviceAdminInfo.put(mFakeAdmin, dai);
+ mProvider.mUsers = new int[] {0};
}
@Test
public void testSameVersionDoesNothing() throws IOException {
- int[] users = new int[] {0};
writeVersionToXml(DevicePolicyManagerService.DPMS_VERSION);
- preparePoliciesFile(users[0]);
- String oldContents = readPoliciesFile(0);
+ final int userId = mProvider.mUsers[0];
+ preparePoliciesFile(userId);
+ String oldContents = readPoliciesFile(userId);
- mUpgrader.upgradePolicy(users, DevicePolicyManagerService.DPMS_VERSION);
+ mUpgrader.upgradePolicy(DevicePolicyManagerService.DPMS_VERSION);
String newContents = readPoliciesFile(0);
assertThat(newContents).isEqualTo(oldContents);
@@ -144,18 +151,18 @@ public class PolicyVersionUpgraderTest {
@Test
public void testUpgrade0To1RemovesPasswordMetrics() throws IOException, XmlPullParserException {
final String activePasswordTag = "active-password";
- int[] users = new int[] {0, 10};
+ mProvider.mUsers = new int[] {0, 10};
writeVersionToXml(0);
- for (int userId : users) {
+ for (int userId : mProvider.mUsers) {
preparePoliciesFile(userId);
}
// Validate test set-up.
assertThat(isTagPresent(readPoliciesFileToStream(0), activePasswordTag)).isTrue();
- mUpgrader.upgradePolicy(users, 1);
+ mUpgrader.upgradePolicy(1);
assertThat(readVersionFromXml()).isGreaterThan(1);
- for (int user: users) {
+ for (int user: mProvider.mUsers) {
assertThat(isTagPresent(readPoliciesFileToStream(user), activePasswordTag)).isFalse();
}
}
@@ -163,21 +170,22 @@ public class PolicyVersionUpgraderTest {
@Test
public void testUpgrade1To2MarksDoForPermissionControl()
throws IOException, XmlPullParserException {
- int[] users = new int[] {0, 10};
+ final int ownerUser = 10;
+ mProvider.mUsers = new int[] {0, ownerUser};
writeVersionToXml(1);
- for (int userId : users) {
+ for (int userId : mProvider.mUsers) {
preparePoliciesFile(userId);
}
- mProvider.mDeviceOwnerUserId = 10;
+ mProvider.mDeviceOwnerUserId = ownerUser;
mProvider.mDeviceOwnerComponent = mFakeAdmin;
- mProvider.mUserToComponent.put(10, mFakeAdmin);
+ mProvider.mUserToComponent.put(ownerUser, mFakeAdmin);
- mUpgrader.upgradePolicy(users, 2);
+ mUpgrader.upgradePolicy(2);
assertThat(readVersionFromXml()).isEqualTo(2);
- assertThat(getBooleanValueTag(readPoliciesFileToStream(users[0]),
+ assertThat(getBooleanValueTag(readPoliciesFileToStream(mProvider.mUsers[0]),
PERMISSIONS_TAG)).isFalse();
- assertThat(getBooleanValueTag(readPoliciesFileToStream(users[1]),
+ assertThat(getBooleanValueTag(readPoliciesFileToStream(ownerUser),
PERMISSIONS_TAG)).isTrue();
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
index 137bd88b1489..375704ee31bf 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -16,183 +16,206 @@
package com.android.server.hdmi;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
import android.annotation.NonNull;
import android.content.Context;
-import android.util.Slog;
-
-import com.android.server.hdmi.cec.config.CecSettings;
-import com.android.server.hdmi.cec.config.XmlParser;
-
-import org.xmlpull.v1.XmlPullParserException;
+import android.content.ContextWrapper;
+import android.content.res.Resources;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-import javax.xml.datatype.DatatypeConfigurationException;
+import com.android.internal.R;
/**
- * Fake class which loads default system configuration with user-configurable
+ * Fake class which stubs default system configuration with user-configurable
* settings (useful for testing).
*/
final class FakeHdmiCecConfig extends HdmiCecConfig {
private static final String TAG = "FakeHdmiCecConfig";
- private static final String SYSTEM_CONFIG_XML =
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + " <setting name=\"power_state_change_on_active_source_lost\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"none\" />"
- + " <value string-value=\"standby_now\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"none\" />"
- + " </setting>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"hdmi_cec_version\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0x05\" />"
- + " <value int-value=\"0x06\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x05\" />"
- + " </setting>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"volume_control_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"tv_wake_on_one_touch_play\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"tv_send_standby_on_sleep\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_tv\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0x0\" />"
- + " <value int-value=\"0x2\" />"
- + " <value int-value=\"0x6\" />"
- + " <value int-value=\"0xA\" />"
- + " <value int-value=\"0xE\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x0\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_source_handles_root_menu\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_source_handles_setup_menu\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_source_handles_contents_menu\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_source_handles_top_menu\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_source_handles_media_context_sensitive_menu\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0\" />"
- + " </setting>"
- + "</cec-settings>";
+ public static Context buildContext(Context context) {
+ Context contextSpy = spy(new ContextWrapper(context));
+ doReturn(buildResources(context)).when(contextSpy).getResources();
+ return contextSpy;
+ }
- FakeHdmiCecConfig(@NonNull Context context) {
- super(context, new StorageAdapter(context), parseFromString(SYSTEM_CONFIG_XML), null);
+ private static Resources buildResources(Context context) {
+ Resources resources = spy(context.getResources());
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecEnabled_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecControlEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecControlEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecControlDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecControlDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecVersion_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecVersion14b_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecVersion14b_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecVersion20_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecVersion20_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSendStandbyOnSleep_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeTv_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeTv_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeBroadcast_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeBroadcast_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeNone_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeNone_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerStateChangeOnActiveSourceLost_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSystemAudioModeMuting_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSystemAudioModeMutingEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSystemAudioModeMutingEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSystemAudioModeMutingDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecSystemAudioModeMutingDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecVolumeControlMode_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecVolumeControlModeEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecVolumeControlModeEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecVolumeControlModeDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecVolumeControlModeDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvWakeOnOneTouchPlay_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvWakeOnOneTouchPlayEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvWakeOnOneTouchPlayEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvWakeOnOneTouchPlayDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecTvWakeOnOneTouchPlayDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvSendStandbyOnSleep_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvSendStandbyOnSleepEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvSendStandbyOnSleepEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecTvSendStandbyOnSleepDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTv_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvNone_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvNone_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvOne_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvOne_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvTwo_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvTwo_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvThree_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvThree_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvFour_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvFour_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceRootMenu_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceRootMenuHandled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceRootMenuHandled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceRootMenuNotHandled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceRootMenuNotHandled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceSetupMenu_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceSetupMenuHandled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceSetupMenuHandled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceSetupMenuNotHandled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceSetupMenuNotHandled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceContentsMenu_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceContentsMenuHandled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceContentsMenuHandled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceContentsMenuNotHandled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceContentsMenuNotHandled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceTopMenu_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceTopMenuHandled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceTopMenuHandled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceTopMenuNotHandled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceTopMenuNotHandled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default);
+
+ return resources;
}
- private static CecSettings parseFromString(@NonNull String configXml) {
- CecSettings config = null;
- try {
- config = XmlParser.read(
- new ByteArrayInputStream(configXml.getBytes()));
- } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
- Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e);
- }
- return config;
+ FakeHdmiCecConfig(@NonNull Context context) {
+ super(buildContext(context), new StorageAdapter(context));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index 798cf85957c0..c834510ba24c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -27,6 +28,7 @@ import static org.testng.Assert.assertThrows;
import android.annotation.NonNull;
import android.content.Context;
+import android.content.res.Resources;
import android.hardware.hdmi.HdmiControlManager;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
@@ -35,6 +37,8 @@ import android.provider.Settings.Global;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.internal.R;
+
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -61,265 +65,118 @@ public final class HdmiCecConfigTest {
@Mock private HdmiCecConfig.StorageAdapter mStorageAdapter;
@Mock private HdmiCecConfig.SettingChangeListener mSettingChangeListener;
+ private void setBooleanResource(int resId, boolean value) {
+ Resources resources = mContext.getResources();
+ doReturn(value).when(resources).getBoolean(resId);
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getTargetContext();
- }
-
- @Test
- public void getAllCecSettings_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThat(hdmiCecConfig.getAllSettings()).isEmpty();
- }
-
- @Test
- public void getAllCecSettings_Empty() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
- assertThat(hdmiCecConfig.getAllSettings()).isEmpty();
+ mContext = FakeHdmiCecConfig.buildContext(InstrumentationRegistry.getTargetContext());
}
@Test
public void getAllCecSettings_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getAllSettings())
.containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
- HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
- }
-
- @Test
- public void getUserCecSettings_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThat(hdmiCecConfig.getUserSettings()).isEmpty();
- }
-
- @Test
- public void getUserCecSettings_Empty() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
- assertThat(hdmiCecConfig.getUserSettings()).isEmpty();
- }
-
- @Test
- public void getUserCecSettings_OnlyMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+ HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+ HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ HdmiControlManager
+ .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU);
+ }
+
+ @Test
+ public void getUserCecSettings_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getUserSettings())
.containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
- HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+ HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+ HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ HdmiControlManager
+ .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU);
}
@Test
public void getUserCecSettings_WithOverride() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>",
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>");
+ setBooleanResource(R.bool.config_cecHdmiCecEnabled_userConfigurable, false);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getUserSettings())
- .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
- }
-
- @Test
- public void isStringValueType_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.isStringValueType("foo"));
+ .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+ HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+ HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ HdmiControlManager
+ .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU);
}
@Test
public void isStringValueType_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.isStringValueType("foo"));
}
@Test
public void isStringValueType_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertTrue(hdmiCecConfig.isStringValueType(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
}
@Test
- public void isIntValueType_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.isIntValueType("foo"));
- }
-
- @Test
public void isIntValueType_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.isIntValueType("foo"));
}
@Test
public void isIntValueType_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertTrue(hdmiCecConfig.isIntValueType(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
}
@Test
- public void getAllowedStringValues_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getAllowedStringValues("foo"));
- }
-
- @Test
public void getAllowedStringValues_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getAllowedStringValues("foo"));
}
@Test
public void getAllowedStringValues_InvalidValueType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getAllowedStringValues(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
@@ -327,21 +184,7 @@ public final class HdmiCecConfigTest {
@Test
public void getAllowedStringValues_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getAllowedStringValues(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
.containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV,
@@ -350,41 +193,25 @@ public final class HdmiCecConfigTest {
}
@Test
- public void getAllowedIntValues_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getAllowedIntValues("foo"));
+ public void getAllowedStringValues_WithOverride() {
+ setBooleanResource(R.bool.config_cecPowerControlModeNone_allowed, false);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
+ assertThat(hdmiCecConfig.getAllowedStringValues(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
+ .containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV,
+ HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
}
@Test
public void getAllowedIntValues_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getAllowedIntValues("foo"));
}
@Test
public void getAllowedIntValues_InvalidValueType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getAllowedIntValues(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
@@ -392,20 +219,7 @@ public final class HdmiCecConfigTest {
@Test
public void getAllowedIntValues_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getAllowedIntValues(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
.containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
@@ -413,62 +227,24 @@ public final class HdmiCecConfigTest {
}
@Test
- public void getAllowedIntValues_HexValues() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0x00\" />"
- + " <value int-value=\"0x01\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x01\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ public void getAllowedIntValues_WithOverride() {
+ setBooleanResource(R.bool.config_cecHdmiCecControlDisabled_allowed, false);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getAllowedIntValues(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
- .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
- HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
- }
-
- @Test
- public void getDefaultStringValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getDefaultStringValue("foo"));
+ .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
}
@Test
public void getDefaultStringValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getDefaultStringValue("foo"));
}
@Test
public void getDefaultStringValue_InvalidValueType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getDefaultStringValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
@@ -476,62 +252,46 @@ public final class HdmiCecConfigTest {
@Test
public void getDefaultStringValue_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getDefaultStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
.isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_TV);
}
@Test
- public void getDefaultIntValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getDefaultIntValue("foo"));
+ public void getDefaultStringValue_WithOverride() {
+ setBooleanResource(R.bool.config_cecPowerControlModeTv_default, false);
+ setBooleanResource(R.bool.config_cecPowerControlModeBroadcast_default, true);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
+ assertThat(hdmiCecConfig.getDefaultStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
+ .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
+ }
+
+ @Test
+ public void getDefaultStringValue_MultipleDefaults() {
+ setBooleanResource(R.bool.config_cecPowerControlModeBroadcast_default, true);
+ assertThrows(RuntimeException.class,
+ () -> new HdmiCecConfig(mContext, mStorageAdapter));
+ }
+
+ @Test
+ public void getDefaultStringValue_NoDefault() {
+ setBooleanResource(R.bool.config_cecPowerControlModeTv_default, false);
+ assertThrows(RuntimeException.class,
+ () -> new HdmiCecConfig(mContext, mStorageAdapter));
}
@Test
public void getDefaultIntValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getDefaultIntValue("foo"));
}
@Test
public void getDefaultIntValue_InvalidValueType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getDefaultIntValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
@@ -539,81 +299,32 @@ public final class HdmiCecConfigTest {
@Test
public void getDefaultIntValue_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getDefaultIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
.isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
}
@Test
- public void getDefaultIntValue_HexValue() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0x00\" />"
- + " <value int-value=\"0x01\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x01\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ public void getDefaultIntValue_WithOverride() {
+ setBooleanResource(R.bool.config_cecHdmiCecControlEnabled_default, false);
+ setBooleanResource(R.bool.config_cecHdmiCecControlDisabled_default, true);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getDefaultIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
- .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
- }
-
- @Test
- public void getStringValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getStringValue("foo"));
+ .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
}
@Test
public void getStringValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getStringValue("foo"));
}
@Test
public void getStringValue_InvalidType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getStringValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
@@ -625,21 +336,7 @@ public final class HdmiCecConfigTest {
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.POWER_CONTROL_MODE_TV))
.thenReturn(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
.isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
@@ -652,61 +349,22 @@ public final class HdmiCecConfigTest {
HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE))
.thenReturn(
HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"power_state_change_on_active_source_lost\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"none\" />"
- + " <value string-value=\"standby_now\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"none\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST))
.isEqualTo(HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
}
@Test
- public void getIntValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getIntValue("foo"));
- }
-
- @Test
public void getIntValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getIntValue("foo"));
}
@Test
public void getIntValue_InvalidType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getIntValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
@@ -718,45 +376,7 @@ public final class HdmiCecConfigTest {
Global.HDMI_CONTROL_ENABLED,
Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED)))
.thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
- assertThat(hdmiCecConfig.getIntValue(
- HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
- .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
- }
-
- @Test
- public void getIntValue_GlobalSetting_HexValue() {
- when(mStorageAdapter.retrieveGlobalSetting(
- Global.HDMI_CONTROL_ENABLED,
- Integer.toHexString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED)))
- .thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0x0\" />"
- + " <value int-value=\"0x1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
.isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
@@ -768,61 +388,23 @@ public final class HdmiCecConfigTest {
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED)))
.thenReturn(Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED));
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getIntValue(
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING))
.isEqualTo(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
}
@Test
- public void setStringValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setStringValue("foo", "bar"));
- }
-
- @Test
public void setStringValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setStringValue("foo", "bar"));
}
@Test
public void setStringValue_NotConfigurable() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ setBooleanResource(R.bool.config_cecSendStandbyOnSleep_userConfigurable, false);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
@@ -831,21 +413,7 @@ public final class HdmiCecConfigTest {
@Test
public void setStringValue_InvalidValue() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
@@ -854,21 +422,7 @@ public final class HdmiCecConfigTest {
@Test
public void setStringValue_GlobalSetting_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.setStringValue(HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
verify(mStorageAdapter).storeGlobalSetting(
@@ -878,20 +432,7 @@ public final class HdmiCecConfigTest {
@Test
public void setStringValue_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"power_state_change_on_active_source_lost\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"none\" />"
- + " <value string-value=\"standby_now\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"none\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
@@ -901,40 +442,16 @@ public final class HdmiCecConfigTest {
}
@Test
- public void setIntValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setIntValue("foo", 0));
- }
-
- @Test
public void setIntValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setIntValue("foo", 0));
}
@Test
public void setIntValue_NotConfigurable() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ setBooleanResource(R.bool.config_cecHdmiCecEnabled_userConfigurable, false);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
@@ -943,20 +460,7 @@ public final class HdmiCecConfigTest {
@Test
public void setIntValue_InvalidValue() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
@@ -965,43 +469,7 @@ public final class HdmiCecConfigTest {
@Test
public void setIntValue_GlobalSetting_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
- hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
- HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
- verify(mStorageAdapter).storeGlobalSetting(
- Global.HDMI_CONTROL_ENABLED,
- Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
- }
-
- @Test
- public void setIntValue_GlobalSetting_HexValue() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0x0\" />"
- + " <value int-value=\"0x1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
verify(mStorageAdapter).storeGlobalSetting(
@@ -1011,20 +479,7 @@ public final class HdmiCecConfigTest {
@Test
public void setIntValue_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.setIntValue(
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
@@ -1035,20 +490,7 @@ public final class HdmiCecConfigTest {
@Test
public void registerChangeListener_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.registerChangeListener(
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
mSettingChangeListener);
@@ -1061,20 +503,7 @@ public final class HdmiCecConfigTest {
@Test
public void removeChangeListener_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.registerChangeListener(
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
mSettingChangeListener);
@@ -1100,20 +529,7 @@ public final class HdmiCecConfigTest {
String originalValue = Global.getString(mContext.getContentResolver(),
Global.HDMI_CONTROL_ENABLED);
try {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.registerGlobalSettingsObserver(mTestLooper.getLooper());
HdmiCecConfig.SettingChangeListener latchUpdateListener =
new HdmiCecConfig.SettingChangeListener() {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index 907cf3eb1f70..c61635cbd4b6 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -136,7 +136,6 @@ public class OneTouchPlayActionTest {
mPhysicalAddress = 0x2000;
mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
mTestLooper.dispatchAll();
- mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
}
private OneTouchPlayAction createOneTouchPlayAction(HdmiCecLocalDevicePlayback device,
@@ -147,7 +146,47 @@ public class OneTouchPlayActionTest {
}
@Test
+ public void succeedWithUnknownTvDevice() {
+ HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
+ mHdmiControlService);
+ playbackDevice.init();
+ mLocalDevices.add(playbackDevice);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
+ TestActionTimer actionTimer = new TestActionTimer();
+ TestCallback callback = new TestCallback();
+ OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback,
+ false);
+ playbackDevice.addAndStartAction(action);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.mAddress, mPhysicalAddress);
+ HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
+ ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
+ .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
+ mNativeWrapper.clearResultMessages();
+ assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
+ HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
+ ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
+ action.processCommand(reportPowerStatusOn);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
+ assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+ }
+
+ @Test
public void succeedAfterGettingPowerStatusOn_Cec14b() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
@@ -187,6 +226,7 @@ public class OneTouchPlayActionTest {
@Test
public void succeedAfterGettingTransientPowerStatus_Cec14b() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
@@ -236,6 +276,7 @@ public class OneTouchPlayActionTest {
@Test
public void timeOut_Cec14b() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
@@ -276,6 +317,7 @@ public class OneTouchPlayActionTest {
@Test
public void succeedIfPowerStatusOn_Cec20() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
@@ -307,6 +349,7 @@ public class OneTouchPlayActionTest {
@Test
public void succeedIfPowerStatusUnknown_Cec20() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
@@ -348,6 +391,7 @@ public class OneTouchPlayActionTest {
@Test
public void succeedIfPowerStatusStandby_Cec20() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index d8e7582633de..c19f3489898d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -159,6 +159,11 @@ public class ActivityRecordTests extends WindowTestsBase {
setBooted(mAtm);
}
+ private TestStartingWindowOrganizer registerTestStartingWindowOrganizer() {
+ return new TestStartingWindowOrganizer(mAtm,
+ mSystemServicesTestRule.getPowerManagerWrapper());
+ }
+
@Test
public void testStackCleanupOnClearingTask() {
final ActivityRecord activity = createActivityWith2LevelTask();
@@ -2294,6 +2299,7 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testCreateRemoveStartingWindow() {
+ registerTestStartingWindowOrganizer();
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
@@ -2307,6 +2313,7 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testAddRemoveRace() {
+ registerTestStartingWindowOrganizer();
// There was once a race condition between adding and removing starting windows
final ActivityRecord appToken = new ActivityBuilder(mAtm).setCreateTask(true).build();
for (int i = 0; i < 1000; i++) {
@@ -2321,6 +2328,7 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testTransferStartingWindow() {
+ registerTestStartingWindowOrganizer();
final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity1.addStartingWindow(mPackageName,
@@ -2337,9 +2345,10 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testTransferStartingWindowWhileCreating() {
+ final TestStartingWindowOrganizer organizer = registerTestStartingWindowOrganizer();
final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
- ((TestWindowManagerPolicy) activity1.mWmService.mPolicy).setRunnableWhenAddingSplashScreen(
+ organizer.setRunnableWhenAddingSplashScreen(
() -> {
// Surprise, ...! Transfer window in the middle of the creation flow.
activity2.addStartingWindow(mPackageName,
@@ -2357,6 +2366,7 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testTransferStartingWindowCanAnimate() {
+ registerTestStartingWindowOrganizer();
final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity1.addStartingWindow(mPackageName,
@@ -2380,6 +2390,7 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testTransferStartingWindowFromFinishingActivity() {
+ registerTestStartingWindowOrganizer();
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
final Task task = activity.getTask();
activity.addStartingWindow(mPackageName, android.R.style.Theme, null /* compatInfo */,
@@ -2423,6 +2434,7 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testTransferStartingWindowSetFixedRotation() {
+ registerTestStartingWindowOrganizer();
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
final Task task = activity.getTask();
final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
@@ -2454,6 +2466,7 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testTryTransferStartingWindowFromHiddenAboveToken() {
+ registerTestStartingWindowOrganizer();
// Add two tasks on top of each other.
final ActivityRecord activityTop = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord activityBottom = new ActivityBuilder(mAtm).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 8703c3103607..7f9e7da99579 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -154,7 +154,7 @@ public class DragDropControllerTests extends WindowTestsBase {
mWindow = createDropTargetWindow("Drag test window", 0);
doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0);
when(mWm.mInputManager.transferTouchFocus(any(InputChannel.class),
- any(InputChannel.class))).thenReturn(true);
+ any(InputChannel.class), any(boolean.class))).thenReturn(true);
mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
}
@@ -370,7 +370,7 @@ public class DragDropControllerTests extends WindowTestsBase {
.build();
assertTrue(mWm.mInputManager.transferTouchFocus(new InputChannel(),
- new InputChannel()));
+ new InputChannel(), true /* isDragDrop */));
mToken = mTarget.performDrag(0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0, data);
assertNotNull(mToken);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index 75226b7e66f7..8bc4cedf6fce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -34,7 +34,6 @@ import static org.junit.Assert.assertTrue;
import android.platform.test.annotations.Presubmit;
import android.view.InputChannel;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -63,7 +62,8 @@ public class TaskPositioningControllerTests extends WindowTestsBase {
when(mWm.mInputManager.transferTouchFocus(
any(InputChannel.class),
- any(InputChannel.class))).thenReturn(true);
+ any(InputChannel.class),
+ any(boolean.class))).thenReturn(true);
mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
mWindow.getTask().setResizeMode(RESIZE_MODE_RESIZEABLE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 86d8eee878fd..7822a8514a13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -119,7 +119,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
mRunnableWhenAddingSplashScreen.run();
mRunnableWhenAddingSplashScreen = null;
}
- return () -> {
+ return (a) -> {
synchronized (wm.mGlobalLock) {
activity.removeChild(window);
activity.mStartingWindow = null;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 2c2c09a5750a..01c503e01326 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -547,7 +547,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
@Override
- public void removeStartingWindow(int taskId) { }
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) { }
@Override
public void copySplashScreenView(int taskId) { }
@@ -614,7 +615,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
@Override
- public void removeStartingWindow(int taskId) { }
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) { }
@Override
public void copySplashScreenView(int taskId) { }
@Override
@@ -688,7 +690,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
@Override
- public void removeStartingWindow(int taskId) { }
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) { }
@Override
public void copySplashScreenView(int taskId) { }
@Override
@@ -832,7 +835,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Override
public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { }
@Override
- public void removeStartingWindow(int taskId) { }
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) { }
@Override
public void copySplashScreenView(int taskId) { }
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 827ff6c18a68..4a7784cf1b36 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -50,6 +51,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
@@ -67,6 +69,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Bundle;
@@ -74,6 +77,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
+import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.IDisplayWindowInsetsController;
@@ -100,6 +104,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.util.HashMap;
/** Common base class for window manager unit test classes. */
class WindowTestsBase extends SystemServiceTestsBase {
@@ -1123,6 +1128,88 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
}
+ static class TestStartingWindowOrganizer extends ITaskOrganizer.Stub {
+ private final ActivityTaskManagerService mAtm;
+ private final WindowManagerService mWMService;
+ private final WindowState.PowerManagerWrapper mPowerManagerWrapper;
+
+ private Runnable mRunnableWhenAddingSplashScreen;
+ private final SparseArray<IBinder> mTaskAppMap = new SparseArray<>();
+ private final HashMap<IBinder, WindowState> mAppWindowMap = new HashMap<>();
+
+ TestStartingWindowOrganizer(ActivityTaskManagerService service,
+ WindowState.PowerManagerWrapper powerManagerWrapper) {
+ mAtm = service;
+ mWMService = mAtm.mWindowManager;
+ mPowerManagerWrapper = powerManagerWrapper;
+ if (DEBUG_ENABLE_SHELL_DRAWER) {
+ mAtm.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer(Runnable::run);
+ mAtm.mTaskOrganizerController.registerTaskOrganizer(this);
+ }
+ }
+
+ void setRunnableWhenAddingSplashScreen(Runnable r) {
+ if (DEBUG_ENABLE_SHELL_DRAWER) {
+ mRunnableWhenAddingSplashScreen = r;
+ } else {
+ ((TestWindowManagerPolicy) mWMService.mPolicy).setRunnableWhenAddingSplashScreen(r);
+ }
+ }
+
+ @Override
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
+ synchronized (mWMService.mGlobalLock) {
+ final ActivityRecord activity = mWMService.mRoot.getActivityRecord(
+ appToken);
+ IWindow iWindow = mock(IWindow.class);
+ doReturn(mock(IBinder.class)).when(iWindow).asBinder();
+ final WindowState window = WindowTestsBase.createWindow(null,
+ TYPE_APPLICATION_STARTING, activity,
+ "Starting window", 0 /* ownerId */, 0 /* userId*/,
+ false /* internalWindows */, mWMService, mock(Session.class),
+ iWindow,
+ mPowerManagerWrapper);
+ activity.mStartingWindow = window;
+ mAppWindowMap.put(appToken, window);
+ mTaskAppMap.put(info.taskInfo.taskId, appToken);
+ }
+ if (mRunnableWhenAddingSplashScreen != null) {
+ mRunnableWhenAddingSplashScreen.run();
+ mRunnableWhenAddingSplashScreen = null;
+ }
+ }
+ @Override
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
+ synchronized (mWMService.mGlobalLock) {
+ final IBinder appToken = mTaskAppMap.get(taskId);
+ if (appToken != null) {
+ mTaskAppMap.remove(taskId);
+ final ActivityRecord activity = mWMService.mRoot.getActivityRecord(
+ appToken);
+ WindowState win = mAppWindowMap.remove(appToken);
+ activity.removeChild(win);
+ activity.mStartingWindow = null;
+ }
+ }
+ }
+ @Override
+ public void copySplashScreenView(int taskId) {
+ }
+ @Override
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
+ }
+ @Override
+ public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
+ }
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+ }
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ }
+ }
+
static class TestSplitOrganizer extends ITaskOrganizer.Stub {
final ActivityTaskManagerService mService;
Task mPrimary;
@@ -1161,7 +1248,8 @@ class WindowTestsBase extends SystemServiceTestsBase {
public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
}
@Override
- public void removeStartingWindow(int taskId) {
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
}
@Override
public void copySplashScreenView(int taskId) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 705e93f8883c..1a71f808daa7 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -27,6 +27,7 @@ import android.annotation.SystemService;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
+import android.net.ipsec.ike.SaProposal;
import android.os.Build;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -4170,9 +4171,11 @@ public class CarrierConfigManager {
KEY_PREFIX + "child_sa_rekey_soft_timer_sec_int";
/**
- * Supported DH groups for IKE negotiation. Possible values are {@link #DH_GROUP_NONE},
- * {@link #DH_GROUP_1024_BIT_MODP}, {@link #DH_GROUP_1536_BIT_MODP}, {@link
- * #DH_GROUP_2048_BIT_MODP}
+ * Supported DH groups for IKE negotiation. Possible values are:
+ * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_NONE},
+ * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_1024_BIT_MODP},
+ * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_1536_BIT_MODP},
+ * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_2048_BIT_MODP}
*/
public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY =
KEY_PREFIX + "diffie_hellman_groups_int_array";
@@ -4208,23 +4211,29 @@ public class CarrierConfigManager {
/**
* List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of child
- * session. Possible values are {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, {@link
- * #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ * session. Possible values are:
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
*/
public static final String KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
KEY_PREFIX + "child_session_aes_cbc_key_size_int_array";
/**
* List of supported key sizes for AES Counter (CTR) encryption mode of child session.
- * Possible values are {@link #KEY_LEN_UNUSED},
- * {@link #KEY_LEN_AES_128}, {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ * Possible values are:
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
*/
public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY =
KEY_PREFIX + "child_session_aes_ctr_key_size_int_array";
/**
* List of supported encryption algorithms for child session. Possible values are
- * {@link #ENCRYPTION_ALGORITHM_AES_CBC}
+ * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CBC}
*/
public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY =
KEY_PREFIX + "supported_child_session_encryption_algorithms_int_array";
@@ -4245,8 +4254,11 @@ public class CarrierConfigManager {
/**
* List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of IKE
- * session. Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, {@link
- * #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ * session. Possible values:
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
*/
public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
KEY_PREFIX + "ike_session_encryption_aes_cbc_key_size_int_array";
@@ -4254,24 +4266,31 @@ public class CarrierConfigManager {
/**
* List of supported key sizes for AES Counter (CTR) encryption mode of IKE session.
- * Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
- * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ * Possible values -
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
*/
public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY =
KEY_PREFIX + "ike_session_encryption_aes_ctr_key_size_int_array";
/**
* List of supported encryption algorithms for IKE session. Possible values are
- * {@link #ENCRYPTION_ALGORITHM_AES_CBC}, {@link #ENCRYPTION_ALGORITHM_AES_CTR}
+ * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CBC},
+ * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CTR}
*/
public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY =
KEY_PREFIX + "supported_ike_session_encryption_algorithms_int_array";
/**
- * List of supported integrity algorithms for IKE session Possible values are {@link
- * #INTEGRITY_ALGORITHM_NONE}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA1_96}, {@link
- * #INTEGRITY_ALGORITHM_AES_XCBC_96}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_256_128}, {@link
- * #INTEGRITY_ALGORITHM_HMAC_SHA2_384_192}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_512_256}
+ * List of supported integrity algorithms for IKE session. Possible values are
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_NONE},
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA1_96},
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_AES_XCBC_96},
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_256_128},
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_384_192},
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_512_256}
*/
public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY =
KEY_PREFIX + "supported_integrity_algorithms_int_array";
@@ -4291,9 +4310,11 @@ public class CarrierConfigManager {
/**
* List of supported pseudo random function algorithms for IKE session. Possible values are
- * {@link #PSEUDORANDOM_FUNCTION_HMAC_SHA1}, {@link #PSEUDORANDOM_FUNCTION_AES128_XCBC},
- * {@link #PSEUDORANDOM_FUNCTION_SHA2_256}, {@link #PSEUDORANDOM_FUNCTION_SHA2_384},
- * {@link #PSEUDORANDOM_FUNCTION_SHA2_512}
+ * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_HMAC_SHA1},
+ * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_AES128_XCBC},
+ * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_256},
+ * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_384},
+ * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_512}
*/
public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY =
KEY_PREFIX + "supported_prf_algorithms_int_array";
@@ -4366,182 +4387,6 @@ public class CarrierConfigManager {
public static final int EPDG_ADDRESS_CELLULAR_LOC = 3;
/** @hide */
- @IntDef({KEY_LEN_UNUSED, KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256})
- public @interface EncrpytionKeyLengthType {}
-
- public static final int KEY_LEN_UNUSED = 0;
- /** AES Encryption/Ciphering Algorithm key length 128 bits. */
- public static final int KEY_LEN_AES_128 = 128;
- /** AES Encryption/Ciphering Algorithm key length 192 bits. */
- public static final int KEY_LEN_AES_192 = 192;
- /** AES Encryption/Ciphering Algorithm key length 256 bits. */
- public static final int KEY_LEN_AES_256 = 256;
-
- /** @hide */
- @IntDef({
- DH_GROUP_NONE,
- DH_GROUP_1024_BIT_MODP,
- DH_GROUP_1536_BIT_MODP,
- DH_GROUP_2048_BIT_MODP,
- DH_GROUP_3072_BIT_MODP,
- DH_GROUP_4096_BIT_MODP
- })
- public @interface DhGroup {}
-
- /** None Diffie-Hellman Group. */
- public static final int DH_GROUP_NONE = 0;
- /**
- * 1024-bit MODP Diffie-Hellman Group.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int DH_GROUP_1024_BIT_MODP = 2;
- /**
- * 1536-bit MODP Diffie-Hellman Group.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int DH_GROUP_1536_BIT_MODP = 5;
- /**
- * 2048-bit MODP Diffie-Hellman Group.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int DH_GROUP_2048_BIT_MODP = 14;
- /**
- * 3072-bit MODP Diffie-Hellman Group.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int DH_GROUP_3072_BIT_MODP = 15;
- /**
- * 4096-bit MODP Diffie-Hellman Group.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int DH_GROUP_4096_BIT_MODP = 16;
-
- /** @hide */
- @IntDef({ENCRYPTION_ALGORITHM_AES_CBC, ENCRYPTION_ALGORITHM_AES_CTR})
- public @interface EncryptionAlgorithm {}
-
- /**
- * AES-CBC Encryption/Ciphering Algorithm.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12;
-
- /**
- * AES-CTR Encryption/Ciphering Algorithm.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int ENCRYPTION_ALGORITHM_AES_CTR = 13;
-
- /** @hide */
- @IntDef({
- INTEGRITY_ALGORITHM_NONE,
- INTEGRITY_ALGORITHM_HMAC_SHA1_96,
- INTEGRITY_ALGORITHM_AES_XCBC_96,
- INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
- INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
- INTEGRITY_ALGORITHM_HMAC_SHA2_512_256
- })
- public @interface IntegrityAlgorithm {}
-
- /** None Authentication/Integrity Algorithm. */
- public static final int INTEGRITY_ALGORITHM_NONE = 0;
- /**
- * HMAC-SHA1 Authentication/Integrity Algorithm.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2;
- /**
- * AES-XCBC-96 Authentication/Integrity Algorithm.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5;
- /**
- * HMAC-SHA256 Authentication/Integrity Algorithm with 128-bit truncation.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12;
- /**
- * HMAC-SHA384 Authentication/Integrity Algorithm with 192-bit truncation.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13;
- /**
- * HMAC-SHA512 Authentication/Integrity Algorithm with 256-bit truncation.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14;
-
- /** @hide */
- @IntDef({
- PSEUDORANDOM_FUNCTION_HMAC_SHA1,
- PSEUDORANDOM_FUNCTION_AES128_XCBC,
- PSEUDORANDOM_FUNCTION_SHA2_256,
- PSEUDORANDOM_FUNCTION_SHA2_384,
- PSEUDORANDOM_FUNCTION_SHA2_512
- })
- public @interface PseudorandomFunction {}
-
- /**
- * HMAC-SHA1 Pseudorandom Function.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2;
- /**
- * AES128-XCBC Pseudorandom Function.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4;
- /**
- * HMAC-SHA2-256 Pseudorandom Function.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int PSEUDORANDOM_FUNCTION_SHA2_256 = 5;
- /**
- * HMAC-SHA2-384 Pseudorandom Function.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int PSEUDORANDOM_FUNCTION_SHA2_384 = 6;
- /**
- * HMAC-SHA2-384 Pseudorandom Function.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int PSEUDORANDOM_FUNCTION_SHA2_512 = 7;
-
- /** @hide */
@IntDef({ID_TYPE_FQDN, ID_TYPE_RFC822_ADDR, ID_TYPE_KEY_ID})
public @interface IkeIdType {}
@@ -4582,31 +4427,33 @@ public class CarrierConfigManager {
defaults.putIntArray(
KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY,
new int[] {
- DH_GROUP_1024_BIT_MODP, DH_GROUP_1536_BIT_MODP, DH_GROUP_2048_BIT_MODP
+ SaProposal.DH_GROUP_1024_BIT_MODP,
+ SaProposal.DH_GROUP_1536_BIT_MODP,
+ SaProposal.DH_GROUP_2048_BIT_MODP
});
defaults.putIntArray(
KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
- new int[] {ENCRYPTION_ALGORITHM_AES_CBC});
+ new int[] {SaProposal.ENCRYPTION_ALGORITHM_AES_CBC});
defaults.putIntArray(
KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
- new int[] {ENCRYPTION_ALGORITHM_AES_CBC});
+ new int[] {SaProposal.ENCRYPTION_ALGORITHM_AES_CBC});
defaults.putIntArray(
KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY,
new int[] {
- INTEGRITY_ALGORITHM_AES_XCBC_96,
- INTEGRITY_ALGORITHM_HMAC_SHA1_96,
- INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
- INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
- INTEGRITY_ALGORITHM_HMAC_SHA2_512_256,
+ SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96,
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96,
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256,
});
defaults.putIntArray(
KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY,
new int[] {
- PSEUDORANDOM_FUNCTION_HMAC_SHA1,
- PSEUDORANDOM_FUNCTION_AES128_XCBC,
- PSEUDORANDOM_FUNCTION_SHA2_256,
- PSEUDORANDOM_FUNCTION_SHA2_384,
- PSEUDORANDOM_FUNCTION_SHA2_512
+ SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1,
+ SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC,
+ SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256,
+ SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384,
+ SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512
});
defaults.putInt(KEY_EPDG_AUTHENTICATION_METHOD_INT, AUTHENTICATION_METHOD_EAP_ONLY);
@@ -4616,16 +4463,28 @@ public class CarrierConfigManager {
defaults.putInt(KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT, 20);
defaults.putIntArray(
KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
- new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+ new int[] {
+ SaProposal.KEY_LEN_AES_128,
+ SaProposal.KEY_LEN_AES_192,
+ SaProposal.KEY_LEN_AES_256});
defaults.putIntArray(
KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
- new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+ new int[] {
+ SaProposal.KEY_LEN_AES_128,
+ SaProposal.KEY_LEN_AES_192,
+ SaProposal.KEY_LEN_AES_256});
defaults.putIntArray(
KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY,
- new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+ new int[] {
+ SaProposal.KEY_LEN_AES_128,
+ SaProposal.KEY_LEN_AES_192,
+ SaProposal.KEY_LEN_AES_256});
defaults.putIntArray(
KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY,
- new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+ new int[] {
+ SaProposal.KEY_LEN_AES_128,
+ SaProposal.KEY_LEN_AES_192,
+ SaProposal.KEY_LEN_AES_256});
defaults.putIntArray(
KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
new int[] {EPDG_ADDRESS_PLMN, EPDG_ADDRESS_STATIC});
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index b2719fbcac82..896ec9ae922c 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -11,6 +11,8 @@
<option name="force-skip-system-props" value="true" />
<!-- set WM tracing verbose level to all -->
<option name="run-command" value="cmd window tracing level all" />
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame" />
<!-- restart launcher to activate TAPL -->
<option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
</target_preparer>
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
index d6846faa5c00..e121b68ca8fa 100644
--- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -94,17 +94,16 @@ public class PlatformCompatChangeRule extends CoreCompatChangeRule {
if (platformCompat == null) {
throw new IllegalStateException("Could not get IPlatformCompat service!");
}
- uiAutomation.adoptShellPermissionIdentity(
- Manifest.permission.LOG_COMPAT_CHANGE,
- Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ adoptShellPermissions(uiAutomation);
Compatibility.setOverrides(mConfig);
try {
platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
packageName);
try {
+ uiAutomation.dropShellPermissionIdentity();
mTestStatement.evaluate();
} finally {
+ adoptShellPermissions(uiAutomation);
platformCompat.clearOverridesForTest(packageName);
}
} catch (RemoteException e) {
@@ -114,5 +113,12 @@ public class PlatformCompatChangeRule extends CoreCompatChangeRule {
Compatibility.clearOverrides();
}
}
+
+ private static void adoptShellPermissions(UiAutomation uiAutomation) {
+ uiAutomation.adoptShellPermissionIdentity(
+ Manifest.permission.LOG_COMPAT_CHANGE,
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ }
}
}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index e84b992a1379..0dfec7592274 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -28,6 +28,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
@@ -44,6 +45,10 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
import static android.os.Process.INVALID_UID;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
+import static com.android.testutils.MiscAsserts.assertEmpty;
+import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
@@ -67,7 +72,6 @@ import android.util.ArraySet;
import androidx.test.runner.AndroidJUnit4;
-import com.android.modules.utils.build.SdkLevel;
import com.android.testutils.CompatUtil;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -85,6 +89,9 @@ import java.util.Set;
public class NetworkCapabilitiesTest {
private static final String TEST_SSID = "TEST_SSID";
private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
+ private static final int TEST_SUBID1 = 1;
+ private static final int TEST_SUBID2 = 2;
+ private static final int TEST_SUBID3 = 3;
@Rule
public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
@@ -92,14 +99,6 @@ public class NetworkCapabilitiesTest {
private DiscoverySession mDiscoverySession = Mockito.mock(DiscoverySession.class);
private PeerHandle mPeerHandle = Mockito.mock(PeerHandle.class);
- private boolean isAtLeastR() {
- return SdkLevel.isAtLeastR();
- }
-
- private boolean isAtLeastS() {
- return SdkLevel.isAtLeastS();
- }
-
@Test
public void testMaybeMarkCapabilitiesRestricted() {
// verify EIMS is restricted
@@ -305,7 +304,9 @@ public class NetworkCapabilitiesTest {
.setUids(uids)
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
- if (isAtLeastR()) {
+ if (isAtLeastS()) {
+ netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+ } else if (isAtLeastR()) {
netCap.setOwnerUid(123);
netCap.setAdministratorUids(new int[] {5, 11});
}
@@ -380,7 +381,7 @@ public class NetworkCapabilitiesTest {
private void testParcelSane(NetworkCapabilities cap) {
if (isAtLeastS()) {
- assertParcelSane(cap, 16);
+ assertParcelSane(cap, 17);
} else if (isAtLeastR()) {
assertParcelSane(cap, 15);
} else {
@@ -614,6 +615,20 @@ public class NetworkCapabilitiesTest {
assertFalse(nc2.appliesToUid(12));
assertTrue(nc1.appliesToUid(22));
assertTrue(nc2.appliesToUid(22));
+
+ // Verify the subscription id list can be combined only when they are equal.
+ if (isAtLeastS()) {
+ nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+ nc2.setSubIds(Set.of(TEST_SUBID2));
+ assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
+
+ nc2.setSubIds(Set.of());
+ assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
+
+ nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1));
+ nc2.combineCapabilities(nc1);
+ assertEquals(Set.of(TEST_SUBID2, TEST_SUBID1), nc2.getSubIds());
+ }
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
@@ -762,6 +777,24 @@ public class NetworkCapabilitiesTest {
nc1.setUids(uidRange(10, 13));
nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
assertEquals(nc1, nc2);
+
+ if (isAtLeastS()) {
+ assertThrows(NullPointerException.class, () -> nc1.setSubIds(null));
+ nc1.setSubIds(Set.of());
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+
+ nc1.setSubIds(Set.of(TEST_SUBID1));
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+
+ nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1));
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+
+ nc2.setSubIds(Set.of(TEST_SUBID3, TEST_SUBID2));
+ assertNotEquals(nc1, nc2);
+ }
}
@Test
@@ -842,6 +875,50 @@ public class NetworkCapabilitiesTest {
} catch (NullPointerException expected) { }
}
+ private static NetworkCapabilities capsWithSubIds(Integer ... subIds) {
+ // Since the NetworkRequest would put NOT_VCN_MANAGED capabilities in general, for
+ // every NetworkCapabilities that simulates networks needs to add it too in order to
+ // satisfy these requests.
+ final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .setSubIds(new ArraySet<>(subIds)).build();
+ assertEquals(new ArraySet<>(subIds), nc.getSubIds());
+ return nc;
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testSubIds() throws Exception {
+ final NetworkCapabilities ncWithoutId = capsWithSubIds();
+ final NetworkCapabilities ncWithId = capsWithSubIds(TEST_SUBID1);
+ final NetworkCapabilities ncWithOtherIds = capsWithSubIds(TEST_SUBID1, TEST_SUBID3);
+ final NetworkCapabilities ncWithoutRequestedIds = capsWithSubIds(TEST_SUBID3);
+
+ final NetworkRequest requestWithoutId = new NetworkRequest.Builder().build();
+ assertEmpty(requestWithoutId.networkCapabilities.getSubIds());
+ final NetworkRequest requestWithIds = new NetworkRequest.Builder()
+ .setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)).build();
+ assertEquals(Set.of(TEST_SUBID1, TEST_SUBID2),
+ requestWithIds.networkCapabilities.getSubIds());
+
+ assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutId));
+ assertTrue(requestWithIds.canBeSatisfiedBy(ncWithOtherIds));
+ assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutRequestedIds));
+ assertTrue(requestWithIds.canBeSatisfiedBy(ncWithId));
+ assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithoutId));
+ assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithId));
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testEqualsSubIds() throws Exception {
+ assertEquals(capsWithSubIds(), capsWithSubIds());
+ assertNotEquals(capsWithSubIds(), capsWithSubIds(TEST_SUBID1));
+ assertEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID1));
+ assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2));
+ assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2, TEST_SUBID1));
+ assertEquals(capsWithSubIds(TEST_SUBID1, TEST_SUBID2),
+ capsWithSubIds(TEST_SUBID2, TEST_SUBID1));
+ }
+
@Test
public void testLinkBandwidthKbps() {
final NetworkCapabilities nc = new NetworkCapabilities();
@@ -1022,5 +1099,11 @@ public class NetworkCapabilitiesTest {
fail("Should not set null into NetworkCapabilities.Builder");
} catch (NullPointerException expected) { }
assertEquals(nc, new NetworkCapabilities.Builder(nc).build());
+
+ if (isAtLeastS()) {
+ final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
+ .setSubIds(Set.of(TEST_SUBID1)).build();
+ assertEquals(Set.of(TEST_SUBID1), nc2.getSubIds());
+ }
}
}
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 098b029b75e6..6fc605e269fe 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -220,7 +220,7 @@ public class ConnectivityManagerTest {
// register callback
when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- any(), nullable(String.class))).thenReturn(request);
+ anyInt(), any(), nullable(String.class))).thenReturn(request);
manager.requestNetwork(request, callback, handler);
// callback triggers
@@ -248,7 +248,7 @@ public class ConnectivityManagerTest {
// register callback
when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- any(), nullable(String.class))).thenReturn(req1);
+ anyInt(), any(), nullable(String.class))).thenReturn(req1);
manager.requestNetwork(req1, callback, handler);
// callback triggers
@@ -266,7 +266,7 @@ public class ConnectivityManagerTest {
// callback can be registered again
when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- any(), nullable(String.class))).thenReturn(req2);
+ anyInt(), any(), nullable(String.class))).thenReturn(req2);
manager.requestNetwork(req2, callback, handler);
// callback triggers
@@ -289,8 +289,8 @@ public class ConnectivityManagerTest {
info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
when(mCtx.getApplicationInfo()).thenReturn(info);
- when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), any(),
- nullable(String.class))).thenReturn(request);
+ when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(),
+ any(), nullable(String.class))).thenReturn(request);
Handler handler = new Handler(Looper.getMainLooper());
manager.requestNetwork(request, callback, handler);
@@ -358,34 +358,34 @@ public class ConnectivityManagerTest {
manager.requestNetwork(request, callback);
verify(mService).requestNetwork(eq(request.networkCapabilities),
- eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
// Verify that register network callback does not calls requestNetwork at all.
manager.registerNetworkCallback(request, callback);
- verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(),
+ verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(),
anyInt(), any(), any());
- verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(),
+ verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.registerDefaultNetworkCallback(callback);
verify(mService).requestNetwork(eq(null),
- eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
manager.requestBackgroundNetwork(request, handler, callback);
verify(mService).requestNetwork(eq(request.networkCapabilities),
- eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.registerSystemDefaultNetworkCallback(callback, handler);
verify(mService).requestNetwork(eq(null),
- eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 9db5854c6525..fadd1eac14ef 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1450,6 +1450,8 @@ public class ConnectivityServiceTest {
applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
.thenReturn(applicationInfo);
+ when(mPackageManager.getTargetSdkVersion(anyString()))
+ .thenReturn(applicationInfo.targetSdkVersion);
when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
@@ -3756,8 +3758,8 @@ public class ConnectivityServiceTest {
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(),
- null, 0, null, ConnectivityManager.TYPE_WIFI, mContext.getPackageName(),
- getAttributionTag());
+ null, 0, null, ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
+ mContext.getPackageName(), getAttributionTag());
});
class NonParcelableSpecifier extends NetworkSpecifier {
@@ -8763,6 +8765,7 @@ public class ConnectivityServiceTest {
applicationInfo.targetSdkVersion = targetSdk;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
.thenReturn(applicationInfo);
+ when(mPackageManager.getTargetSdkVersion(any())).thenReturn(targetSdk);
when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
@@ -8777,102 +8780,183 @@ public class ConnectivityServiceTest {
}
}
- private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
+ private int getOwnerUidNetCapsPermission(int ownerUid, int callerUid,
+ boolean includeLocationSensitiveInfo) {
final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, callerUid, mContext.getPackageName(), getAttributionTag()).getOwnerUid();
+ netCap, includeLocationSensitiveInfo, callerUid,
+ mContext.getPackageName(), getAttributionTag())
+ .getOwnerUid();
}
- private void verifyWifiInfoCopyNetCapsForCallerPermission(
- int callerUid, boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
+ private void verifyWifiInfoCopyNetCapsPermission(
+ int callerUid, boolean includeLocationSensitiveInfo,
+ boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
final WifiInfo wifiInfo = mock(WifiInfo.class);
when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true);
final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, callerUid, mContext.getPackageName(), getAttributionTag());
+ netCap, includeLocationSensitiveInfo, callerUid,
+ mContext.getPackageName(), getAttributionTag());
verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
}
+ private void verifyOwnerUidAndWifiInfoNetCapsPermission(
+ boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag,
+ boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag,
+ boolean shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag,
+ boolean shouldInclLocationSensitiveWifiInfoWithIncludeFlag) {
+ final int myUid = Process.myUid();
+
+ final int expectedOwnerUidWithoutIncludeFlag =
+ shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag
+ ? Process.myUid() : INVALID_UID;
+ assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission(
+ myUid, myUid, false /* includeLocationSensitiveInfo */));
+
+ final int expectedOwnerUidWithIncludeFlag =
+ shouldInclLocationSensitiveOwnerUidWithIncludeFlag ? myUid : INVALID_UID;
+ assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission(
+ myUid, myUid, true /* includeLocationSensitiveInfo */));
+
+ verifyWifiInfoCopyNetCapsPermission(myUid,
+ false, /* includeLocationSensitiveInfo */
+ shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag);
+
+ verifyWifiInfoCopyNetCapsPermission(myUid,
+ true, /* includeLocationSensitiveInfo */
+ shouldInclLocationSensitiveWifiInfoWithIncludeFlag);
+
+ }
+
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithFineLocationAfterQ()
+ public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQ()
throws Exception {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- final int myUid = Process.myUid();
- assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ // Ensure that we include owner uid even if the request asks to remove it since the
+ // app has necessary permissions and targetSdk < S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
+ }
+
+ @Test
+ public void testCreateWithLocationInfoSanitizedWithFineLocationPreSWithAndWithoutCallbackFlag()
+ throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ // Ensure that we include owner uid even if the request asks to remove it since the
+ // app has necessary permissions and targetSdk < S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationPreQ()
+ public void
+ testCreateWithLocationInfoSanitizedWithFineLocationAfterSWithAndWithoutCallbackFlag()
+ throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ // Ensure that we owner UID if the request asks us to remove it even if the app
+ // has necessary permissions since targetSdk >= S.
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
+ }
+
+ @Test
+ public void testCreateWithLocationInfoSanitizedWithCoarseLocationPreQ()
throws Exception {
setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
- final int myUid = Process.myUid();
- assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ // Ensure that we owner UID if the request asks us to remove it even if the app
+ // has necessary permissions since targetSdk >= S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedLocationOff() throws Exception {
+ public void testCreateWithLocationInfoSanitizedLocationOff() throws Exception {
// Test that even with fine location permission, and UIDs matching, the UID is sanitized.
setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWrongUid() throws Exception {
+ public void testCreateWithLocationInfoSanitizedWrongUid() throws Exception {
// Test that even with fine location permission, not being the owner leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ assertEquals(Process.INVALID_UID,
+ getOwnerUidNetCapsPermission(myUid + 1, myUid,
+ true /* includeLocationSensitiveInfo */));
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationAfterQ()
+ public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterQ()
throws Exception {
// Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
- // Test that without the location permission, the owner field is sanitized.
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithoutLocationPermission()
+ public void testCreateWithLocationInfoSanitizedWithoutLocationPermission()
throws Exception {
+ // Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
- // Test that without the location permission, the owner field is sanitized.
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
}
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -9463,8 +9547,8 @@ public class ConnectivityServiceTest {
assertThrows("Expect throws for invalid request type " + reqTypeInt,
IllegalArgumentException.class,
() -> mService.requestNetwork(nc, reqTypeInt, null, 0, null,
- ConnectivityManager.TYPE_NONE, mContext.getPackageName(),
- getAttributionTag())
+ ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
+ mContext.getPackageName(), getAttributionTag())
);
}
}
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index f97eabf6366d..6232423b4f9e 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.IpSecAlgorithm;
import android.net.IpSecConfig;
@@ -47,6 +48,7 @@ import android.os.Process;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
+import android.util.Range;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -647,9 +649,9 @@ public class IpSecServiceTest {
@Test
public void testReserveNetId() {
- int start = mIpSecService.TUN_INTF_NETID_START;
- for (int i = 0; i < mIpSecService.TUN_INTF_NETID_RANGE; i++) {
- assertEquals(start + i, mIpSecService.reserveNetId());
+ final Range<Integer> netIdRange = ConnectivityManager.getIpSecNetIdRange();
+ for (int netId = netIdRange.getLower(); netId <= netIdRange.getUpper(); netId++) {
+ assertEquals(netId, mIpSecService.reserveNetId());
}
// Check that resource exhaustion triggers an exception
@@ -661,7 +663,7 @@ public class IpSecServiceTest {
// Now release one and try again
int releasedNetId =
- mIpSecService.TUN_INTF_NETID_START + mIpSecService.TUN_INTF_NETID_RANGE / 2;
+ netIdRange.getLower() + (netIdRange.getUpper() - netIdRange.getLower()) / 2;
mIpSecService.releaseNetId(releasedNetId);
assertEquals(releasedNetId, mIpSecService.reserveNetId());
}
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index e4e24b464838..fec5ef39374a 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -48,18 +48,22 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.net.INetd;
import android.net.UidRange;
+import android.net.Uri;
import android.os.Build;
import android.os.SystemConfigManager;
import android.os.UserHandle;
@@ -70,12 +74,11 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.server.LocalServices;
-import com.android.server.pm.PackageList;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
@@ -112,7 +115,6 @@ public class PermissionMonitorTest {
@Mock private Context mContext;
@Mock private PackageManager mPackageManager;
@Mock private INetd mNetdService;
- @Mock private PackageManagerInternal mMockPmi;
@Mock private UserManager mUserManager;
@Mock private PermissionMonitor.Dependencies mDeps;
@Mock private SystemConfigManager mSystemConfigManager;
@@ -131,16 +133,14 @@ public class PermissionMonitorTest {
when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
.thenReturn(mSystemConfigManager);
when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
+ final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
+ doReturn(UserHandle.ALL).when(asUserCtx).getUser();
+ when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
- LocalServices.removeServiceForTest(PackageManagerInternal.class);
- LocalServices.addService(PackageManagerInternal.class, mMockPmi);
- when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList<String>(),
- /* observer */ null));
when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
mPermissionMonitor.startMonitoring();
- verify(mMockPmi).getPackageList(mPermissionMonitor);
}
private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
@@ -770,4 +770,32 @@ public class PermissionMonitorTest {
INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
new int[]{ MOCK_UID2 });
}
+
+ @Test
+ public void testIntentReceiver() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext, times(1)).registerReceiver(receiverCaptor.capture(), any(), any(), any());
+ final BroadcastReceiver receiver = receiverCaptor.getValue();
+
+ // Verify receiving PACKAGE_ADDED intent.
+ final Intent addedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED,
+ Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
+ addedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
+ setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1,
+ new String[] { INTERNET, UPDATE_DEVICE_STATS });
+ receiver.onReceive(mContext, addedIntent);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[] { MOCK_UID1 });
+
+ // Verify receiving PACKAGE_REMOVED intent.
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(null);
+ final Intent removedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
+ Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
+ removedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
+ receiver.onReceive(mContext, removedIntent);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[] { MOCK_UID1 });
+ }
+
}