Merge changes Ie8f4efaa,Ic1af43cf into main
* changes:
set aconfig_declarations containers to system
set aconfig_declarations containers to system
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 42e82f6..ea6f45e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10284,6 +10284,16 @@
* get the list of app restrictions set by each admin via
* {@link android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin}.
*
+ * <p>Starting from Android Version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM},
+ * the device policy management role holder can also set app restrictions on any applications
+ * in the calling user, as well as the parent user of an organization-owned managed profile via
+ * the {@link DevicePolicyManager} instance returned by
+ * {@link #getParentProfileInstance(ComponentName)}. App restrictions set by the device policy
+ * management role holder are not returned by
+ * {@link UserManager#getApplicationRestrictions(String)}. The target application should use
+ * {@link android.content.RestrictionsManager#getApplicationRestrictionsPerAdmin} to retrieve
+ * them, alongside any app restrictions the profile or device owner might have set.
+ *
* <p>NOTE: The method performs disk I/O and shouldn't be called on the main thread
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
@@ -10299,11 +10309,14 @@
@WorkerThread
public void setApplicationRestrictions(@Nullable ComponentName admin, String packageName,
Bundle settings) {
- throwIfParentInstance("setApplicationRestrictions");
+ if (!Flags.dmrhCanSetAppRestriction()) {
+ throwIfParentInstance("setApplicationRestrictions");
+ }
+
if (mService != null) {
try {
mService.setApplicationRestrictions(admin, mContext.getPackageName(), packageName,
- settings);
+ settings, mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11704,11 +11717,14 @@
@WorkerThread
public @NonNull Bundle getApplicationRestrictions(
@Nullable ComponentName admin, String packageName) {
- throwIfParentInstance("getApplicationRestrictions");
+ if (!Flags.dmrhCanSetAppRestriction()) {
+ throwIfParentInstance("getApplicationRestrictions");
+ }
+
if (mService != null) {
try {
return mService.getApplicationRestrictions(admin, mContext.getPackageName(),
- packageName);
+ packageName, mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -13986,8 +14002,15 @@
public @NonNull DevicePolicyManager getParentProfileInstance(@NonNull ComponentName admin) {
throwIfParentInstance("getParentProfileInstance");
try {
- if (!mService.isManagedProfile(admin)) {
- throw new SecurityException("The current user does not have a parent profile.");
+ if (Flags.dmrhCanSetAppRestriction()) {
+ UserManager um = mContext.getSystemService(UserManager.class);
+ if (!um.isManagedProfile()) {
+ throw new SecurityException("The current user does not have a parent profile.");
+ }
+ } else {
+ if (!mService.isManagedProfile(admin)) {
+ throw new SecurityException("The current user does not have a parent profile.");
+ }
}
return new DevicePolicyManager(mContext, mService, true);
} catch (RemoteException e) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index d4589dc..2002326 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -244,8 +244,8 @@
void setDefaultSmsApplication(in ComponentName admin, String callerPackageName, String packageName, boolean parent);
void setDefaultDialerApplication(String packageName);
- void setApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName, in Bundle settings);
- Bundle getApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName);
+ void setApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName, in Bundle settings, in boolean parent);
+ Bundle getApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName, in boolean parent);
boolean setApplicationRestrictionsManagingPackage(in ComponentName admin, in String packageName);
String getApplicationRestrictionsManagingPackage(in ComponentName admin);
boolean isCallerApplicationRestrictionsManagingPackage(in String callerPackage);
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 6b2baa7..56fb4aa 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -204,6 +204,13 @@
}
flag {
+ name: "dmrh_can_set_app_restriction"
+ namespace: "enterprise"
+ description: "Allow DMRH to set application restrictions (both on the profile and the parent)"
+ bug: "328758346"
+}
+
+flag {
name: "allow_screen_brightness_control_on_cope"
namespace: "enterprise"
description: "Allow COPE admin to control screen brightness and timeout."
diff --git a/core/java/android/permission/TEST_MAPPING b/core/java/android/permission/TEST_MAPPING
index 69113ef..a15d9bc 100644
--- a/core/java/android/permission/TEST_MAPPING
+++ b/core/java/android/permission/TEST_MAPPING
@@ -11,5 +11,29 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsVirtualDevicesAudioTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "include-filter": "android.virtualdevice.cts.audio.VirtualAudioPermissionTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsVirtualDevicesAppLaunchTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "include-filter": "android.virtualdevice.cts.applaunch.VirtualDevicePermissionTest"
+ }
+ ]
+ }
]
}
\ No newline at end of file
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index c1be6b5..50fdb8a 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -121,3 +121,13 @@
description: "Enables apps owning a MediaBrowserService to disconnect all connected browsers."
bug: "185136506"
}
+
+flag {
+ name: "enable_prevention_of_manager_scans_when_no_apps_scan"
+ namespace: "media_solutions"
+ description: "Prevents waking up route providers when no apps are scanning, even if SysUI or Settings are scanning."
+ bug: "319604673"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
index 7093ba4..f86eb61 100644
--- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
+++ b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
@@ -139,7 +139,7 @@
static final String NAMESPACE_TO_PACKAGE_MAPPING_FLAG =
"namespace_to_package_mapping";
@VisibleForTesting
- static final long DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN = 10;
+ static final long DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN = 1440;
private static final String NAME = "rescue-party-observer";
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
index 6b833cc..0282f03 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
@@ -16,6 +16,7 @@
package com.android.settingslib.applications;
+import android.annotation.NonNull;
import android.app.usage.StorageStats;
import android.app.usage.StorageStatsManager;
import android.content.Context;
@@ -25,6 +26,7 @@
import androidx.annotation.VisibleForTesting;
import java.io.IOException;
+import java.util.UUID;
/**
* StorageStatsSource wraps the StorageStatsManager for testability purposes.
@@ -59,6 +61,10 @@
return mStorageStatsManager.getCacheQuotaBytes(volumeUuid, uid);
}
+ public long getTotalBytes(@NonNull UUID storageUuid) throws IOException {
+ return mStorageStatsManager.getTotalBytes(storageUuid);
+ }
+
/**
* Static class that provides methods for querying the amount of external storage available as
* well as breaking it up into several media types.
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
index 7a73c58..8129e41 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
@@ -71,7 +71,6 @@
return remember(clock, topInset, topmostTop) {
BurnInParameters(
- clockControllerProvider = { clock },
topInset = topInset,
minViewY = topmostTop,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
index f517cec..31337a6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
@@ -23,6 +23,7 @@
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.burnInInteractor
@@ -60,10 +61,7 @@
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
private lateinit var underTest: AodBurnInViewModel
- private var burnInParameters =
- BurnInParameters(
- clockControllerProvider = { clockController },
- )
+ private var burnInParameters = BurnInParameters()
private val burnInFlow = MutableStateFlow(BurnInModel())
@Before
@@ -76,6 +74,7 @@
whenever(goneToAodTransitionViewModel.enterFromTopTranslationY(anyInt()))
.thenReturn(emptyFlow())
kosmos.goneToAodTransitionViewModel = goneToAodTransitionViewModel
+ kosmos.fakeKeyguardClockRepository.setCurrentClock(clockController)
underTest = kosmos.aodBurnInViewModel
}
diff --git a/packages/SystemUI/res/anim/slide_in_up.xml b/packages/SystemUI/res/anim/slide_in_up.xml
new file mode 100644
index 0000000..6089a28
--- /dev/null
+++ b/packages/SystemUI/res/anim/slide_in_up.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<translate
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromYDelta="100%p"
+ android:toYDelta="0"
+ android:duration="@android:integer/config_shortAnimTime" />
diff --git a/packages/SystemUI/res/anim/slide_out_down.xml b/packages/SystemUI/res/anim/slide_out_down.xml
new file mode 100644
index 0000000..5a7b591
--- /dev/null
+++ b/packages/SystemUI/res/anim/slide_out_down.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<translate
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromYDelta="0"
+ android:toYDelta="100%p"
+ android:duration="@android:integer/config_shortAnimTime" />
diff --git a/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml b/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml
index 1b12e74..0406f0e 100644
--- a/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml
+++ b/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml
@@ -14,12 +14,15 @@
limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="48"
android:viewportHeight="48"
- android:tint="?android:attr/textColorSecondary">
+ android:tint="?androidprv:attr/materialColorOnSurfaceVariant">
<path
android:fillColor="@android:color/white"
+ android:strokeColor="@android:color/white"
+ android:strokeWidth="2"
android:pathData="M39.8,41.95 L26.65,28.8Q25.15,30.1 23.15,30.825Q21.15,31.55 18.9,31.55Q13.5,31.55 9.75,27.8Q6,24.05 6,18.75Q6,13.45 9.75,9.7Q13.5,5.95 18.85,5.95Q24.15,5.95 27.875,9.7Q31.6,13.45 31.6,18.75Q31.6,20.9 30.9,22.9Q30.2,24.9 28.8,26.65L42,39.75ZM18.85,28.55Q22.9,28.55 25.75,25.675Q28.6,22.8 28.6,18.75Q28.6,14.7 25.75,11.825Q22.9,8.95 18.85,8.95Q14.75,8.95 11.875,11.825Q9,14.7 9,18.75Q9,22.8 11.875,25.675Q14.75,28.55 18.85,28.55Z"/>
-</vector>
\ No newline at end of file
+</vector>
diff --git a/packages/SystemUI/res/drawable/shortcut_button_colored.xml b/packages/SystemUI/res/drawable/shortcut_button_colored.xml
index bf90853..2e2d9b9 100644
--- a/packages/SystemUI/res/drawable/shortcut_button_colored.xml
+++ b/packages/SystemUI/res/drawable/shortcut_button_colored.xml
@@ -21,7 +21,7 @@
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
- <corners android:radius="16dp"/>
+ <corners android:radius="@dimen/ksh_button_corner_radius"/>
<solid android:color="?androidprv:attr/materialColorSurfaceBright"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml b/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml
index f692ed97..5b88bb9 100644
--- a/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml
+++ b/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml
@@ -21,7 +21,7 @@
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
- <corners android:radius="16dp"/>
+ <corners android:radius="@dimen/ksh_button_corner_radius"/>
<solid android:color="?androidprv:attr/materialColorPrimary"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml b/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml
index 6ce3eae..aa0b268 100644
--- a/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml
@@ -17,8 +17,8 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?android:attr/colorBackground"/>
- <corners android:topLeftRadius="16dp"
- android:topRightRadius="16dp"
+ <corners android:topLeftRadius="@dimen/ksh_dialog_top_corner_radius"
+ android:topRightRadius="@dimen/ksh_dialog_top_corner_radius"
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"/>
-</shape>
\ No newline at end of file
+</shape>
diff --git a/packages/SystemUI/res/drawable/shortcut_search_background.xml b/packages/SystemUI/res/drawable/shortcut_search_background.xml
index 66fc191..d6847f0 100644
--- a/packages/SystemUI/res/drawable/shortcut_search_background.xml
+++ b/packages/SystemUI/res/drawable/shortcut_search_background.xml
@@ -19,8 +19,8 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<item>
<shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="24dp" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceBright" />
+ <corners android:radius="@dimen/ksh_search_box_corner_radius" />
</shape>
</item>
-</layer-list>
\ No newline at end of file
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/shortcut_search_cancel_button.xml b/packages/SystemUI/res/drawable/shortcut_search_cancel_button.xml
index 6c4d4fb..2675906 100644
--- a/packages/SystemUI/res/drawable/shortcut_search_cancel_button.xml
+++ b/packages/SystemUI/res/drawable/shortcut_search_cancel_button.xml
@@ -20,7 +20,7 @@
<shape android:shape="oval">
<size android:width="24dp"
android:height="24dp" />
- <solid android:color="?androidprv:attr/colorSurface"/>
+ <solid android:color="?androidprv:attr/materialColorSurfaceBright"/>
</shape>
</item>
</ripple>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
index a005100..5ab2327 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
@@ -15,13 +15,14 @@
~ limitations under the License
-->
<com.android.systemui.statusbar.KeyboardShortcutAppItemLayout
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:background="@drawable/list_item_background"
android:focusable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="48dp"
+ android:minHeight="@dimen/ksh_app_item_minimum_height"
android:paddingBottom="8dp">
<ImageView
android:id="@+id/keyboard_shortcuts_icon"
@@ -39,7 +40,8 @@
android:layout_height="wrap_content"
android:paddingEnd="12dp"
android:paddingBottom="4dp"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="16sp"
android:maxLines="5"
android:singleLine="false"
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml
index 530e46e..76e5b12 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml
@@ -15,6 +15,6 @@
limitations under the License
-->
<View xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="0dp"
+ android:layout_marginTop="@dimen/ksh_category_separator_margin"
+ android:layout_marginBottom="@dimen/ksh_category_separator_margin"
style="@style/ShortcutHorizontalDivider" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
index 4f100f6..6e7fde6 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
@@ -16,10 +16,12 @@
~ limitations under the License
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="14sp"
- android:fontFamily="sans-serif-medium"
+ android:textColor="?androidprv:attr/materialColorPrimary"
android:importantForAccessibility="yes"
android:paddingTop="20dp"
android:paddingBottom="10dp"/>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
index f6042e4..2cfd644 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
@@ -16,15 +16,21 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:background="@drawable/shortcut_dialog_bg"
android:layout_width="@dimen/ksh_layout_width"
android:layout_height="wrap_content"
android:orientation="vertical">
+
+ <com.google.android.material.bottomsheet.BottomSheetDragHandleView
+ android:id="@+id/drag_handle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
<TextView
android:id="@+id/shortcut_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="40dp"
android:layout_gravity="center_horizontal"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="?android:attr/textColorPrimary"
@@ -39,44 +45,47 @@
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
- android:layout_marginStart="49dp"
- android:layout_marginEnd="49dp"
+ android:layout_marginStart="@dimen/ksh_container_horizontal_margin"
+ android:layout_marginEnd="@dimen/ksh_container_horizontal_margin"
android:padding="16dp"
android:background="@drawable/shortcut_search_background"
android:drawableStart="@drawable/ic_shortcutlist_search"
android:drawablePadding="15dp"
android:singleLine="true"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
android:inputType="text"
android:textDirection="locale"
android:textAlignment="viewStart"
android:hint="@string/keyboard_shortcut_search_list_hint"
- android:textColorHint="?android:attr/textColorTertiary" />
+ android:textAppearance="@android:style/TextAppearance.Material"
+ android:textSize="16sp"
+ android:textColorHint="?androidprv:attr/materialColorOutline" />
<ImageButton
android:id="@+id/keyboard_shortcuts_search_cancel"
android:layout_gravity="center_vertical|end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="49dp"
+ android:layout_marginEnd="@dimen/ksh_container_horizontal_margin"
android:padding="16dp"
android:contentDescription="@string/keyboard_shortcut_clear_text"
android:src="@drawable/ic_shortcutlist_search_button_cancel"
android:background="@drawable/shortcut_search_cancel_button"
style="@android:style/Widget.Material.Button.Borderless.Small"
- android:pointerIcon="arrow" />
+ android:pointerIcon="arrow"
+ android:visibility="gone" />
</FrameLayout>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="49dp"
+ android:layout_marginStart="@dimen/ksh_container_horizontal_margin"
android:layout_marginEnd="0dp"
android:scrollbars="none">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
android:orientation="horizontal">
<Button
android:id="@+id/shortcut_system"
@@ -113,29 +122,29 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
- android:layout_marginStart="49dp"
- android:layout_marginEnd="49dp"
+ android:layout_marginStart="@dimen/ksh_container_horizontal_margin"
+ android:layout_marginEnd="@dimen/ksh_container_horizontal_margin"
android:layout_gravity="center_horizontal"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/keyboard_shortcut_search_list_no_result"/>
- <ScrollView
+ <androidx.core.widget.NestedScrollView
android:id="@+id/keyboard_shortcuts_scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
- android:layout_marginStart="49dp"
- android:layout_marginEnd="49dp"
+ android:layout_marginStart="@dimen/ksh_container_horizontal_margin"
+ android:layout_marginEnd="@dimen/ksh_container_horizontal_margin"
android:overScrollMode="never"
- android:layout_marginBottom="16dp"
+ android:clipToPadding="false"
android:scrollbars="none">
<LinearLayout
android:id="@+id/keyboard_shortcuts_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
- </ScrollView>
+ </androidx.core.widget.NestedScrollView>
<!-- Required for stretching to full available height when the items in the scroll view
occupy less space then the full height -->
<View
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 55606aa..56ebc06 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -94,4 +94,7 @@
<dimen name="keyguard_indication_margin_bottom">8dp</dimen>
<dimen name="lock_icon_margin_bottom">24dp</dimen>
+
+ <!-- Keyboard shortcuts helper -->
+ <dimen name="ksh_container_horizontal_margin">48dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f2288a4..b95ee56 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -978,6 +978,7 @@
<dimen name="assist_disclosure_shadow_thickness">1.5dp</dimen>
<!-- Keyboard shortcuts helper -->
+ <dimen name="ksh_container_horizontal_margin">32dp</dimen>
<dimen name="ksh_layout_width">@dimen/match_parent</dimen>
<dimen name="ksh_item_text_size">14sp</dimen>
<dimen name="ksh_item_padding">0dp</dimen>
@@ -985,6 +986,11 @@
<dimen name="ksh_icon_scaled_size">18dp</dimen>
<dimen name="ksh_key_view_padding_vertical">4dp</dimen>
<dimen name="ksh_key_view_padding_horizontal">12dp</dimen>
+ <dimen name="ksh_button_corner_radius">12dp</dimen>
+ <dimen name="ksh_dialog_top_corner_radius">28dp</dimen>
+ <dimen name="ksh_search_box_corner_radius">100dp</dimen>
+ <dimen name="ksh_app_item_minimum_height">64dp</dimen>
+ <dimen name="ksh_category_separator_margin">16dp</dimen>
<!-- The size of corner radius of the arrow in the onboarding toast. -->
<dimen name="recents_onboarding_toast_arrow_corner_radius">2dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e825f32..9da4f79 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -366,6 +366,21 @@
<item name="android:layout_height">wrap_content</item>
</style>
+ <style name="KeyboardShortcutHelper" parent="@android:style/Theme.DeviceDefault.Settings">
+ <!-- Needed to be able to use BottomSheetDragHandleView -->
+ <item name="android:windowActionBar">false</item>
+ <item name="bottomSheetDragHandleStyle">@style/KeyboardShortcutHelper.BottomSheet.DragHandle</item>
+ </style>
+
+ <style name="KeyboardShortcutHelper.BottomSheet.DragHandle" parent="Widget.Material3.BottomSheet.DragHandle">
+ <item name="tint">?androidprv:attr/materialColorOutlineVariant</item>
+ </style>
+
+ <style name="KeyboardShortcutHelper.BottomSheetDialogAnimation">
+ <item name="android:windowEnterAnimation">@anim/slide_in_up</item>
+ <item name="android:windowExitAnimation">@anim/slide_out_down</item>
+ </style>
+
<style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer" />
<style name="Animation" />
@@ -1598,14 +1613,15 @@
<item name="android:layout_marginEnd">12dp</item>
<item name="android:paddingLeft">24dp</item>
<item name="android:paddingRight">24dp</item>
- <item name="android:minHeight">40dp</item>
+ <item name="android:minHeight">36dp</item>
+ <item name="android:minWidth">120dp</item>
<item name="android:stateListAnimator">@*android:anim/flat_button_state_list_anim_material</item>
<item name="android:pointerIcon">arrow</item>
</style>
<style name="ShortcutHorizontalDivider">
- <item name="android:layout_width">120dp</item>
- <item name="android:layout_height">1dp</item>
+ <item name="android:layout_width">132dp</item>
+ <item name="android:layout_height">2dp</item>
<item name="android:layout_gravity">center_horizontal</item>
<item name="android:background">?android:attr/dividerHorizontal</item>
</style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 4632914..dcc1440 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -155,5 +155,10 @@
*/
oneway void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) = 54;
- // Next id = 55
+ /**
+ * Set the override value for home button long press duration in ms and slop multiplier.
+ */
+ oneway void setOverrideHomeButtonLongPress(long duration, float slopMultiplier) = 55;
+
+ // Next id = 56
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 9f7e0d4..e6e6ff6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -208,7 +208,7 @@
chipbarCoordinator,
screenOffAnimationController,
shadeInteractor,
- { keyguardStatusViewController!!.getClockController() },
+ clockInteractor,
interactionJankMonitor,
deviceEntryHapticsInteractor,
vibratorHelper,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
index 99b691e..d551c9b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -17,7 +17,9 @@
package com.android.systemui.keyguard.domain.interactor
+import android.util.Log
import com.android.keyguard.ClockEventController
+import com.android.keyguard.KeyguardClockSwitch
import com.android.keyguard.KeyguardClockSwitch.ClockSize
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardClockRepository
@@ -54,6 +56,15 @@
keyguardClockRepository.setClockSize(size)
}
+ val renderedClockId: ClockId
+ get() {
+ return clock?.let { clock -> clock.config.id }
+ ?: run {
+ Log.e(TAG, "No clock is available")
+ KeyguardClockSwitch.MISSING_CLOCK_ID
+ }
+ }
+
fun animateFoldToAod(foldFraction: Float) {
clock?.let { clock ->
clock.smallClock.animations.fold(foldFraction)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 5f50f7e..0249abd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -36,7 +36,6 @@
import com.android.app.tracing.coroutines.launch
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
-import com.android.keyguard.KeyguardClockSwitch.MISSING_CLOCK_ID
import com.android.systemui.Flags.newAodTransition
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
@@ -47,6 +46,7 @@
import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.MigrateClocksToBlueprint
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
@@ -55,7 +55,6 @@
import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.CrossFadeHelper
@@ -69,7 +68,6 @@
import com.android.systemui.util.ui.isAnimating
import com.android.systemui.util.ui.stopAnimating
import com.android.systemui.util.ui.value
-import javax.inject.Provider
import kotlin.math.min
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DisposableHandle
@@ -93,7 +91,7 @@
chipbarCoordinator: ChipbarCoordinator,
screenOffAnimationController: ScreenOffAnimationController,
shadeInteractor: ShadeInteractor,
- clockControllerProvider: Provider<ClockController>?,
+ clockInteractor: KeyguardClockInteractor,
interactionJankMonitor: InteractionJankMonitor?,
deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor?,
vibratorHelper: VibratorHelper?,
@@ -281,14 +279,11 @@
viewModel.goneToAodTransition.collect {
when (it.transitionState) {
TransitionState.STARTED -> {
- val clockId =
- clockControllerProvider?.get()?.config?.id
- ?: MISSING_CLOCK_ID
+ val clockId = clockInteractor.renderedClockId
val builder =
InteractionJankMonitor.Configuration.Builder
.withView(CUJ_SCREEN_OFF_SHOW_AOD, view)
.setTag(clockId)
-
jankMonitor.begin(builder)
}
TransitionState.CANCELED ->
@@ -345,12 +340,6 @@
}
}
- if (!MigrateClocksToBlueprint.isEnabled) {
- burnInParams.update { current ->
- current.copy(clockControllerProvider = clockControllerProvider)
- }
- }
-
if (MigrateClocksToBlueprint.isEnabled) {
burnInParams.update { current ->
current.copy(translationY = { childViews[burnInLayerId]?.translationY })
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 9195b4f..39df4c3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -60,6 +60,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.MigrateClocksToBlueprint
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
@@ -140,6 +141,7 @@
private val secureSettings: SecureSettings,
private val communalTutorialViewModel: CommunalTutorialIndicatorViewModel,
private val defaultShortcutsSection: DefaultShortcutsSection,
+ private val keyguardClockInteractor: KeyguardClockInteractor,
) {
val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
private val width: Int = bundle.getInt(KEY_VIEW_WIDTH)
@@ -364,6 +366,7 @@
),
)
}
+
@OptIn(ExperimentalCoroutinesApi::class)
private fun setupKeyguardRootView(previewContext: Context, rootView: FrameLayout) {
val keyguardRootView = KeyguardRootView(previewContext, null)
@@ -377,7 +380,7 @@
chipbarCoordinator,
screenOffAnimationController,
shadeInteractor,
- null, // clock provider only needed for burn in
+ keyguardClockInteractor,
null, // jank monitor not required for preview mode
null, // device entry haptics not required preview mode
null, // device entry haptics not required for preview mode
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
index 2054932..4ddd5711 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -33,10 +33,8 @@
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.ui.StateToValue
-import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.res.R
import javax.inject.Inject
-import javax.inject.Provider
import kotlin.math.max
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -128,12 +126,12 @@
yDimenResourceId = R.dimen.burn_in_prevention_offset_y
),
) { interpolated, burnIn ->
+ val useAltAod =
+ keyguardClockViewModel.currentClock.value?.let { clock ->
+ clock.config.useAlternateSmartspaceAODTransition
+ } == true
val useScaleOnly =
- (clockController(params.clockControllerProvider)
- ?.get()
- ?.config
- ?.useAlternateSmartspaceAODTransition
- ?: false) && keyguardClockViewModel.clockSize.value == KeyguardClockSwitch.LARGE
+ useAltAod && keyguardClockViewModel.clockSize.value == KeyguardClockSwitch.LARGE
if (useScaleOnly) {
BurnInModel(
@@ -164,21 +162,10 @@
}
}
}
-
- private fun clockController(
- provider: Provider<ClockController>?,
- ): Provider<ClockController>? {
- return if (MigrateClocksToBlueprint.isEnabled) {
- Provider { keyguardClockViewModel.currentClock.value }
- } else {
- provider
- }
- }
}
/** UI-sourced parameters to pass into the various methods of [AodBurnInViewModel]. */
data class BurnInParameters(
- val clockControllerProvider: Provider<ClockController>? = null,
/** System insets that keyguard needs to stay out of */
val topInset: Int = 0,
/** The min y-value of the visible elements on lockscreen */
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 4fe3a11..ade56c4 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -85,6 +85,7 @@
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
@@ -186,6 +187,7 @@
/** Allow some time inbetween the long press for back and recents. */
private static final int LOCK_TO_APP_GESTURE_TOLERANCE = 200;
private static final long AUTODIM_TIMEOUT_MS = 2250;
+ private static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 3f;
private final Context mContext;
private final Bundle mSavedState;
@@ -223,6 +225,7 @@
private final int mNavColorSampleMargin;
private EdgeBackGestureHandler mEdgeBackGestureHandler;
private NavigationBarFrame mFrame;
+ private MotionEvent mCurrentDownEvent;
private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
@@ -238,6 +241,8 @@
private int mLayoutDirection;
private Optional<Long> mHomeButtonLongPressDurationMs;
+ private Optional<Long> mOverrideHomeButtonLongPressDurationMs = Optional.empty();
+ private Optional<Float> mOverrideHomeButtonLongPressSlopMultiplier = Optional.empty();
/** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
private @Appearance int mAppearance;
@@ -405,6 +410,25 @@
}
@Override
+ public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier) {
+ mOverrideHomeButtonLongPressDurationMs = Optional.of(duration)
+ .filter(value -> value > 0);
+ mOverrideHomeButtonLongPressSlopMultiplier = Optional.of(slopMultiplier)
+ .filter(value -> value > 0);
+ if (mOverrideHomeButtonLongPressDurationMs.isPresent()) {
+ Log.d(TAG, "Receive duration override: "
+ + mOverrideHomeButtonLongPressDurationMs.get());
+ }
+ if (mOverrideHomeButtonLongPressSlopMultiplier.isPresent()) {
+ Log.d(TAG, "Receive slop multiplier override: "
+ + mOverrideHomeButtonLongPressSlopMultiplier.get());
+ }
+ if (mView != null) {
+ reconfigureHomeLongClick();
+ }
+ }
+
+ @Override
public void onHomeRotationEnabled(boolean enabled) {
mView.getRotationButtonController().setHomeRotationEnabled(enabled);
}
@@ -1016,7 +1040,10 @@
if (mView.getHomeButton().getCurrentView() == null) {
return;
}
- if (mHomeButtonLongPressDurationMs.isPresent() || !mLongPressHomeEnabled) {
+ if (mHomeButtonLongPressDurationMs.isPresent()
+ || mOverrideHomeButtonLongPressDurationMs.isPresent()
+ || mOverrideHomeButtonLongPressSlopMultiplier.isPresent()
+ || !mLongPressHomeEnabled) {
mView.getHomeButton().getCurrentView().setLongClickable(false);
mView.getHomeButton().getCurrentView().setHapticFeedbackEnabled(false);
mView.getHomeButton().setOnLongClickListener(null);
@@ -1038,6 +1065,10 @@
pw.println(" mStartingQuickSwitchRotation=" + mStartingQuickSwitchRotation);
pw.println(" mCurrentRotation=" + mCurrentRotation);
pw.println(" mHomeButtonLongPressDurationMs=" + mHomeButtonLongPressDurationMs);
+ pw.println(" mOverrideHomeButtonLongPressDurationMs="
+ + mOverrideHomeButtonLongPressDurationMs);
+ pw.println(" mOverrideHomeButtonLongPressSlopMultiplier="
+ + mOverrideHomeButtonLongPressSlopMultiplier);
pw.println(" mLongPressHomeEnabled=" + mLongPressHomeEnabled);
pw.println(" mNavigationBarWindowState="
+ windowStateToString(mNavigationBarWindowState));
@@ -1331,6 +1362,10 @@
final Optional<CentralSurfaces> centralSurfacesOptional = mCentralSurfacesOptionalLazy.get();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
+ if (mCurrentDownEvent != null) {
+ mCurrentDownEvent.recycle();
+ }
+ mCurrentDownEvent = MotionEvent.obtain(event);
mHomeBlockedThisTouch = false;
if (mTelecomManagerOptional.isPresent()
&& mTelecomManagerOptional.get().isRinging()) {
@@ -1342,9 +1377,45 @@
}
}
if (mLongPressHomeEnabled) {
- mHomeButtonLongPressDurationMs.ifPresent(longPressDuration -> {
- mHandler.postDelayed(mOnVariableDurationHomeLongClick, longPressDuration);
- });
+ if (mOverrideHomeButtonLongPressDurationMs.isPresent()) {
+ Log.d(TAG, "ACTION_DOWN Launcher override duration: "
+ + mOverrideHomeButtonLongPressDurationMs.get());
+ mHandler.postDelayed(mOnVariableDurationHomeLongClick,
+ mOverrideHomeButtonLongPressDurationMs.get());
+ } else if (mOverrideHomeButtonLongPressSlopMultiplier.isPresent()) {
+ // If override timeout doesn't exist but override touch slop exists, we use
+ // system default long press duration
+ Log.d(TAG, "ACTION_DOWN default duration: "
+ + ViewConfiguration.getLongPressTimeout());
+ mHandler.postDelayed(mOnVariableDurationHomeLongClick,
+ ViewConfiguration.getLongPressTimeout());
+ } else {
+ mHomeButtonLongPressDurationMs.ifPresent(longPressDuration -> {
+ Log.d(TAG, "ACTION_DOWN original duration: " + longPressDuration);
+ mHandler.postDelayed(mOnVariableDurationHomeLongClick,
+ longPressDuration);
+ });
+ }
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (!mHandler.hasCallbacks(mOnVariableDurationHomeLongClick)) {
+ Log.w(TAG, "No callback. Don't handle touch slop.");
+ break;
+ }
+ float customSlopMultiplier = mOverrideHomeButtonLongPressSlopMultiplier.orElse(1f);
+ float touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ float calculatedTouchSlop =
+ customSlopMultiplier * QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON * touchSlop;
+ float touchSlopSquared = calculatedTouchSlop * calculatedTouchSlop;
+
+ float dx = event.getX() - mCurrentDownEvent.getX();
+ float dy = event.getY() - mCurrentDownEvent.getY();
+ double distanceSquared = (dx * dx) + (dy * dy);
+ if (distanceSquared > touchSlopSquared) {
+ Log.i(TAG, "Touch slop passed. Abort.");
+ mView.abortCurrentGesture();
+ mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
}
break;
case MotionEvent.ACTION_UP:
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 7c1a2c0..f621f11 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -259,6 +259,12 @@
}
@Override
+ public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier) {
+ verifyCallerAndClearCallingIdentityPostMain("setOverrideHomeButtonLongPress",
+ () -> notifySetOverrideHomeButtonLongPress(duration, slopMultiplier));
+ }
+
+ @Override
public void onBackPressed() {
verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> {
sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
@@ -947,6 +953,12 @@
}
}
+ private void notifySetOverrideHomeButtonLongPress(long duration, float slopMultiplier) {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).setOverrideHomeButtonLongPress(duration, slopMultiplier);
+ }
+ }
+
public void notifyAssistantVisibilityChanged(float visibility) {
try {
if (mOverviewProxy != null) {
@@ -1104,6 +1116,8 @@
default void startAssistant(Bundle bundle) {}
default void setAssistantOverridesRequested(int[] invocationTypes) {}
default void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) {}
+ /** Set override of home button long press duration and touch slop multiplier. */
+ default void setOverrideHomeButtonLongPress(long override, float slopMultiplier) {}
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
index d6858ca..78e108d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -40,6 +40,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.text.Editable;
+import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.util.Pair;
@@ -57,6 +58,7 @@
import android.view.View.AccessibilityDelegate;
import android.view.ViewGroup;
import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button;
@@ -104,6 +106,7 @@
private WindowManager mWindowManager;
private EditText mSearchEditText;
+ private ImageButton mEditTextCancel;
private String mQueryString;
private int mCurrentCategoryIndex = 0;
private Map<Integer, Boolean> mKeySearchResultMap = new HashMap<>();
@@ -143,7 +146,7 @@
@VisibleForTesting
KeyboardShortcutListSearch(Context context, WindowManager windowManager) {
this.mContext = new ContextThemeWrapper(
- context, android.R.style.Theme_DeviceDefault_Settings);
+ context, R.style.KeyboardShortcutHelper);
this.mPackageManager = AppGlobals.getPackageManager();
if (windowManager != null) {
this.mWindowManager = windowManager;
@@ -853,13 +856,14 @@
List<List<KeyboardShortcutMultiMappingGroup>> keyboardShortcutMultiMappingGroupList) {
mQueryString = null;
LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
- mKeyboardShortcutsBottomSheetDialog =
- new BottomSheetDialog(mContext);
+ mKeyboardShortcutsBottomSheetDialog = new BottomSheetDialog(mContext);
final View keyboardShortcutsView = inflater.inflate(
R.layout.keyboard_shortcuts_search_view, null);
LinearLayout shortcutsContainer = keyboardShortcutsView.findViewById(
R.id.keyboard_shortcuts_container);
mNoSearchResults = keyboardShortcutsView.findViewById(R.id.shortcut_search_no_result);
+ Window keyboardShortcutsWindow = mKeyboardShortcutsBottomSheetDialog.getWindow();
+ setWindowProperties(keyboardShortcutsWindow);
mKeyboardShortcutsBottomSheetDialog.setContentView(keyboardShortcutsView);
setButtonsDefaultStatus(keyboardShortcutsView);
populateCurrentAppButton();
@@ -874,25 +878,11 @@
}
BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
+ behavior.setDraggable(true);
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
behavior.setSkipCollapsed(true);
- behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
- @Override
- public void onStateChanged(@NonNull View bottomSheet, int newState) {
- if (newState == BottomSheetBehavior.STATE_DRAGGING) {
- behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
- }
- }
- @Override
- public void onSlide(@NonNull View bottomSheet, float slideOffset) {
- // Do nothing.
- }
- });
- mKeyboardShortcutsBottomSheetDialog.setCanceledOnTouchOutside(true);
- Window keyboardShortcutsWindow = mKeyboardShortcutsBottomSheetDialog.getWindow();
- keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
synchronized (sLock) {
// show KeyboardShortcutsBottomSheetDialog only if it has not been dismissed already
if (sInstance != null) {
@@ -908,6 +898,8 @@
}
}
mSearchEditText = keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_search);
+ mEditTextCancel = keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_search_cancel);
mSearchEditText.addTextChangedListener(
new TextWatcher() {
@Override
@@ -921,6 +913,8 @@
shortcutsContainer.setAccessibilityPaneTitle(mContext.getString(
R.string.keyboard_shortcut_a11y_show_search_results));
}
+ mEditTextCancel.setVisibility(
+ TextUtils.isEmpty(mQueryString) ? View.GONE : View.VISIBLE);
}
@Override
@@ -933,9 +927,28 @@
// Do nothing.
}
});
- ImageButton editTextCancel = keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_search_cancel);
- editTextCancel.setOnClickListener(v -> mSearchEditText.setText(null));
+
+ mEditTextCancel.setOnClickListener(v -> mSearchEditText.setText(null));
+ }
+
+ private static void setWindowProperties(Window keyboardShortcutsWindow) {
+ keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
+ WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+ params.copyFrom(keyboardShortcutsWindow.getAttributes());
+ // Allows the bottom sheet dialog to render all the way to the bottom of the screen,
+ // behind the gesture navigation bar.
+ params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+ params.setFitInsetsTypes(WindowInsets.Type.statusBars());
+ keyboardShortcutsWindow.setAttributes(params);
+ keyboardShortcutsWindow.getDecorView().setOnApplyWindowInsetsListener((v, insets) -> {
+ int bottom = insets.getInsets(WindowInsets.Type.navigationBars()).bottom;
+ View container = v.findViewById(R.id.keyboard_shortcuts_container);
+ container.setPadding(container.getPaddingLeft(), container.getPaddingTop(),
+ container.getPaddingRight(), bottom);
+ return WindowInsets.CONSUMED;
+ });
+ keyboardShortcutsWindow.setWindowAnimations(
+ R.style.KeyboardShortcutHelper_BottomSheetDialogAnimation);
}
private void populateKeyboardShortcutSearchList(LinearLayout keyboardShortcutsLayout) {
@@ -1256,10 +1269,10 @@
if (mContext.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_PORTRAIT) {
lp.width = (int) (display.getWidth() * 0.8);
- lp.height = (int) (display.getHeight() * 0.7);
+ lp.height = (int) (display.getHeight() * 0.8);
} else {
lp.width = (int) (display.getWidth() * 0.7);
- lp.height = (int) (display.getHeight() * 0.8);
+ lp.height = (int) (display.getHeight() * 0.95);
}
window.setGravity(Gravity.BOTTOM);
window.setAttributes(lp);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 8ea29dd6..aa6bec1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -49,7 +49,6 @@
import com.android.systemui.deviceentry.shared.model.DeviceUnlockStatus;
import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
-import com.android.systemui.plugins.clocks.ClockController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.res.R;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
@@ -469,13 +468,7 @@
/** Returns the id of the currently rendering clock */
public String getClockId() {
if (MigrateClocksToBlueprint.isEnabled()) {
- ClockController clock = mKeyguardClockInteractorLazy.get()
- .getCurrentClock().getValue();
- if (clock == null) {
- Log.e(TAG, "No clock is available");
- return KeyguardClockSwitch.MISSING_CLOCK_ID;
- }
- return clock.getConfig().getId();
+ return mKeyguardClockInteractorLazy.get().getRenderedClockId();
}
if (mClockSwitchView == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index 20a82a4..d99af2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -165,6 +165,8 @@
public void showNotification(@NonNull NotificationEntry entry) {
HeadsUpEntry headsUpEntry = createHeadsUpEntry(entry);
+ mLogger.logShowNotificationRequest(entry);
+
Runnable runnable = () -> {
// TODO(b/315362456) log outside runnable too
mLogger.logShowNotification(entry);
@@ -219,6 +221,8 @@
*/
public void updateNotification(@NonNull String key, boolean shouldHeadsUpAgain) {
HeadsUpEntry headsUpEntry = mHeadsUpEntryMap.get(key);
+ mLogger.logUpdateNotificationRequest(key, shouldHeadsUpAgain, headsUpEntry != null);
+
Runnable runnable = () -> {
updateNotificationInternal(key, shouldHeadsUpAgain);
};
@@ -378,8 +382,11 @@
*/
protected final void removeEntry(@NonNull String key) {
HeadsUpEntry headsUpEntry = mHeadsUpEntryMap.get(key);
+ mLogger.logRemoveEntryRequest(key);
Runnable runnable = () -> {
+ mLogger.logRemoveEntry(key);
+
if (headsUpEntry == null) {
return;
}
@@ -566,8 +573,10 @@
public void unpinAll(boolean userUnPinned) {
for (String key : mHeadsUpEntryMap.keySet()) {
HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
-
+ mLogger.logUnpinEntryRequest(key);
Runnable runnable = () -> {
+ mLogger.logUnpinEntry(key);
+
setEntryPinned(headsUpEntry, false /* isPinned */);
// maybe it got un sticky
headsUpEntry.updateEntry(false /* updatePostTime */, "unpinAll");
@@ -886,6 +895,7 @@
* Clear any pending removal runnables.
*/
public void cancelAutoRemovalCallbacks(@Nullable String reason) {
+ mLogger.logAutoRemoveCancelRequest(this.mEntry, reason);
Runnable runnable = () -> {
final boolean removed = cancelAutoRemovalCallbackInternal();
@@ -900,6 +910,7 @@
public void scheduleAutoRemovalCallback(FinishTimeUpdater finishTimeCalculator,
@NonNull String reason) {
+ mLogger.logAutoRemoveRequest(this.mEntry, reason);
Runnable runnable = () -> {
long delayMs = finishTimeCalculator.updateAndGetTimeRemaining();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
index f6154afe..a306606 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
@@ -58,6 +58,14 @@
})
}
+ fun logShowNotificationRequest(entry: NotificationEntry) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ }, {
+ "request: show notification $str1"
+ })
+ }
+
fun logShowNotification(entry: NotificationEntry) {
buffer.log(TAG, INFO, {
str1 = entry.logKey
@@ -76,6 +84,15 @@
})
}
+ fun logAutoRemoveRequest(entry: NotificationEntry, reason: String) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ str2 = reason
+ }, {
+ "request: reschedule auto remove of $str1 reason: $str2"
+ })
+ }
+
fun logAutoRemoveRescheduled(entry: NotificationEntry, delayMillis: Long, reason: String) {
buffer.log(TAG, INFO, {
str1 = entry.logKey
@@ -86,6 +103,15 @@
})
}
+ fun logAutoRemoveCancelRequest(entry: NotificationEntry, reason: String?) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ str2 = reason ?: "unknown"
+ }, {
+ "request: cancel auto remove of $str1 reason: $str2"
+ })
+ }
+
fun logAutoRemoveCanceled(entry: NotificationEntry, reason: String?) {
buffer.log(TAG, INFO, {
str1 = entry.logKey
@@ -95,6 +121,38 @@
})
}
+ fun logRemoveEntryRequest(key: String) {
+ buffer.log(TAG, INFO, {
+ str1 = logKey(key)
+ }, {
+ "request: remove entry $str1"
+ })
+ }
+
+ fun logRemoveEntry(key: String) {
+ buffer.log(TAG, INFO, {
+ str1 = logKey(key)
+ }, {
+ "remove entry $str1"
+ })
+ }
+
+ fun logUnpinEntryRequest(key: String) {
+ buffer.log(TAG, INFO, {
+ str1 = logKey(key)
+ }, {
+ "request: unpin entry $str1"
+ })
+ }
+
+ fun logUnpinEntry(key: String) {
+ buffer.log(TAG, INFO, {
+ str1 = logKey(key)
+ }, {
+ "unpin entry $str1"
+ })
+ }
+
fun logRemoveNotification(key: String, releaseImmediately: Boolean) {
buffer.log(TAG, INFO, {
str1 = logKey(key)
@@ -112,6 +170,16 @@
})
}
+ fun logUpdateNotificationRequest(key: String, alert: Boolean, hasEntry: Boolean) {
+ buffer.log(TAG, INFO, {
+ str1 = logKey(key)
+ bool1 = alert
+ bool2 = hasEntry
+ }, {
+ "request: update notification $str1 alert: $bool1 hasEntry: $bool2 reason: $str2"
+ })
+ }
+
fun logUpdateNotification(key: String, alert: Boolean, hasEntry: Boolean) {
buffer.log(TAG, INFO, {
str1 = logKey(key)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
index d791e94..12165cd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt
@@ -20,4 +20,4 @@
import com.android.systemui.kosmos.Kosmos
val Kosmos.keyguardClockInteractor by
- Kosmos.Fixture { KeyguardClockInteractor(keyguardClockRepository = keyguardClockRepository) }
+ Kosmos.Fixture { KeyguardClockInteractor(keyguardClockRepository) }
diff --git a/ravenwood/bivalenttest/test/com/android/platform/test/ravenwood/bivalenttest/RavenwoodAndroidApiTest.java b/ravenwood/bivalenttest/test/com/android/platform/test/ravenwood/bivalenttest/RavenwoodAndroidApiTest.java
new file mode 100644
index 0000000..c11c1bb
--- /dev/null
+++ b/ravenwood/bivalenttest/test/com/android/platform/test/ravenwood/bivalenttest/RavenwoodAndroidApiTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 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.platform.test.ravenwood.bivalenttest;
+
+import static org.junit.Assert.assertEquals;
+
+import android.util.ArrayMap;
+import android.util.Size;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+// Tests for calling simple Android APIs.
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodAndroidApiTest {
+ @Test
+ public void testArrayMapSimple() {
+ final Map<String, String> map = new ArrayMap<>();
+
+ map.put("key1", "value1");
+ assertEquals("value1", map.get("key1"));
+ }
+
+ @Test
+ public void testSizeSimple() {
+ final var size = new Size(1, 2);
+
+ assertEquals(2, size.getHeight());
+ }
+}
diff --git a/ravenwood/bivalenttest/test/com/android/platform/test/ravenwood/bivalenttest/RavenwoodClassRuleDeviceOnlyTest.java b/ravenwood/bivalenttest/test/com/android/platform/test/ravenwood/bivalenttest/RavenwoodClassRuleDeviceOnlyTest.java
new file mode 100644
index 0000000..6f2465c
--- /dev/null
+++ b/ravenwood/bivalenttest/test/com/android/platform/test/ravenwood/bivalenttest/RavenwoodClassRuleDeviceOnlyTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 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.platform.test.ravenwood.bivalenttest;
+
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.ravenwood.RavenwoodClassRule;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@DisabledOnRavenwood
+public class RavenwoodClassRuleDeviceOnlyTest {
+ @ClassRule
+ public static final RavenwoodClassRule sRavenwood = new RavenwoodClassRule();
+
+ @Test
+ public void testDeviceOnly() {
+ Assert.assertFalse(RavenwoodRule.isOnRavenwood());
+ }
+}
diff --git a/ravenwood/bivalenttest/test/com/android/platform/test/ravenwood/bivalenttest/RavenwoodClassRuleRavenwoodOnlyTest.java b/ravenwood/bivalenttest/test/com/android/platform/test/ravenwood/bivalenttest/RavenwoodClassRuleRavenwoodOnlyTest.java
new file mode 100644
index 0000000..21b31d1
--- /dev/null
+++ b/ravenwood/bivalenttest/test/com/android/platform/test/ravenwood/bivalenttest/RavenwoodClassRuleRavenwoodOnlyTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.platform.test.ravenwood.bivalenttest;
+
+import android.platform.test.ravenwood.RavenwoodClassRule;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+// TODO: atest RavenwoodBivalentTest_device fails with the following message.
+// `RUNNER ERROR: Instrumentation reported numtests=7 but only ran 6`
+// @android.platform.test.annotations.DisabledOnNonRavenwood
+// Figure it out and then make DisabledOnNonRavenwood support TYPEs as well.
+@Ignore
+public class RavenwoodClassRuleRavenwoodOnlyTest {
+ @ClassRule
+ public static final RavenwoodClassRule sRavenwood = new RavenwoodClassRule();
+
+ @Test
+ public void testRavenwoodOnly() {
+ Assert.assertTrue(RavenwoodRule.isOnRavenwood());
+ }
+}
diff --git a/ravenwood/coretest/test/com/android/platform/test/ravenwood/coretest/RavenwoodTestRunnerValidationTest.java b/ravenwood/coretest/test/com/android/platform/test/ravenwood/coretest/RavenwoodTestRunnerValidationTest.java
index 2cd585f..4ee9a9c 100644
--- a/ravenwood/coretest/test/com/android/platform/test/ravenwood/coretest/RavenwoodTestRunnerValidationTest.java
+++ b/ravenwood/coretest/test/com/android/platform/test/ravenwood/coretest/RavenwoodTestRunnerValidationTest.java
@@ -40,7 +40,7 @@
public final RuleChain chain = RuleChain.outerRule(mThrown).around(mRavenwood);
public RavenwoodTestRunnerValidationTest() {
- Assume.assumeTrue(mRavenwood._ravenwood_private$isOptionalValidationEnabled());
+ Assume.assumeTrue(RavenwoodRule._$RavenwoodPrivate.isOptionalValidationEnabled());
// Because RavenwoodRule will throw this error before executing the test method,
// we can't do it in the test method itself.
// So instead, we initialize it here.
diff --git a/ravenwood/junit-src/android/platform/test/annotations/DisabledOnNonRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnNonRavenwood.java
index 8ca34ba..9d47f3a 100644
--- a/ravenwood/junit-src/android/platform/test/annotations/DisabledOnNonRavenwood.java
+++ b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnNonRavenwood.java
@@ -31,13 +31,17 @@
* which means if a test class has this annotation, you can't negate it in subclasses or
* on a per-method basis.
*
+ * THIS ANNOTATION CANNOT BE ADDED TO CLASSES AT THIS PONINT.
+ * See {@link com.android.platform.test.ravenwood.bivalenttest.RavenwoodClassRuleRavenwoodOnlyTest}
+ * for the reason.
+ *
* The {@code RAVENWOOD_RUN_DISABLED_TESTS} environmental variable won't work because it won't be
* propagated to the device. (We may support it in the future, possibly using a debug. sysprop.)
*
* @hide
*/
@Inherited
-@Target({ElementType.METHOD, ElementType.TYPE})
+@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DisabledOnNonRavenwood {
/**
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java
index 9a4d488..f4b7ec36 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java
@@ -25,6 +25,7 @@
import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.annotations.EnabledOnRavenwood;
+import org.junit.Assert;
import org.junit.Assume;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -41,27 +42,16 @@
public class RavenwoodClassRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
- // No special treatment when running outside Ravenwood; run tests as-is
if (!IS_ON_RAVENWOOD) {
- Assume.assumeTrue(shouldEnableOnDevice(description));
- return base;
- }
-
- if (ENABLE_PROBE_IGNORED) {
+ // This should be "Assume", not Assert, but if we use assume here, the device side
+ // test runner would complain.
+ // See the TODO comment in RavenwoodClassRuleRavenwoodOnlyTest.
+ Assert.assertTrue(shouldEnableOnDevice(description));
+ } else if (ENABLE_PROBE_IGNORED) {
Assume.assumeFalse(shouldStillIgnoreInProbeIgnoreMode(description));
- // Pass through to possible underlying RavenwoodRule for both environment
- // configuration and handling method-level annotations
- return base;
} else {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- Assume.assumeTrue(shouldEnableOnRavenwood(description));
- // Pass through to possible underlying RavenwoodRule for both environment
- // configuration and handling method-level annotations
- base.evaluate();
- }
- };
+ Assume.assumeTrue(shouldEnableOnRavenwood(description));
}
+ return base;
}
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 52ea340..a2e8ec1 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -28,7 +28,6 @@
import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.annotations.EnabledOnRavenwood;
import android.platform.test.annotations.IgnoreUnderRavenwood;
-import android.util.ArraySet;
import org.junit.Assume;
import org.junit.rules.TestRule;
@@ -278,6 +277,9 @@
return false;
}
}
+ if (description.getTestClass().getAnnotation(DisabledOnNonRavenwood.class) != null) {
+ return false;
+ }
return true;
}
@@ -413,10 +415,9 @@
};
}
- /**
- * Do not use it outside ravenwood core classes.
- */
- public boolean _ravenwood_private$isOptionalValidationEnabled() {
- return ENABLE_OPTIONAL_VALIDATION;
+ public static class _$RavenwoodPrivate {
+ public static boolean isOptionalValidationEnabled() {
+ return ENABLE_OPTIONAL_VALIDATION;
+ }
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 951f676..656611a 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1820,18 +1820,17 @@
+ "received with null profile proxy: "
+ btInfo)).printLog(TAG));
} else {
- @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec =
+ final Pair<Integer, Boolean> codecAndChanged =
mBtHelper.getCodecWithFallback(btInfo.mDevice,
btInfo.mProfile, btInfo.mIsLeOutput,
"MSG_L_SET_BT_ACTIVE_DEVICE");
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetBtActiveDevice(btInfo, codec,
- (btInfo.mProfile
- != BluetoothProfile.LE_AUDIO
+ mDeviceInventory.onSetBtActiveDevice(btInfo, codecAndChanged.first,
+ (btInfo.mProfile != BluetoothProfile.LE_AUDIO
|| btInfo.mIsLeOutput)
- ? mAudioService.getBluetoothContextualVolumeStream()
- : AudioSystem.STREAM_DEFAULT);
+ ? mAudioService.getBluetoothContextualVolumeStream()
+ : AudioSystem.STREAM_DEFAULT);
if (btInfo.mProfile == BluetoothProfile.LE_AUDIO
|| btInfo.mProfile
== BluetoothProfile.HEARING_AID) {
@@ -1866,13 +1865,13 @@
break;
case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: {
final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
- @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec =
- mBtHelper.getCodecWithFallback(btInfo.mDevice,
- btInfo.mProfile, btInfo.mIsLeOutput,
- "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE");
+ final Pair<Integer, Boolean> codecAndChanged = mBtHelper.getCodecWithFallback(
+ btInfo.mDevice, btInfo.mProfile, btInfo.mIsLeOutput,
+ "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE");
synchronized (mDeviceStateLock) {
- mDeviceInventory.onBluetoothDeviceConfigChange(
- btInfo, codec, BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
+ mDeviceInventory.onBluetoothDeviceConfigChange(btInfo,
+ codecAndChanged.first, codecAndChanged.second,
+ BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
}
} break;
case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 14428c4..ebe9c63 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -868,7 +868,8 @@
@GuardedBy("mDeviceBroker.mDeviceStateLock")
/*package*/ void onBluetoothDeviceConfigChange(
@NonNull AudioDeviceBroker.BtDeviceInfo btInfo,
- @AudioSystem.AudioFormatNativeEnumForBtCodec int codec, int event) {
+ @AudioSystem.AudioFormatNativeEnumForBtCodec int codec,
+ boolean codecChanged, int event) {
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
+ "onBluetoothDeviceConfigChange")
.set(MediaMetrics.Property.EVENT, BtHelper.deviceEventToString(event));
@@ -916,14 +917,12 @@
if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
- boolean codecChange = false;
if (btInfo.mProfile == BluetoothProfile.A2DP
|| btInfo.mProfile == BluetoothProfile.LE_AUDIO
|| btInfo.mProfile == BluetoothProfile.LE_AUDIO_BROADCAST) {
- if (di.mDeviceCodecFormat != codec) {
+ if (codecChanged) {
di.mDeviceCodecFormat = codec;
mConnectedDevices.replace(key, di);
- codecChange = true;
final int res = mAudioSystem.handleDeviceConfigChange(
btInfo.mAudioSystemDevice, address,
BtHelper.getName(btDevice), codec);
@@ -947,7 +946,7 @@
}
}
}
- if (!codecChange) {
+ if (!codecChanged) {
updateBluetoothPreferredModes_l(btDevice /*connectedDevice*/);
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ed58c40..40099581 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -47,6 +47,7 @@
import static com.android.media.audio.Flags.disablePrescaleAbsoluteVolume;
import static com.android.media.audio.Flags.ringerModeAffectsAlarm;
import static com.android.media.audio.Flags.setStreamVolumeOrder;
+import static com.android.media.audio.Flags.vgsVssSyncMuteOrder;
import static com.android.server.audio.SoundDoseHelper.ACTION_CHECK_MUSIC_ACTIVE;
import static com.android.server.utils.EventLogger.Event.ALOGE;
import static com.android.server.utils.EventLogger.Event.ALOGI;
@@ -4544,6 +4545,8 @@
+ setStreamVolumeOrder());
pw.println("\tandroid.media.audio.roForegroundAudioControl:"
+ roForegroundAudioControl());
+ pw.println("\tcom.android.media.audio.vgsVssSyncMuteOrder:"
+ + vgsVssSyncMuteOrder());
}
private void dumpAudioMode(PrintWriter pw) {
@@ -8317,13 +8320,23 @@
synced = true;
continue;
}
+ if (vgsVssSyncMuteOrder()) {
+ if ((isMuted() != streamMuted) && isVssMuteBijective(
+ stream)) {
+ mStreamStates[stream].mute(isMuted(),
+ "VGS.applyAllVolumes#1");
+ }
+ }
if (indexForStream != index) {
mStreamStates[stream].setIndex(index * 10, device, caller,
true /*hasModifyAudioSettings*/);
}
- if ((isMuted() != streamMuted) && isVssMuteBijective(stream)) {
- mStreamStates[stream].mute(isMuted(),
- "VGS.applyAllVolumes#1");
+ if (!vgsVssSyncMuteOrder()) {
+ if ((isMuted() != streamMuted) && isVssMuteBijective(
+ stream)) {
+ mStreamStates[stream].mute(isMuted(),
+ "VGS.applyAllVolumes#1");
+ }
}
}
}
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index f3a5fdb..edeabdc 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -98,9 +98,16 @@
private @Nullable BluetoothLeAudio mLeAudio;
+ private @Nullable BluetoothLeAudioCodecConfig mLeAudioCodecConfig;
+
// Reference to BluetoothA2dp to query for AbsoluteVolume.
private @Nullable BluetoothA2dp mA2dp;
+ private @Nullable BluetoothCodecConfig mA2dpCodecConfig;
+
+ private @AudioSystem.AudioFormatNativeEnumForBtCodec
+ int mLeAudioBroadcastCodec = AudioSystem.AUDIO_FORMAT_DEFAULT;
+
// If absolute volume is supported in AVRCP device
private boolean mAvrcpAbsVolSupported = false;
@@ -265,12 +272,15 @@
}
}
- /*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec int getCodec(
+ private synchronized Pair<Integer, Boolean> getCodec(
@NonNull BluetoothDevice device, @AudioService.BtProfile int profile) {
+
switch (profile) {
case BluetoothProfile.A2DP: {
+ boolean changed = mA2dpCodecConfig != null;
if (mA2dp == null) {
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ mA2dpCodecConfig = null;
+ return new Pair<>(AudioSystem.AUDIO_FORMAT_DEFAULT, changed);
}
BluetoothCodecStatus btCodecStatus = null;
try {
@@ -279,17 +289,24 @@
Log.e(TAG, "Exception while getting status of " + device, e);
}
if (btCodecStatus == null) {
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ mA2dpCodecConfig = null;
+ return new Pair<>(AudioSystem.AUDIO_FORMAT_DEFAULT, changed);
}
final BluetoothCodecConfig btCodecConfig = btCodecStatus.getCodecConfig();
if (btCodecConfig == null) {
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ mA2dpCodecConfig = null;
+ return new Pair<>(AudioSystem.AUDIO_FORMAT_DEFAULT, changed);
}
- return AudioSystem.bluetoothA2dpCodecToAudioFormat(btCodecConfig.getCodecType());
+ changed = !btCodecConfig.equals(mA2dpCodecConfig);
+ mA2dpCodecConfig = btCodecConfig;
+ return new Pair<>(AudioSystem.bluetoothA2dpCodecToAudioFormat(
+ btCodecConfig.getCodecType()), changed);
}
case BluetoothProfile.LE_AUDIO: {
+ boolean changed = mLeAudioCodecConfig != null;
if (mLeAudio == null) {
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ mLeAudioCodecConfig = null;
+ return new Pair<>(AudioSystem.AUDIO_FORMAT_DEFAULT, changed);
}
BluetoothLeAudioCodecStatus btLeCodecStatus = null;
int groupId = mLeAudio.getGroupId(device);
@@ -299,42 +316,54 @@
Log.e(TAG, "Exception while getting status of " + device, e);
}
if (btLeCodecStatus == null) {
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ mLeAudioCodecConfig = null;
+ return new Pair<>(AudioSystem.AUDIO_FORMAT_DEFAULT, changed);
}
BluetoothLeAudioCodecConfig btLeCodecConfig =
btLeCodecStatus.getOutputCodecConfig();
if (btLeCodecConfig == null) {
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ mLeAudioCodecConfig = null;
+ return new Pair<>(AudioSystem.AUDIO_FORMAT_DEFAULT, changed);
}
- return AudioSystem.bluetoothLeCodecToAudioFormat(btLeCodecConfig.getCodecType());
+ changed = !btLeCodecConfig.equals(mLeAudioCodecConfig);
+ mLeAudioCodecConfig = btLeCodecConfig;
+ return new Pair<>(AudioSystem.bluetoothLeCodecToAudioFormat(
+ btLeCodecConfig.getCodecType()), changed);
+ }
+ case BluetoothProfile.LE_AUDIO_BROADCAST: {
+ // We assume LC3 for LE Audio broadcast codec as there is no API to get the codec
+ // config on LE Broadcast profile proxy.
+ boolean changed = mLeAudioBroadcastCodec != AudioSystem.AUDIO_FORMAT_LC3;
+ mLeAudioBroadcastCodec = AudioSystem.AUDIO_FORMAT_LC3;
+ return new Pair<>(mLeAudioBroadcastCodec, changed);
}
default:
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ return new Pair<>(AudioSystem.AUDIO_FORMAT_DEFAULT, false);
}
}
- /*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec
- int getCodecWithFallback(
- @NonNull BluetoothDevice device, @AudioService.BtProfile int profile,
- boolean isLeOutput, @NonNull String source) {
+ /*package*/ synchronized Pair<Integer, Boolean>
+ getCodecWithFallback(@NonNull BluetoothDevice device,
+ @AudioService.BtProfile int profile,
+ boolean isLeOutput, @NonNull String source) {
// For profiles other than A2DP and LE Audio output, the audio codec format must be
// AUDIO_FORMAT_DEFAULT as native audio policy manager expects a specific audio format
// only if audio HW module selection based on format is supported for the device type.
if (!(profile == BluetoothProfile.A2DP
|| (isLeOutput && ((profile == BluetoothProfile.LE_AUDIO)
|| (profile == BluetoothProfile.LE_AUDIO_BROADCAST))))) {
- return AudioSystem.AUDIO_FORMAT_DEFAULT;
+ return new Pair<>(AudioSystem.AUDIO_FORMAT_DEFAULT, false);
}
- @AudioSystem.AudioFormatNativeEnumForBtCodec int codec =
+ Pair<Integer, Boolean> codecAndChanged =
getCodec(device, profile);
- if (codec == AudioSystem.AUDIO_FORMAT_DEFAULT) {
+ if (codecAndChanged.first == AudioSystem.AUDIO_FORMAT_DEFAULT) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"getCodec DEFAULT from " + source + " fallback to "
+ (profile == BluetoothProfile.A2DP ? "SBC" : "LC3")));
- return profile == BluetoothProfile.A2DP
- ? AudioSystem.AUDIO_FORMAT_SBC : AudioSystem.AUDIO_FORMAT_LC3;
+ return new Pair<>(profile == BluetoothProfile.A2DP
+ ? AudioSystem.AUDIO_FORMAT_SBC : AudioSystem.AUDIO_FORMAT_LC3, true);
}
- return codec;
+ return codecAndChanged;
}
// @GuardedBy("mDeviceBroker.mSetModeLock")
@@ -539,15 +568,19 @@
break;
case BluetoothProfile.A2DP:
mA2dp = null;
+ mA2dpCodecConfig = null;
break;
case BluetoothProfile.HEARING_AID:
mHearingAid = null;
break;
case BluetoothProfile.LE_AUDIO:
mLeAudio = null;
+ mLeAudioCodecConfig = null;
+ break;
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ mLeAudioBroadcastCodec = AudioSystem.AUDIO_FORMAT_DEFAULT;
break;
case BluetoothProfile.A2DP_SINK:
- case BluetoothProfile.LE_AUDIO_BROADCAST:
// nothing to do in BtHelper
break;
default:
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 67d3fe9..db83d4b 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -232,7 +232,9 @@
if (!mRunning) {
return false;
}
- if (!getSessionInfos().isEmpty() || mIsManagerScanning) {
+ boolean bindDueToManagerScan =
+ mIsManagerScanning && Flags.enablePreventionOfManagerScansWhenNoAppsScan();
+ if (!getSessionInfos().isEmpty() || bindDueToManagerScan) {
// We bind if any manager is scanning (regardless of whether an app is scanning) to give
// the opportunity for providers to publish routing sessions that were established
// directly between the app and the provider (typically via AndroidX MediaRouter). See
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java
index 82f9aad..d24afabe 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java
@@ -92,7 +92,7 @@
while (count > 0 && (type = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (type == XmlPullParser.START_TAG
&& parser.getName().equals(TAG_VALUE)) {
- values.add(parser.nextText().trim());
+ values.add(parser.nextText());
count--;
}
}
@@ -111,7 +111,7 @@
restrictions.putParcelableArray(key,
bundleList.toArray(new Bundle[bundleList.size()]));
} else {
- String value = parser.nextText().trim();
+ String value = parser.nextText();
if (ATTR_TYPE_BOOLEAN.equals(valType)) {
restrictions.putBoolean(key, Boolean.parseBoolean(value));
} else if (ATTR_TYPE_INTEGER.equals(valType)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b34092c..3dd7b54 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11509,10 +11509,17 @@
@Override
public void setApplicationRestrictions(ComponentName who, String callerPackage,
- String packageName, Bundle restrictions) {
+ String packageName, Bundle restrictions, boolean parent) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_APPLICATION_RESTRICTIONS);
+ // This check is eventually made in UMS, checking here to fail early.
+ String validationResult =
+ FrameworkParsingPackageUtils.validateName(packageName, false, false);
+ if (validationResult != null) {
+ throw new IllegalArgumentException("Invalid package name: " + validationResult);
+ }
+
if (isUnicornFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
@@ -11520,12 +11527,6 @@
caller.getPackageName(),
caller.getUserId()
);
- // This check is eventually made in UMS, checking here to fail early.
- String validationResult =
- FrameworkParsingPackageUtils.validateName(packageName, false, false);
- if (validationResult != null) {
- throw new IllegalArgumentException("Invalid package name: " + validationResult);
- }
if (restrictions == null || restrictions.isEmpty()) {
mDevicePolicyEngine.removeLocalPolicy(
@@ -11541,6 +11542,57 @@
}
setBackwardsCompatibleAppRestrictions(
caller, packageName, restrictions, caller.getUserHandle());
+ } else if (Flags.dmrhCanSetAppRestriction()) {
+ final boolean isRoleHolder;
+ if (who != null) {
+ // DO or PO
+ Preconditions.checkCallAuthorization(
+ (isProfileOwner(caller) || isDefaultDeviceOwner(caller)));
+ Preconditions.checkCallAuthorization(!parent,
+ "DO or PO cannot call this on parent");
+ // Caller has opted to be treated as DPC (by passing a non-null who), so don't
+ // consider it as the DMRH, even if the caller is both the DPC and the DMRH.
+ isRoleHolder = false;
+ } else {
+ // Delegates, or the DMRH. Only DMRH can call this on COPE parent
+ isRoleHolder = isCallerDevicePolicyManagementRoleHolder(caller);
+ if (parent) {
+ Preconditions.checkCallAuthorization(isRoleHolder);
+ Preconditions.checkState(isOrganizationOwnedDeviceWithManagedProfile(),
+ "Role Holder can only operate parent app restriction on COPE devices");
+ } else {
+ Preconditions.checkCallAuthorization(isRoleHolder
+ || isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS));
+ }
+ }
+ // DMRH caller uses policy engine, others still use legacy code path
+ if (isRoleHolder) {
+ EnforcingAdmin enforcingAdmin = getEnforcingAdminForCaller(/* who */ null,
+ caller.getPackageName());
+ int affectedUserId = parent
+ ? getProfileParentId(caller.getUserId()) : caller.getUserId();
+ if (restrictions == null || restrictions.isEmpty()) {
+ mDevicePolicyEngine.removeLocalPolicy(
+ PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
+ enforcingAdmin,
+ affectedUserId);
+ } else {
+ mDevicePolicyEngine.setLocalPolicy(
+ PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
+ enforcingAdmin,
+ new BundlePolicyValue(restrictions),
+ affectedUserId);
+ }
+ Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+ changeIntent.setPackage(packageName);
+ changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(changeIntent, UserHandle.of(affectedUserId));
+ } else {
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ mUserManager.setApplicationRestrictions(packageName, restrictions,
+ caller.getUserHandle());
+ });
+ }
} else {
Preconditions.checkCallAuthorization((caller.hasAdminComponent()
&& (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
@@ -12872,7 +12924,7 @@
@Override
public Bundle getApplicationRestrictions(ComponentName who, String callerPackage,
- String packageName) {
+ String packageName, boolean parent) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
if (isUnicornFlagEnabled()) {
@@ -12891,6 +12943,50 @@
return Bundle.EMPTY;
}
return policies.get(enforcingAdmin).getValue();
+ } else if (Flags.dmrhCanSetAppRestriction()) {
+ final boolean isRoleHolder;
+ if (who != null) {
+ // Caller is DO or PO. They cannot call this on parent
+ Preconditions.checkCallAuthorization(!parent
+ && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)));
+ // Caller has opted to be treated as DPC (by passing a non-null who), so don't
+ // consider it as the DMRH, even if the caller is both the DPC and the DMRH.
+ isRoleHolder = false;
+ } else {
+ // Caller is delegates or the DMRH. Only DMRH can call this on parent
+ isRoleHolder = isCallerDevicePolicyManagementRoleHolder(caller);
+ if (parent) {
+ Preconditions.checkCallAuthorization(isRoleHolder);
+ Preconditions.checkState(isOrganizationOwnedDeviceWithManagedProfile(),
+ "Role Holder can only operate parent app restriction on COPE devices");
+ } else {
+ Preconditions.checkCallAuthorization(isRoleHolder
+ || isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS));
+ }
+ }
+ if (isRoleHolder) {
+ EnforcingAdmin enforcingAdmin = getEnforcingAdminForCaller(/* who */ null,
+ caller.getPackageName());
+ int affectedUserId = parent
+ ? getProfileParentId(caller.getUserId()) : caller.getUserId();
+ LinkedHashMap<EnforcingAdmin, PolicyValue<Bundle>> policies =
+ mDevicePolicyEngine.getLocalPoliciesSetByAdmins(
+ PolicyDefinition.APPLICATION_RESTRICTIONS(packageName),
+ affectedUserId);
+ if (!policies.containsKey(enforcingAdmin)) {
+ return Bundle.EMPTY;
+ }
+ return policies.get(enforcingAdmin).getValue();
+ } else {
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ Bundle bundle = mUserManager.getApplicationRestrictions(packageName,
+ caller.getUserHandle());
+ // if no restrictions were saved, mUserManager.getApplicationRestrictions
+ // returns null, but DPM method should return an empty Bundle as per JavaDoc
+ return bundle != null ? bundle : Bundle.EMPTY;
+ });
+ }
+
} else {
Preconditions.checkCallAuthorization((caller.hasAdminComponent()
&& (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
@@ -15811,19 +15907,16 @@
for (EnforcingAdmin admin : policies.keySet()) {
restrictions.add(policies.get(admin).getValue());
}
- if (!restrictions.isEmpty()) {
- return restrictions;
- }
return mInjector.binderWithCleanCallingIdentity(() -> {
- // Could be a device that has a DPC that hasn't migrated yet, so just return any
+ // Could be a device that has a DPC that hasn't migrated yet, so also return any
// restrictions saved in userManager.
Bundle bundle = mUserManager.getApplicationRestrictions(
packageName, UserHandle.of(userId));
- if (bundle == null || bundle.isEmpty()) {
- return new ArrayList<>();
+ if (bundle != null && !bundle.isEmpty()) {
+ restrictions.add(bundle);
}
- return List.of(bundle);
+ return restrictions;
});
}
diff --git a/services/permission/TEST_MAPPING b/services/permission/TEST_MAPPING
index 00bfcd3..4de4a56 100644
--- a/services/permission/TEST_MAPPING
+++ b/services/permission/TEST_MAPPING
@@ -103,6 +103,28 @@
"include-filter": "android.permission.cts.PermissionMaxSdkVersionTest"
}
]
+ },
+ {
+ "name": "CtsVirtualDevicesAudioTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "include-filter": "android.virtualdevice.cts.audio.VirtualAudioPermissionTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsVirtualDevicesAppLaunchTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "include-filter": "android.virtualdevice.cts.applaunch.VirtualDevicePermissionTest"
+ }
+ ]
}
],
"imports": [
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
index 30333da..682adbc 100644
--- a/tools/hoststubgen/hoststubgen/Android.bp
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -82,13 +82,30 @@
jarjar_rules: "jarjar-rules.txt",
}
-// Host-side stub generator tool.
-java_binary_host {
- name: "hoststubgen",
- main_class: "com.android.hoststubgen.Main",
+// For sharing the code with other tools
+java_library_host {
+ name: "hoststubgen-lib",
+ defaults: ["ravenwood-internal-only-visibility-java"],
srcs: ["src/**/*.kt"],
static_libs: [
"hoststubgen-helper-runtime",
+ ],
+ libs: [
+ "junit",
+ "ow2-asm",
+ "ow2-asm-analysis",
+ "ow2-asm-commons",
+ "ow2-asm-tree",
+ "ow2-asm-util",
+ ],
+}
+
+// Host-side stub generator tool.
+java_binary_host {
+ name: "hoststubgen",
+ main_class: "com.android.hoststubgen.HostStubGenMain",
+ static_libs: [
+ "hoststubgen-lib",
"junit",
"ow2-asm",
"ow2-asm-analysis",
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 1089f82..803dc28 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -32,7 +32,6 @@
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
-import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.util.CheckClassAdapter
import java.io.BufferedInputStream
import java.io.FileOutputStream
@@ -52,7 +51,7 @@
val stats = HostStubGenStats()
// Load all classes.
- val allClasses = loadClassStructures(options.inJar.get)
+ val allClasses = ClassNodes.loadClassStructures(options.inJar.get)
// Dump the classes, if specified.
options.inputJarDumpFile.ifSet {
@@ -92,55 +91,6 @@
}
/**
- * Load all the classes, without code.
- */
- private fun loadClassStructures(inJar: String): ClassNodes {
- log.i("Reading class structure from $inJar ...")
- val start = System.currentTimeMillis()
-
- val allClasses = ClassNodes()
-
- log.withIndent {
- ZipFile(inJar).use { inZip ->
- val inEntries = inZip.entries()
-
- while (inEntries.hasMoreElements()) {
- val entry = inEntries.nextElement()
-
- BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
- if (entry.name.endsWith(".class")) {
- val cr = ClassReader(bis)
- val cn = ClassNode()
- cr.accept(cn, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG
- or ClassReader.SKIP_FRAMES)
- if (!allClasses.addClass(cn)) {
- log.w("Duplicate class found: ${cn.name}")
- }
- } else if (entry.name.endsWith(".dex")) {
- // Seems like it's an ART jar file. We can't process it.
- // It's a fatal error.
- throw InvalidJarFileException(
- "$inJar is not a desktop jar file. It contains a *.dex file.")
- } else {
- // Unknown file type. Skip.
- while (bis.available() > 0) {
- bis.skip((1024 * 1024).toLong())
- }
- }
- }
- }
- }
- }
- if (allClasses.size == 0) {
- log.w("$inJar contains no *.class files.")
- }
-
- val end = System.currentTimeMillis()
- log.i("Done reading class structure in %.1f second(s).", (end - start) / 1000.0)
- return allClasses
- }
-
- /**
* Build the filter, which decides what classes/methods/fields should be put in stub or impl
* jars, and "how". (e.g. with substitution?)
*/
@@ -229,7 +179,7 @@
val intersectingJars = mutableMapOf<String, ClassNodes>()
filenames.forEach { filename ->
- intersectingJars[filename] = loadClassStructures(filename)
+ intersectingJars[filename] = ClassNodes.loadClassStructures(filename)
}
return intersectingJars
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
similarity index 86%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt
rename to tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
index 4882c00..45e7e30 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
@@ -13,18 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@file:JvmName("Main")
+@file:JvmName("HostStubGenMain")
package com.android.hoststubgen
import java.io.PrintWriter
-const val COMMAND_NAME = "HostStubGen"
-
/**
* Entry point.
*/
fun main(args: Array<String>) {
+ executableName = "HostStubGen"
+
var success = false
var clanupOnError = false
@@ -33,7 +33,7 @@
val options = HostStubGenOptions.parseArgs(args)
clanupOnError = options.cleanUpOnError.get
- log.v("HostStubGen started")
+ log.v("$executableName started")
log.v("Options: $options")
// Run.
@@ -41,7 +41,7 @@
success = true
} catch (e: Throwable) {
- log.e("$COMMAND_NAME: Error: ${e.message}")
+ log.e("$executableName: Error: ${e.message}")
if (e !is UserErrorException) {
e.printStackTrace(PrintWriter(log.getWriter(LogLevel.Error)))
}
@@ -49,7 +49,7 @@
TODO("Remove output jars here")
}
} finally {
- log.i("$COMMAND_NAME finished")
+ log.i("$executableName finished")
log.flush()
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index 9f5d524..9ff798a 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -268,7 +268,7 @@
}
if (!ret.outStubJar.isSet && !ret.outImplJar.isSet) {
log.w("Neither --out-stub-jar nor --out-impl-jar is set." +
- " $COMMAND_NAME will not generate jar files.")
+ " $executableName will not generate jar files.")
}
if (ret.enableNonStubMethodCallDetection.get) {
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
index 937e56c..aa63d8d9 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
@@ -16,6 +16,11 @@
package com.android.hoststubgen
/**
+ * Name of this executable. Set it in the main method.
+ */
+var executableName = "[command name not set]"
+
+/**
* A regex that maches whitespate.
*/
val whitespaceRegex = """\s+""".toRegex()
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
index 0579c2b..83e122f 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
@@ -34,6 +34,9 @@
/** Descriptor of the class initializer method. */
val CLASS_INITIALIZER_DESC = "()V"
+/** Name of constructors. */
+val CTOR_NAME = "<init>"
+
/**
* Find any of [anyAnnotations] from the list of visible / invisible annotations.
*/
@@ -135,10 +138,10 @@
// Note, long and double will consume two local variable spaces, so the extra `i++`.
when (type) {
Type.VOID_TYPE -> throw HostStubGenInternalException("VOID_TYPE not expected")
- Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.SHORT_TYPE, Type.CHAR_TYPE
+ Type.BOOLEAN_TYPE, Type.CHAR_TYPE, Type.BYTE_TYPE, Type.SHORT_TYPE, Type.INT_TYPE
-> writer.visitVarInsn(Opcodes.ILOAD, i)
- Type.LONG_TYPE -> writer.visitVarInsn(Opcodes.LLOAD, i++)
Type.FLOAT_TYPE -> writer.visitVarInsn(Opcodes.FLOAD, i)
+ Type.LONG_TYPE -> writer.visitVarInsn(Opcodes.LLOAD, i++)
Type.DOUBLE_TYPE -> writer.visitVarInsn(Opcodes.DLOAD, i++)
else -> writer.visitVarInsn(Opcodes.ALOAD, i)
}
@@ -154,10 +157,10 @@
// See https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions
when (type) {
Type.VOID_TYPE -> writer.visitInsn(Opcodes.RETURN)
- Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.SHORT_TYPE, Type.CHAR_TYPE
+ Type.BOOLEAN_TYPE, Type.CHAR_TYPE, Type.BYTE_TYPE, Type.SHORT_TYPE, Type.INT_TYPE
-> writer.visitInsn(Opcodes.IRETURN)
- Type.LONG_TYPE -> writer.visitInsn(Opcodes.LRETURN)
Type.FLOAT_TYPE -> writer.visitInsn(Opcodes.FRETURN)
+ Type.LONG_TYPE -> writer.visitInsn(Opcodes.LRETURN)
Type.DOUBLE_TYPE -> writer.visitInsn(Opcodes.DRETURN)
else -> writer.visitInsn(Opcodes.ARETURN)
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
index bc34ef0..92906a7 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
@@ -16,13 +16,18 @@
package com.android.hoststubgen.asm
import com.android.hoststubgen.ClassParseException
+import com.android.hoststubgen.InvalidJarFileException
+import com.android.hoststubgen.log
+import org.objectweb.asm.ClassReader
import org.objectweb.asm.tree.AnnotationNode
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.FieldNode
import org.objectweb.asm.tree.MethodNode
import org.objectweb.asm.tree.TypeAnnotationNode
+import java.io.BufferedInputStream
import java.io.PrintWriter
import java.util.Arrays
+import java.util.zip.ZipFile
/**
* Stores all classes loaded from a jar file, in a form of [ClassNode]
@@ -62,8 +67,8 @@
/** Find a field, which may not exist. */
fun findField(
- className: String,
- fieldName: String,
+ className: String,
+ fieldName: String,
): FieldNode? {
return findClass(className)?.fields?.firstOrNull { it.name == fieldName }?.let { fn ->
return fn
@@ -72,14 +77,14 @@
/** Find a method, which may not exist. */
fun findMethod(
- className: String,
- methodName: String,
- descriptor: String,
+ className: String,
+ methodName: String,
+ descriptor: String,
): MethodNode? {
return findClass(className)?.methods
- ?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn ->
- return mn
- }
+ ?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn ->
+ return mn
+ }
}
/** @return true if a class has a class initializer. */
@@ -106,26 +111,33 @@
private fun dumpClass(pw: PrintWriter, cn: ClassNode) {
pw.printf("Class: %s [access: %x]\n", cn.name, cn.access)
- dumpAnnotations(pw, " ",
- cn.visibleTypeAnnotations, cn.invisibleTypeAnnotations,
- cn.visibleAnnotations, cn.invisibleAnnotations,
- )
+ dumpAnnotations(
+ pw, " ",
+ cn.visibleTypeAnnotations, cn.invisibleTypeAnnotations,
+ cn.visibleAnnotations, cn.invisibleAnnotations,
+ )
for (f in cn.fields ?: emptyList()) {
- pw.printf(" Field: %s [sig: %s] [desc: %s] [access: %x]\n",
- f.name, f.signature, f.desc, f.access)
- dumpAnnotations(pw, " ",
- f.visibleTypeAnnotations, f.invisibleTypeAnnotations,
- f.visibleAnnotations, f.invisibleAnnotations,
- )
+ pw.printf(
+ " Field: %s [sig: %s] [desc: %s] [access: %x]\n",
+ f.name, f.signature, f.desc, f.access
+ )
+ dumpAnnotations(
+ pw, " ",
+ f.visibleTypeAnnotations, f.invisibleTypeAnnotations,
+ f.visibleAnnotations, f.invisibleAnnotations,
+ )
}
for (m in cn.methods ?: emptyList()) {
- pw.printf(" Method: %s [sig: %s] [desc: %s] [access: %x]\n",
- m.name, m.signature, m.desc, m.access)
- dumpAnnotations(pw, " ",
- m.visibleTypeAnnotations, m.invisibleTypeAnnotations,
- m.visibleAnnotations, m.invisibleAnnotations,
- )
+ pw.printf(
+ " Method: %s [sig: %s] [desc: %s] [access: %x]\n",
+ m.name, m.signature, m.desc, m.access
+ )
+ dumpAnnotations(
+ pw, " ",
+ m.visibleTypeAnnotations, m.invisibleTypeAnnotations,
+ m.visibleAnnotations, m.invisibleAnnotations,
+ )
}
}
@@ -136,7 +148,7 @@
invisibleTypeAnnotations: List<TypeAnnotationNode>?,
visibleAnnotations: List<AnnotationNode>?,
invisibleAnnotations: List<AnnotationNode>?,
- ) {
+ ) {
for (an in visibleTypeAnnotations ?: emptyList()) {
pw.printf("%sTypeAnnotation(vis): %s\n", prefix, an.desc)
}
@@ -166,4 +178,55 @@
}
}
}
+
+ companion object {
+ /**
+ * Load all the classes, without code.
+ */
+ fun loadClassStructures(inJar: String): ClassNodes {
+ log.i("Reading class structure from $inJar ...")
+ val start = System.currentTimeMillis()
+
+ val allClasses = ClassNodes()
+
+ log.withIndent {
+ ZipFile(inJar).use { inZip ->
+ val inEntries = inZip.entries()
+
+ while (inEntries.hasMoreElements()) {
+ val entry = inEntries.nextElement()
+
+ BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
+ if (entry.name.endsWith(".class")) {
+ val cr = ClassReader(bis)
+ val cn = ClassNode()
+ cr.accept(cn, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG
+ or ClassReader.SKIP_FRAMES)
+ if (!allClasses.addClass(cn)) {
+ log.w("Duplicate class found: ${cn.name}")
+ }
+ } else if (entry.name.endsWith(".dex")) {
+ // Seems like it's an ART jar file. We can't process it.
+ // It's a fatal error.
+ throw InvalidJarFileException(
+ "$inJar is not a desktop jar file. It contains a *.dex file.")
+ } else {
+ // Unknown file type. Skip.
+ while (bis.available() > 0) {
+ bis.skip((1024 * 1024).toLong())
+ }
+ }
+ }
+ }
+ }
+ }
+ if (allClasses.size == 0) {
+ log.w("$inJar contains no *.class files.")
+ }
+
+ val end = System.currentTimeMillis()
+ log.i("Done reading class structure in %.1f second(s).", (end - start) / 1000.0)
+ return allClasses
+ }
+ }
}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
index 78b13fd..5a26fc6 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
@@ -19,14 +19,14 @@
import com.android.hoststubgen.HostStubGenInternalException
import com.android.hoststubgen.asm.CLASS_INITIALIZER_DESC
import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME
-import com.android.hoststubgen.asm.isAnonymousInnerClass
-import com.android.hoststubgen.log
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.isAnnotation
+import com.android.hoststubgen.asm.isAnonymousInnerClass
import com.android.hoststubgen.asm.isAutoGeneratedEnumMember
import com.android.hoststubgen.asm.isEnum
import com.android.hoststubgen.asm.isSynthetic
import com.android.hoststubgen.asm.isVisibilityPrivateOrPackagePrivate
+import com.android.hoststubgen.log
import org.objectweb.asm.tree.ClassNode
/**
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index f70a17d..fa8fe6c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -1833,7 +1833,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 10, attributes: 2
+ interfaces: 0, fields: 1, methods: 11, attributes: 2
int value;
descriptor: I
flags: (0x0000)
@@ -1938,6 +1938,10 @@
x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
x: athrow
LineNumberTable:
+
+ public static native byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
}
SourceFile: "TinyFrameworkNative.java"
RuntimeInvisibleAnnotations:
@@ -1955,7 +1959,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
super_class: #x // java/lang/Object
- interfaces: 0, fields: 0, methods: 4, attributes: 2
+ interfaces: 0, fields: 0, methods: 5, attributes: 2
public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
@@ -2013,6 +2017,22 @@
Start Length Slot Name Signature
0 7 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
0 7 1 arg I
+
+ public static byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: i2b
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 arg1 B
+ 0 5 1 arg2 B
}
SourceFile: "TinyFrameworkNative_host.java"
RuntimeInvisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index 37de857..c605f76 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -1554,7 +1554,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 9, attributes: 3
+ interfaces: 0, fields: 1, methods: 10, attributes: 3
int value;
descriptor: I
flags: (0x0000)
@@ -1686,6 +1686,15 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static native byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
}
SourceFile: "TinyFrameworkNative.java"
RuntimeVisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index c9c607c..11d5939 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -2236,7 +2236,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 10, attributes: 3
+ interfaces: 0, fields: 1, methods: 11, attributes: 3
int value;
descriptor: I
flags: (0x0000)
@@ -2435,6 +2435,23 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_0
+ x: iload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeBytePlus:(BB)B
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
}
SourceFile: "TinyFrameworkNative.java"
RuntimeVisibleAnnotations:
@@ -2457,7 +2474,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
super_class: #x // java/lang/Object
- interfaces: 0, fields: 0, methods: 4, attributes: 3
+ interfaces: 0, fields: 0, methods: 5, attributes: 3
public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
@@ -2551,6 +2568,31 @@
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String nativeBytePlus
+ x: ldc #x // String (BB)B
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: i2b
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 15 5 0 arg1 B
+ 15 5 1 arg2 B
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
}
SourceFile: "TinyFrameworkNative_host.java"
RuntimeVisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index 37de857..c605f76 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -1554,7 +1554,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 9, attributes: 3
+ interfaces: 0, fields: 1, methods: 10, attributes: 3
int value;
descriptor: I
flags: (0x0000)
@@ -1686,6 +1686,15 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static native byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
}
SourceFile: "TinyFrameworkNative.java"
RuntimeVisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index a57907d..088bc80 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -2743,7 +2743,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 11, attributes: 3
+ interfaces: 0, fields: 1, methods: 12, attributes: 3
int value;
descriptor: I
flags: (0x0000)
@@ -3002,6 +3002,28 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String nativeBytePlus
+ x: ldc #x // String (BB)B
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iload_1
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeBytePlus:(BB)B
+ x: ireturn
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
}
SourceFile: "TinyFrameworkNative.java"
RuntimeVisibleAnnotations:
@@ -3024,7 +3046,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
super_class: #x // java/lang/Object
- interfaces: 0, fields: 0, methods: 5, attributes: 3
+ interfaces: 0, fields: 0, methods: 6, attributes: 3
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3148,6 +3170,36 @@
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static byte nativeBytePlus(byte, byte);
+ descriptor: (BB)B
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String nativeBytePlus
+ x: ldc #x // String (BB)B
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String nativeBytePlus
+ x: ldc #x // String (BB)B
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iload_0
+ x: iload_1
+ x: iadd
+ x: i2b
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 26 5 0 arg1 B
+ 26 5 1 arg2 B
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
}
SourceFile: "TinyFrameworkNative_host.java"
RuntimeVisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
index 5a5e22d..09ee183 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
@@ -52,4 +52,6 @@
public static void nativeStillNotSupported_should_be_like_this() {
throw new RuntimeException();
}
+
+ public static native byte nativeBytePlus(byte arg1, byte arg2);
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
index 749ebaa..b23c216 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
@@ -34,4 +34,8 @@
public static int nativeNonStaticAddToValue(TinyFrameworkNative source, int arg) {
return source.value + arg;
}
+
+ public static byte nativeBytePlus(byte arg1, byte arg2) {
+ return (byte) (arg1 + arg2);
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
index ba17c75..762180d 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -154,13 +154,22 @@
}
@Test
+ public void testNativeSubstitutionLong() {
+ assertThat(TinyFrameworkNative.nativeLongPlus(1L, 2L)).isEqualTo(3L);
+ }
+
+ @Test
+ public void testNativeSubstitutionByte() {
+ assertThat(TinyFrameworkNative.nativeBytePlus((byte) 3, (byte) 4)).isEqualTo(7);
+ }
+
+ @Test
public void testNativeSubstitutionClass_nonStatic() {
TinyFrameworkNative instance = new TinyFrameworkNative();
instance.setValue(5);
assertThat(instance.nativeNonStaticAddToValue(3)).isEqualTo(8);
}
-
@Test
public void testSubstituteNativeWithThrow() throws Exception {
// We can't use TinyFrameworkNative.nativeStillNotSupported() directly in this class,