diff options
29 files changed, 478 insertions, 319 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java b/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java index 8a5d09404ebb..ae86afbd8380 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java @@ -123,21 +123,21 @@ class JobNotificationCoordinator { if (oldDetails == null) { if (jobStatus.startedAsUserInitiatedJob) { Counter.logIncrementWithUid( - "job_scheduler.value_cntr_w_uid_initial_setNotification_call_required", + "job_scheduler.value_cntr_w_uid_initial_set_notification_call_required", jobStatus.getUid()); } else { Counter.logIncrementWithUid( - "job_scheduler.value_cntr_w_uid_initial_setNotification_call_optional", + "job_scheduler.value_cntr_w_uid_initial_set_notification_call_optional", jobStatus.getUid()); } } else { if (jobStatus.startedAsUserInitiatedJob) { Counter.logIncrementWithUid( - "job_scheduler.value_cntr_w_uid_subsequent_setNotification_call_required", + "job_scheduler.value_cntr_w_uid_subsequent_set_notification_call_required", jobStatus.getUid()); } else { Counter.logIncrementWithUid( - "job_scheduler.value_cntr_w_uid_subsequent_setNotification_call_optional", + "job_scheduler.value_cntr_w_uid_subsequent_set_notification_call_optional", jobStatus.getUid()); } if (oldDetails.notificationId != notificationId) { @@ -145,7 +145,7 @@ class JobNotificationCoordinator { removeNotificationAssociation(hostingContext, JobParameters.STOP_REASON_UNDEFINED, jobStatus); Counter.logIncrementWithUid( - "job_scheduler.value_cntr_w_uid_setNotification_changed_notification_ids", + "job_scheduler.value_cntr_w_uid_set_notification_changed_notification_ids", jobStatus.getUid()); } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 0b08b6faf971..5f795b6fedd9 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -1331,7 +1331,7 @@ public final class JobServiceContext implements ServiceConnection { // FINISHED/NO-RETRY. onSlowAppResponseLocked(/* reschedule */ false, /* updateStopReasons */ true, /* texCounterMetricId */ - "job_scheduler.value_cntr_w_uid_slow_app_response_onStartJob", + "job_scheduler.value_cntr_w_uid_slow_app_response_on_start_job", /* debugReason */ "timed out while starting", /* anrMessage */ "No response to onStartJob", CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES, @@ -1343,7 +1343,7 @@ public final class JobServiceContext implements ServiceConnection { // other reason. onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ false, /* texCounterMetricId */ - "job_scheduler.value_cntr_w_uid_slow_app_response_onStopJob", + "job_scheduler.value_cntr_w_uid_slow_app_response_on_stop_job", /* debugReason */ "timed out while stopping", /* anrMessage */ "No response to onStopJob", CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES, @@ -1400,7 +1400,7 @@ public final class JobServiceContext implements ServiceConnection { } else if (mAwaitingNotification) { onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ true, /* texCounterMetricId */ - "job_scheduler.value_cntr_w_uid_slow_app_response_setNotification", + "job_scheduler.value_cntr_w_uid_slow_app_response_set_notification", /* debugReason */ "timed out while stopping", /* anrMessage */ "required notification not provided", /* triggerAnr */ true); diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 57935e3bd5b1..70e924a2acfe 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -2933,62 +2933,21 @@ public class WallpaperManager { } } - if (!isComponentExist(context, cn)) { - cn = null; - } - - return cn; - } - - /** - * Return {@link ComponentName} of the CMF default wallpaper, or - * {@link #getDefaultWallpaperComponent(Context)} if none is defined. - * - * @hide - */ - public static ComponentName getCmfDefaultWallpaperComponent(Context context) { - ComponentName cn = null; - String[] cmfWallpaperMap = context.getResources().getStringArray( - com.android.internal.R.array.cmf_default_wallpaper_component); - if (cmfWallpaperMap == null || cmfWallpaperMap.length == 0) { - Log.d(TAG, "No CMF wallpaper config"); - return getDefaultWallpaperComponent(context); - } - - for (String entry : cmfWallpaperMap) { - String[] cmfWallpaper; - if (!TextUtils.isEmpty(entry)) { - cmfWallpaper = entry.split(","); - if (cmfWallpaper != null && cmfWallpaper.length == 2 && VALUE_CMF_COLOR.equals( - cmfWallpaper[0]) && !TextUtils.isEmpty(cmfWallpaper[1])) { - cn = ComponentName.unflattenFromString(cmfWallpaper[1]); - break; - } + // Check if the package exists + if (cn != null) { + try { + final PackageManager packageManager = context.getPackageManager(); + packageManager.getPackageInfo(cn.getPackageName(), + PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); + } catch (PackageManager.NameNotFoundException e) { + cn = null; } } - if (!isComponentExist(context, cn)) { - cn = null; - } - return cn; } - private static boolean isComponentExist(Context context, ComponentName cn) { - if (cn == null) { - return false; - } - try { - final PackageManager packageManager = context.getPackageManager(); - packageManager.getPackageInfo(cn.getPackageName(), - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); - } catch (PackageManager.NameNotFoundException e) { - return false; - } - return true; - } - /** * Register a callback for lock wallpaper observation. Only the OS may use this. * diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 1bbb7b4bd671..a28be4be24ad 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -5459,7 +5459,7 @@ public final class ViewRootImpl implements ViewParent, } private void updateRenderHdrSdrRatio() { - mRenderHdrSdrRatio = mDisplay.getHdrSdrRatio(); + mRenderHdrSdrRatio = Math.min(mDesiredHdrSdrRatio, mDisplay.getHdrSdrRatio()); mUpdateHdrSdrRatioInfo = true; } @@ -5487,22 +5487,14 @@ public final class ViewRootImpl implements ViewParent, mHdrSdrRatioChangedListener = null; } else { mHdrSdrRatioChangedListener = display -> { - setTargetHdrSdrRatio(display.getHdrSdrRatio()); + updateRenderHdrSdrRatio(); + invalidate(); }; mDisplay.registerHdrSdrRatioChangedListener(mExecutor, mHdrSdrRatioChangedListener); } } } - /** happylint */ - public void setTargetHdrSdrRatio(float ratio) { - if (mRenderHdrSdrRatio != ratio) { - mRenderHdrSdrRatio = ratio; - mUpdateHdrSdrRatioInfo = true; - invalidate(); - } - } - @Override public void requestChildFocus(View child, View focused) { if (DEBUG_INPUT_RESIZE) { diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 00f8db0d9264..ee8c0f83304e 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1817,16 +1817,6 @@ specified --> <string name="default_wallpaper_component" translatable="false">@null</string> - <!-- CMF colors to default wallpaper component map, the component with color matching the device - color will be the cmf default wallpapers. The default wallpaper will be default wallpaper - component if not specified. - - E.g. for SLV color, and com.android.example/com.android.example.SlVDefaultWallpaper - <item>SLV,com.android.example/com.android.example.SlVDefaultWallpaper</item> --> - <string-array name="cmf_default_wallpaper_component" translatable="false"> - <!-- Add packages here --> - </string-array> - <!-- By default a product has no distinct default lock wallpaper --> <item name="default_lock_wallpaper" type="drawable">@null</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a8518afd7d3d..dc4eafd2e00e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2116,7 +2116,6 @@ <java-symbol type="string" name="data_usage_rapid_body" /> <java-symbol type="string" name="data_usage_rapid_app_body" /> <java-symbol type="string" name="default_wallpaper_component" /> - <java-symbol type="array" name="cmf_default_wallpaper_component" /> <java-symbol type="string" name="device_storage_monitor_notification_channel" /> <java-symbol type="string" name="dlg_ok" /> <java-symbol type="string" name="dump_heap_notification" /> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java index d6e1a82a68ff..467e9c7a116b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java @@ -375,16 +375,15 @@ public class DisplayLayout { insetsState.getDisplayFrame(), WindowInsets.Type.navigationBars(), false /* ignoreVisibility */); - outInsets.set(insets.left, insets.top, insets.right, insets.bottom); int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation); int navBarSize = getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode); if (position == NAV_BAR_BOTTOM) { - outInsets.bottom = Math.max(outInsets.bottom , navBarSize); + outInsets.bottom = Math.max(insets.bottom , navBarSize); } else if (position == NAV_BAR_RIGHT) { - outInsets.right = Math.max(outInsets.right , navBarSize); + outInsets.right = Math.max(insets.right , navBarSize); } else if (position == NAV_BAR_LEFT) { - outInsets.left = Math.max(outInsets.left , navBarSize); + outInsets.left = Math.max(insets.left , navBarSize); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index 8723f9b0181d..66da1253be6f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -595,8 +595,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { cancel(mWillFinishToHome, true /* withScreenshots */, "display change"); return; } - // Don't consider order-only changes as changing apps. - if (!TransitionUtil.isOrderOnly(change)) { + // Don't consider order-only & non-leaf changes as changing apps. + if (!TransitionUtil.isOrderOnly(change) && isLeafTask) { hasChangingApp = true; } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt new file mode 100644 index 000000000000..f7ce87088040 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.flicker.pip + +import android.app.Instrumentation +import android.os.SystemClock +import android.platform.test.annotations.Presubmit +import android.tools.common.NavBar +import android.tools.common.Rotation +import android.tools.device.apphelpers.StandardAppHelper +import android.tools.device.flicker.junit.FlickerParametersRunnerFactory +import android.tools.device.flicker.legacy.FlickerBuilder +import android.tools.device.flicker.legacy.FlickerTest +import android.tools.device.flicker.legacy.FlickerTestFactory +import android.tools.device.helpers.WindowUtils +import android.tools.device.traces.parsers.toFlickerComponent +import androidx.test.filters.RequiresDevice +import androidx.test.uiautomator.By +import androidx.test.uiautomator.BySelector +import androidx.test.uiautomator.UiObject2 +import androidx.test.uiautomator.Until +import com.android.server.wm.flicker.helpers.SimpleAppHelper +import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME +import org.junit.Assume +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test entering pip from an app via auto-enter property when navigating to home from split screen. + * + * To run this test: `atest WMShellFlickerTests:AutoEnterPipOnGoToHomeTest` + * + * Actions: + * ``` + * Launch an app in full screen + * Select "Auto-enter PiP" radio button + * Open all apps and drag another app icon to enter split screen + * Press Home button or swipe up to go Home and put [pipApp] in pip mode + * ``` + * + * Notes: + * ``` + * 1. All assertions are inherited from [EnterPipTest] + * 2. Part of the test setup occurs automatically via + * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup + * ``` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: FlickerTest) : + AutoEnterPipOnGoToHomeTest(flicker) { + private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) + /** Second app used to enter split screen mode */ + protected val secondAppForSplitScreen = getSplitScreenApp(instrumentation) + fun getSplitScreenApp(instrumentation: Instrumentation): StandardAppHelper = + SimpleAppHelper( + instrumentation, + ActivityOptions.SplitScreen.Primary.LABEL, + ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent() + ) + + /** Defines the transition used to run the test */ + override val transition: FlickerBuilder.() -> Unit + get() = { + setup { + secondAppForSplitScreen.launchViaIntent(wmHelper) + pipApp.launchViaIntent(wmHelper) + tapl.goHome() + enterSplitScreen() + // wait until split screen is established + wmHelper + .StateSyncBuilder() + .withWindowSurfaceAppeared(pipApp) + .withWindowSurfaceAppeared(secondAppForSplitScreen) + .withSplitDividerVisible() + .waitForAndVerify() + pipApp.enableAutoEnterForPipActivity() + } + teardown { + // close gracefully so that onActivityUnpinned() can be called before force exit + pipApp.closePipWindow(wmHelper) + pipApp.exit(wmHelper) + secondAppForSplitScreen.exit(wmHelper) + } + transitions { tapl.goHome() } + } + + // TODO(b/285400227) merge the code in a common utility - this is copied from SplitScreenUtils + private val TIMEOUT_MS = 3_000L + private val overviewSnapshotSelector: BySelector + get() = By.res(LAUNCHER_UI_PACKAGE_NAME, "snapshot") + private fun enterSplitScreen() { + // Note: The initial split position in landscape is different between tablet and phone. + // In landscape, tablet will let the first app split to right side, and phone will + // split to left side. + if (tapl.isTablet) { + // TAPL's currentTask on tablet is sometimes not what we expected if the overview + // contains more than 3 task views. We need to use uiautomator directly to find the + // second task to split. + tapl.workspace.switchToOverview().overviewActions.clickSplit() + val snapshots = tapl.device.wait(Until.findObjects(overviewSnapshotSelector), + TIMEOUT_MS) + if (snapshots == null || snapshots.size < 1) { + error("Fail to find a overview snapshot to split.") + } + + // Find the second task in the upper right corner in split select mode by sorting + // 'left' in descending order and 'top' in ascending order. + snapshots.sortWith { t1: UiObject2, t2: UiObject2 -> + t2.getVisibleBounds().left - t1.getVisibleBounds().left + } + snapshots.sortWith { t1: UiObject2, t2: UiObject2 -> + t1.getVisibleBounds().top - t2.getVisibleBounds().top + } + snapshots[0].click() + } else { + tapl.workspace + .switchToOverview() + .currentTask + .tapMenu() + .tapSplitMenuItem() + .currentTask + .open() + } + SystemClock.sleep(TIMEOUT_MS) + } + + @Presubmit + @Test + override fun pipOverlayLayerAppearThenDisappear() { + // when entering from split screen we use alpha animation, without overlay + } + + @Presubmit + @Test + override fun pipLayerOrOverlayRemainInsideVisibleBounds() { + // when entering from split screen we use alpha animation, without overlay + } + + @Presubmit + @Test + override fun pipLayerReduces() { + // when entering from split screen we use alpha animation, so there is no size change + Assume.assumeFalse(flicker.scenario.isGesturalNavigation) + super.pipLayerReduces() + } + + @Presubmit + @Test + override fun pipAppLayerAlwaysVisible() { + // pip layer in gesture nav will disappear during transition with alpha animation + Assume.assumeFalse(flicker.scenario.isGesturalNavigation) + super.pipAppLayerAlwaysVisible() + } + + @Presubmit + @Test + override fun pipWindowRemainInsideVisibleBounds() { + if (tapl.isTablet) { + flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) } + } else { + // on phones home does not rotate in landscape, PiP enters back to portrait + // orientation so use display bounds from that orientation for assertion + flicker.assertWmVisibleRegion(pipApp) { coversAtMost(portraitDisplayBounds) } + } + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTest> { + return FlickerTestFactory.nonRotationTests( + // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. + supportedNavigationModes = listOf(NavBar.MODE_GESTURAL) + ) + } + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt index ef7bedf49a92..b95732e43357 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt @@ -53,7 +53,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiButtonTest(flicker) { +open class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipViaAppUiButtonTest(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt index 95121def07bc..cdbdb85a9195 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt @@ -62,7 +62,7 @@ abstract class EnterPipTransition(flicker: FlickerTest) : PipTransition(flicker) */ @Presubmit @Test - fun pipWindowRemainInsideVisibleBounds() { + open fun pipWindowRemainInsideVisibleBounds() { flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index 3fcb7f398185..ffc0479f01c3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -116,10 +116,7 @@ public class InfoMediaManager extends MediaManager { && !TextUtils.isEmpty(mPackageName)) { RouteListingPreference routeListingPreference = mRouterManager.getRouteListingPreference(mPackageName); - if (routeListingPreference != null) { - Api34Impl.onRouteListingPreferenceUpdated(null, routeListingPreference, - mPreferenceItemMap); - } + Api34Impl.onRouteListingPreferenceUpdated(routeListingPreference, mPreferenceItemMap); } refreshDevices(); } @@ -631,7 +628,7 @@ public class InfoMediaManager extends MediaManager { } /** - * Ignore callback here since we'll also receive {@link onRequestFailed} with reason code. + * Ignore callback here since we'll also receive {@link #onRequestFailed} with reason code. */ @Override public void onTransferFailed(RoutingSessionInfo session, MediaRoute2Info route) { @@ -656,9 +653,9 @@ public class InfoMediaManager extends MediaManager { public void onRouteListingPreferenceUpdated( String packageName, RouteListingPreference routeListingPreference) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - Api34Impl.onRouteListingPreferenceUpdated(packageName, routeListingPreference, - mPreferenceItemMap); + if (TextUtils.equals(mPackageName, packageName)) { + Api34Impl.onRouteListingPreferenceUpdated( + routeListingPreference, mPreferenceItemMap); refreshDevices(); } } @@ -746,7 +743,6 @@ public class InfoMediaManager extends MediaManager { @DoNotInline static void onRouteListingPreferenceUpdated( - String packageName, RouteListingPreference routeListingPreference, Map<String, RouteListingPreference.Item> preferenceItemMap) { preferenceItemMap.clear(); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java index aa5f3df1b750..39780f3a96ed 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java @@ -73,6 +73,7 @@ import java.util.Set; public class InfoMediaManagerTest { private static final String TEST_PACKAGE_NAME = "com.test.packagename"; + private static final String TEST_PACKAGE_NAME_2 = "com.test.packagename2"; private static final String TEST_ID = "test_id"; private static final String TEST_ID_1 = "test_id_1"; private static final String TEST_ID_2 = "test_id_2"; @@ -308,7 +309,54 @@ public class InfoMediaManagerTest { } @Test - public void onRouteChanged_getAvailableRoutesWithPrefernceListExit_ordersRoutes() { + public void onRouteChanged_getAvailableRoutesWithPreferenceListExit_ordersRoutes() { + RouteListingPreference routeListingPreference = setUpPreferenceList(TEST_PACKAGE_NAME); + setUpSelectedRoutes(TEST_PACKAGE_NAME); + + final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>(); + final RoutingSessionInfo sessionInfo = mock(RoutingSessionInfo.class); + routingSessionInfos.add(sessionInfo); + + when(mRouterManager.getRoutingSessions(TEST_PACKAGE_NAME)).thenReturn(routingSessionInfos); + when(sessionInfo.getSelectedRoutes()).thenReturn(ImmutableList.of(TEST_ID)); + + setAvailableRoutesList(TEST_PACKAGE_NAME); + + mInfoMediaManager.mRouterManager = mRouterManager; + mInfoMediaManager.mMediaRouterCallback.onRouteListingPreferenceUpdated(TEST_PACKAGE_NAME, + routeListingPreference); + mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated(); + + assertThat(mInfoMediaManager.mMediaDevices).hasSize(3); + assertThat(mInfoMediaManager.mMediaDevices.get(0).getId()).isEqualTo(TEST_ID); + assertThat(mInfoMediaManager.mMediaDevices.get(1).getId()).isEqualTo(TEST_ID_4); + assertThat(mInfoMediaManager.mMediaDevices.get(1).isSuggestedDevice()).isTrue(); + assertThat(mInfoMediaManager.mMediaDevices.get(2).getId()).isEqualTo(TEST_ID_3); + } + + @Test + public void onRouteChanged_preferenceListUpdateWithDifferentPkg_notOrdersRoutes() { + RouteListingPreference routeListingPreference = setUpPreferenceList(TEST_PACKAGE_NAME_2); + setUpSelectedRoutes(TEST_PACKAGE_NAME); + + final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>(); + final RoutingSessionInfo sessionInfo = mock(RoutingSessionInfo.class); + routingSessionInfos.add(sessionInfo); + + when(mRouterManager.getRoutingSessions(TEST_PACKAGE_NAME)).thenReturn(routingSessionInfos); + when(sessionInfo.getSelectedRoutes()).thenReturn(ImmutableList.of(TEST_ID)); + + setAvailableRoutesList(TEST_PACKAGE_NAME); + mInfoMediaManager.mRouterManager = mRouterManager; + mInfoMediaManager.mMediaRouterCallback.onRouteListingPreferenceUpdated(TEST_PACKAGE_NAME_2, + routeListingPreference); + mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated(); + + assertThat(mInfoMediaManager.mMediaDevices).hasSize(1); + assertThat(mInfoMediaManager.mMediaDevices.get(0).getId()).isEqualTo(TEST_ID); + } + + private RouteListingPreference setUpPreferenceList(String packageName) { ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.UPSIDE_DOWN_CAKE); final List<RouteListingPreference.Item> preferenceItemList = new ArrayList<>(); @@ -324,57 +372,40 @@ public class InfoMediaManagerTest { RouteListingPreference routeListingPreference = new RouteListingPreference.Builder().setItems( preferenceItemList).setUseSystemOrdering(false).build(); - when(mRouterManager.getRouteListingPreference(TEST_PACKAGE_NAME)) + when(mRouterManager.getRouteListingPreference(packageName)) .thenReturn(routeListingPreference); + return routeListingPreference; + } + private void setUpSelectedRoutes(String packageName) { final List<MediaRoute2Info> selectedRoutes = new ArrayList<>(); final MediaRoute2Info info = mock(MediaRoute2Info.class); when(info.getId()).thenReturn(TEST_ID); - when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(info.getClientPackageName()).thenReturn(packageName); when(info.isSystemRoute()).thenReturn(true); selectedRoutes.add(info); when(mRouterManager.getSelectedRoutes(any())).thenReturn(selectedRoutes); - - final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>(); - final RoutingSessionInfo sessionInfo = mock(RoutingSessionInfo.class); - routingSessionInfos.add(sessionInfo); - - when(mRouterManager.getRoutingSessions(TEST_PACKAGE_NAME)).thenReturn(routingSessionInfos); - when(sessionInfo.getSelectedRoutes()).thenReturn(ImmutableList.of(TEST_ID)); - - setAvailableRoutesList(); - - mInfoMediaManager.mRouterManager = mRouterManager; - mInfoMediaManager.mMediaRouterCallback.onRouteListingPreferenceUpdated(TEST_PACKAGE_NAME, - routeListingPreference); - mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated(); - - assertThat(mInfoMediaManager.mMediaDevices).hasSize(3); - assertThat(mInfoMediaManager.mMediaDevices.get(0).getId()).isEqualTo(TEST_ID); - assertThat(mInfoMediaManager.mMediaDevices.get(1).getId()).isEqualTo(TEST_ID_4); - assertThat(mInfoMediaManager.mMediaDevices.get(1).isSuggestedDevice()).isTrue(); - assertThat(mInfoMediaManager.mMediaDevices.get(2).getId()).isEqualTo(TEST_ID_3); } - private List<MediaRoute2Info> setAvailableRoutesList() { + private List<MediaRoute2Info> setAvailableRoutesList(String packageName) { final List<MediaRoute2Info> availableRoutes = new ArrayList<>(); final MediaRoute2Info availableInfo1 = mock(MediaRoute2Info.class); when(availableInfo1.getId()).thenReturn(TEST_ID_2); - when(availableInfo1.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(availableInfo1.getClientPackageName()).thenReturn(packageName); when(availableInfo1.getType()).thenReturn(TYPE_REMOTE_TV); availableRoutes.add(availableInfo1); final MediaRoute2Info availableInfo2 = mock(MediaRoute2Info.class); when(availableInfo2.getId()).thenReturn(TEST_ID_3); - when(availableInfo2.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(availableInfo2.getClientPackageName()).thenReturn(packageName); availableRoutes.add(availableInfo2); final MediaRoute2Info availableInfo3 = mock(MediaRoute2Info.class); when(availableInfo3.getId()).thenReturn(TEST_ID_4); - when(availableInfo3.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(availableInfo3.getClientPackageName()).thenReturn(packageName); availableRoutes.add(availableInfo3); - when(mRouterManager.getAvailableRoutes(TEST_PACKAGE_NAME)).thenReturn( + when(mRouterManager.getAvailableRoutes(packageName)).thenReturn( availableRoutes); return availableRoutes; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt index 23b5241b79ef..314566eaf8d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt @@ -633,12 +633,17 @@ class HeadsUpCoordinator @Inject constructor( mFSIUpdateCandidates.removeAll(toRemoveForFSI) } - /** When an action is pressed on a notification, end HeadsUp lifetime extension. */ + /** + * When an action is pressed on a notification, make sure we don't lifetime-extend it in the + * future by informing the HeadsUpManager, and make sure we don't keep lifetime-extending it if + * we already are. + * + * @see HeadsUpManager.setUserActionMayIndirectlyRemove + * @see HeadsUpManager.canRemoveImmediately + */ private val mActionPressListener = Consumer<NotificationEntry> { entry -> - if (mNotifsExtendingLifetime.contains(entry)) { - val removeInMillis = mHeadsUpManager.getEarliestRemovalTime(entry.key) - mExecutor.executeDelayed({ endNotifLifetimeExtensionIfExtended(entry) }, removeInMillis) - } + mHeadsUpManager.setUserActionMayIndirectlyRemove(entry) + mExecutor.execute { endNotifLifetimeExtensionIfExtended(entry) } } private val mLifetimeExtender = object : NotifLifetimeExtender { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index ed8050a031d8..92a78541d744 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -393,6 +393,31 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { } } + /** + * Notes that the user took an action on an entry that might indirectly cause the system or the + * app to remove the notification. + * + * @param entry the entry that might be indirectly removed by the user's action + * + * @see com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator#mActionPressListener + * @see #canRemoveImmediately(String) + */ + public void setUserActionMayIndirectlyRemove(@NonNull NotificationEntry entry) { + HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey()); + if (headsUpEntry != null) { + headsUpEntry.userActionMayIndirectlyRemove = true; + } + } + + @Override + public boolean canRemoveImmediately(@NonNull String key) { + HeadsUpEntry headsUpEntry = getHeadsUpEntry(key); + if (headsUpEntry != null && headsUpEntry.userActionMayIndirectlyRemove) { + return true; + } + return super.canRemoveImmediately(key); + } + @NonNull @Override protected HeadsUpEntry createAlertEntry() { @@ -421,6 +446,8 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { */ protected class HeadsUpEntry extends AlertEntry { public boolean remoteInputActive; + public boolean userActionMayIndirectlyRemove; + protected boolean expanded; protected boolean wasUnpinned; diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 109c1cfdcf0f..b848d2e84faf 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -930,7 +930,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, showRingerDrawer(); } }); - updateSelectedRingerContainerDescription(mIsRingerDrawerOpen); mRingerDrawerVibrate.setOnClickListener( new RingerDrawerItemClickListener(RINGER_MODE_VIBRATE)); @@ -993,18 +992,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, : 0; } - @VisibleForTesting String getSelectedRingerContainerDescription() { - return mSelectedRingerContainer.getContentDescription().toString(); - } - - @VisibleForTesting void toggleRingerDrawer(boolean show) { - if (show) { - showRingerDrawer(); - } else { - hideRingerDrawer(); - } - } - /** Animates in the ringer drawer. */ private void showRingerDrawer() { if (mIsRingerDrawerOpen) { @@ -1082,7 +1069,12 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, .start(); } - updateSelectedRingerContainerDescription(true); + // When the ringer drawer is open, tapping the currently selected ringer will set the ringer + // to the current ringer mode. Change the content description to that, instead of the 'tap + // to change ringer mode' default. + mSelectedRingerContainer.setContentDescription( + mContext.getString(getStringDescriptionResourceForRingerMode( + mState.ringerModeInternal))); mIsRingerDrawerOpen = true; } @@ -1128,38 +1120,14 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, .translationY(0f) .start(); - updateSelectedRingerContainerDescription(false); + // When the drawer is closed, tapping the selected ringer drawer will open it, allowing the + // user to change the ringer. + mSelectedRingerContainer.setContentDescription( + mContext.getString(R.string.volume_ringer_change)); mIsRingerDrawerOpen = false; } - - /** - * @param open false to set the description when drawer is closed - */ - private void updateSelectedRingerContainerDescription(boolean open) { - if (mState == null) return; - - String currentMode = mContext.getString(getStringDescriptionResourceForRingerMode( - mState.ringerModeInternal)); - String tapToSelect; - - if (open) { - // When the ringer drawer is open, tapping the currently selected ringer will set the - // ringer to the current ringer mode. Change the content description to that, instead of - // the 'tap to change ringer mode' default. - tapToSelect = ""; - - } else { - // When the drawer is closed, tapping the selected ringer drawer will open it, allowing - // the user to change the ringer. The user needs to know that, and also the current mode - currentMode += ", "; - tapToSelect = mContext.getString(R.string.volume_ringer_change); - } - - mSelectedRingerContainer.setContentDescription(currentMode + tapToSelect); - } - private void initSettingsH(int lockTaskModeState) { if (mSettingsView != null) { mSettingsView.setVisibility( @@ -1735,7 +1703,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, }); } - @VisibleForTesting int getStringDescriptionResourceForRingerMode(int mode) { + private int getStringDescriptionResourceForRingerMode(int mode) { switch (mode) { case RINGER_MODE_SILENT: return R.string.volume_ringer_status_silent; @@ -1817,7 +1785,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, updateVolumeRowH(row); } updateRingerH(); - updateSelectedRingerContainerDescription(mIsRingerDrawerOpen); mWindow.setTitle(composeWindowTitle()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt index 283efe263f04..257cc5b1b85c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt @@ -221,16 +221,35 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { } @Test - fun hunExtensionCancelledWhenHunActionPressed() { + fun actionPressCancelsExistingLifetimeExtension() { whenever(headsUpManager.isSticky(anyString())).thenReturn(true) addHUN(entry) + whenever(headsUpManager.canRemoveImmediately(anyString())).thenReturn(false) whenever(headsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L) - assertTrue(notifLifetimeExtender.maybeExtendLifetime(entry, 0)) + assertTrue(notifLifetimeExtender.maybeExtendLifetime(entry, /* reason = */ 0)) + actionPressListener.accept(entry) - executor.advanceClockToLast() executor.runAllReady() - verify(headsUpManager, times(1)).removeNotification(eq(entry.key), eq(true)) + verify(endLifetimeExtension, times(1)).onEndLifetimeExtension(notifLifetimeExtender, entry) + + collectionListener.onEntryRemoved(entry, /* reason = */ 0) + verify(headsUpManager, times(1)).removeNotification(eq(entry.key), any()) + } + + @Test + fun actionPressPreventsFutureLifetimeExtension() { + whenever(headsUpManager.isSticky(anyString())).thenReturn(true) + addHUN(entry) + + actionPressListener.accept(entry) + verify(headsUpManager, times(1)).setUserActionMayIndirectlyRemove(entry) + + whenever(headsUpManager.canRemoveImmediately(anyString())).thenReturn(true) + assertFalse(notifLifetimeExtender.maybeExtendLifetime(entry, 0)) + + collectionListener.onEntryRemoved(entry, /* reason = */ 0) + verify(headsUpManager, times(1)).removeNotification(eq(entry.key), any()) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java index 487d26d21824..a797e032a353 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java @@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotSame; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; @@ -346,4 +345,17 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest { assertEquals(HeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(), mUiEventLoggerFake.eventId(0)); } + + @Test + public void testSetUserActionMayIndirectlyRemove() { + NotificationEntry notifEntry = new NotificationEntryBuilder() + .setSbn(createNewNotification(/* id= */ 0)) + .build(); + + mHeadsUpManager.showNotification(notifEntry); + assertFalse(mHeadsUpManager.canRemoveImmediately(notifEntry.getKey())); + + mHeadsUpManager.setUserActionMayIndirectlyRemove(notifEntry); + assertTrue(mHeadsUpManager.canRemoveImmediately(notifEntry.getKey())); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index 2ea6368ab402..8f725bebfb16 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -16,16 +16,11 @@ package com.android.systemui.volume; -import static android.media.AudioManager.RINGER_MODE_NORMAL; -import static android.media.AudioManager.RINGER_MODE_SILENT; -import static android.media.AudioManager.RINGER_MODE_VIBRATE; - import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN; import static com.android.systemui.volume.Events.SHOW_REASON_UNKNOWN; import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS; import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotSame; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -298,7 +293,7 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Test public void testSelectVibrateFromDrawer() { final State initialUnsetState = new State(); - initialUnsetState.ringerModeInternal = RINGER_MODE_NORMAL; + initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL; mDialog.onStateChangedH(initialUnsetState); mActiveRinger.performClick(); @@ -312,7 +307,7 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Test public void testSelectMuteFromDrawer() { final State initialUnsetState = new State(); - initialUnsetState.ringerModeInternal = RINGER_MODE_NORMAL; + initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL; mDialog.onStateChangedH(initialUnsetState); mActiveRinger.performClick(); @@ -334,7 +329,7 @@ public class VolumeDialogImplTest extends SysuiTestCase { // Make sure we've actually changed the ringer mode. verify(mVolumeDialogController, times(1)).setRingerMode( - RINGER_MODE_NORMAL, false); + AudioManager.RINGER_MODE_NORMAL, false); } /** @@ -516,85 +511,6 @@ public class VolumeDialogImplTest extends SysuiTestCase { } } - private enum RingerDrawerState {INIT, OPEN, CLOSE} - - @Test - public void ringerModeNormal_ringerContainerDescribesItsState() { - assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.INIT); - } - - @Test - public void ringerModeSilent_ringerContainerDescribesItsState() { - assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.INIT); - } - - @Test - public void ringerModeVibrate_ringerContainerDescribesItsState() { - assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.INIT); - } - - @Test - public void ringerModeNormal_openDrawer_ringerContainerDescribesItsState() { - assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.OPEN); - } - - @Test - public void ringerModeSilent_openDrawer_ringerContainerDescribesItsState() { - assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.OPEN); - } - - @Test - public void ringerModeVibrate_openDrawer_ringerContainerDescribesItsState() { - assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.OPEN); - } - - @Test - public void ringerModeNormal_closeDrawer_ringerContainerDescribesItsState() { - assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.CLOSE); - } - - @Test - public void ringerModeSilent_closeDrawer_ringerContainerDescribesItsState() { - assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.CLOSE); - } - - @Test - public void ringerModeVibrate_closeDrawer_ringerContainerDescribesItsState() { - assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.CLOSE); - } - - /** - * The content description should include ringer state, and the correct one. - */ - private void assertRingerContainerDescribesItsState(int ringerMode, - RingerDrawerState drawerState) { - State state = createShellState(); - state.ringerModeInternal = ringerMode; - mDialog.onStateChangedH(state); - - mDialog.show(SHOW_REASON_UNKNOWN); - - if (drawerState != RingerDrawerState.INIT) { - // in both cases we first open the drawer - mDialog.toggleRingerDrawer(true); - - if (drawerState == RingerDrawerState.CLOSE) { - mDialog.toggleRingerDrawer(false); - } - } - - String ringerContainerDescription = mDialog.getSelectedRingerContainerDescription(); - String ringerDescription = mContext.getString( - mDialog.getStringDescriptionResourceForRingerMode(ringerMode)); - - if (drawerState == RingerDrawerState.OPEN) { - assertEquals(ringerDescription, ringerContainerDescription); - } else { - assertNotSame(ringerDescription, ringerContainerDescription); - assertTrue(ringerContainerDescription.startsWith(ringerDescription)); - } - } - @After public void teardown() { if (mDialog != null) { diff --git a/services/core/java/com/android/server/WallpaperUpdateReceiver.java b/services/core/java/com/android/server/WallpaperUpdateReceiver.java index 2812233815a6..99178920cc52 100644 --- a/services/core/java/com/android/server/WallpaperUpdateReceiver.java +++ b/services/core/java/com/android/server/WallpaperUpdateReceiver.java @@ -88,7 +88,7 @@ public class WallpaperUpdateReceiver extends BroadcastReceiver { } else { //live wallpaper ComponentName currCN = info.getComponent(); - ComponentName defaultCN = WallpaperManager.getCmfDefaultWallpaperComponent(context); + ComponentName defaultCN = WallpaperManager.getDefaultWallpaperComponent(context); if (!currCN.equals(defaultCN)) { return true; } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 1f8ff73b2d5d..fc72a771fa9c 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -2214,6 +2214,7 @@ import java.util.concurrent.atomic.AtomicBoolean; mDeviceInventory.removePreferredDevicesForStrategyInt(mAccessibilityStrategyId); } mDeviceInventory.applyConnectedDevicesRoles(); + mDeviceInventory.reapplyExternalDevicesRoles(); } else { mDeviceInventory.setPreferredDevicesForStrategyInt( mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice)); diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index d1cae490a31d..219dda398ebf 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -361,23 +361,34 @@ public class AudioDeviceInventory { AudioSystem.DEVICE_STATE_AVAILABLE, di.mDeviceCodecFormat); } - mAppliedStrategyRoles.clear(); mAppliedStrategyRolesInt.clear(); - mAppliedPresetRoles.clear(); mAppliedPresetRolesInt.clear(); applyConnectedDevicesRoles_l(); } + reapplyExternalDevicesRoles(); + } + + /*package*/ void reapplyExternalDevicesRoles() { + synchronized (mDevicesLock) { + mAppliedStrategyRoles.clear(); + mAppliedPresetRoles.clear(); + } synchronized (mPreferredDevices) { mPreferredDevices.forEach((strategy, devices) -> { - setPreferredDevicesForStrategy(strategy, devices); }); + setPreferredDevicesForStrategy(strategy, devices); + }); } synchronized (mNonDefaultDevices) { mNonDefaultDevices.forEach((strategy, devices) -> { addDevicesRoleForStrategy(strategy, AudioSystem.DEVICE_ROLE_DISABLED, - devices, false /* internal */); }); + devices, false /* internal */); + }); } synchronized (mPreferredDevicesForCapturePreset) { - // TODO: call audiosystem to restore + mPreferredDevicesForCapturePreset.forEach((capturePreset, devices) -> { + setDevicesRoleForCapturePreset( + capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices); + }); } } @@ -1163,6 +1174,7 @@ public class AudioDeviceInventory { return mAudioSystem.removeDevicesRoleForStrategy(s, r, d); }); purgeRoles(mAppliedPresetRolesInt, (p, r, d) -> { return mAudioSystem.removeDevicesRoleForCapturePreset(p, r, d); }); + reapplyExternalDevicesRoles(); } @GuardedBy("mDevicesLock") diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index f2d1357ac1b5..aaf13ebeff2a 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -3714,11 +3714,16 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile if (parser.getName().equals(TAG_PERMISSIONS)) { final LegacyPermissionState legacyState; if (ps.hasSharedUser()) { - legacyState = getSettingLPr(ps.getSharedUserAppId()).getLegacyPermissionState(); + final SettingBase sharedUserSettings = getSettingLPr( + ps.getSharedUserAppId()); + legacyState = sharedUserSettings != null + ? sharedUserSettings.getLegacyPermissionState() : null; } else { legacyState = ps.getLegacyPermissionState(); } - readInstallPermissionsLPr(parser, legacyState, users); + if (legacyState != null) { + readInstallPermissionsLPr(parser, legacyState, users); + } } else if (parser.getName().equals(TAG_USES_STATIC_LIB)) { readUsesStaticLibLPw(parser, ps); } else if (parser.getName().equals(TAG_USES_SDK_LIB)) { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index a020728cc85e..5b3514c01f9f 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -2547,10 +2547,7 @@ public class ShortcutService extends IShortcutService.Stub { enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS, "getShareTargets"); final ComponentName chooser = injectChooserActivity(); - final String pkg = (chooser != null - && mPackageManagerInternal.getComponentEnabledSetting(chooser, - injectBinderCallingUid(), userId) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) - ? chooser.getPackageName() : mContext.getPackageName(); + final String pkg = chooser != null ? chooser.getPackageName() : mContext.getPackageName(); synchronized (mLock) { throwIfUserLockedL(userId); final List<ShortcutManager.ShareShortcutInfo> shortcutInfoList = new ArrayList<>(); diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java index 3e7ae331d705..2499529f0fc0 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java @@ -141,6 +141,7 @@ import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageState; import com.android.server.pm.pkg.PackageStateInternal; +import com.android.server.pm.pkg.SharedUserApi; import com.android.server.pm.pkg.component.ComponentMutateUtils; import com.android.server.pm.pkg.component.ParsedPermission; import com.android.server.pm.pkg.component.ParsedPermissionGroup; @@ -4538,8 +4539,13 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt final int appId = ps.getAppId(); final LegacyPermissionState legacyState; if (ps.hasSharedUser()) { - legacyState = mPackageManagerInt.getSharedUserApi( - ps.getSharedUserAppId()).getSharedUserLegacyPermissionState(); + final int sharedUserId = ps.getSharedUserAppId(); + SharedUserApi sharedUserApi = mPackageManagerInt.getSharedUserApi(sharedUserId); + if (sharedUserApi == null) { + Slog.wtf(TAG, "Missing shared user Api for " + sharedUserId); + return; + } + legacyState = sharedUserApi.getSharedUserLegacyPermissionState(); } else { legacyState = ps.getLegacyPermissionState(); } @@ -4584,8 +4590,13 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt ps.setInstallPermissionsFixed(false); final LegacyPermissionState legacyState; if (ps.hasSharedUser()) { - legacyState = mPackageManagerInt.getSharedUserApi( - ps.getSharedUserAppId()).getSharedUserLegacyPermissionState(); + final int sharedUserId = ps.getSharedUserAppId(); + SharedUserApi sharedUserApi = mPackageManagerInt.getSharedUserApi(sharedUserId); + if (sharedUserApi == null) { + Slog.wtf(TAG, "Missing shared user Api for " + sharedUserId); + return; + } + legacyState = sharedUserApi.getSharedUserLegacyPermissionState(); } else { legacyState = ps.getLegacyPermissionState(); } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperData.java b/services/core/java/com/android/server/wallpaper/WallpaperData.java index 9ff6a0d7e6ee..d87fca4d3c71 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperData.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperData.java @@ -133,16 +133,14 @@ class WallpaperData { */ final Rect cropHint = new Rect(0, 0, 0, 0); - WallpaperData(int userId, File wallpaperDir, String inputFileName, String cropFileName) { - this.userId = userId; - wallpaperFile = new File(wallpaperDir, inputFileName); - cropFile = new File(wallpaperDir, cropFileName); - } - WallpaperData(int userId, @SetWallpaperFlags int wallpaperType) { - this(userId, getWallpaperDir(userId), - (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER, - (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP); + this.userId = userId; + this.mWhich = wallpaperType; + File wallpaperDir = getWallpaperDir(userId); + String wallpaperFileName = (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER; + String cropFileName = (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP; + this.wallpaperFile = new File(wallpaperDir, wallpaperFileName); + this.cropFile = new File(wallpaperDir, cropFileName); } /** diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index a079875a23e4..9e9b3444006c 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1588,7 +1588,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub mShuttingDown = false; mImageWallpaper = ComponentName.unflattenFromString( context.getResources().getString(R.string.image_wallpaper_component)); - mDefaultWallpaperComponent = WallpaperManager.getCmfDefaultWallpaperComponent(context); + mDefaultWallpaperComponent = WallpaperManager.getDefaultWallpaperComponent(context); mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mIPackageManager = AppGlobals.getPackageManager(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index a5b15489f292..0eafbd4a0b60 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -7840,27 +7840,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new SecurityException("Cannot wipe data. " + restriction + " restriction is set for user " + userId); } + }); - boolean isSystemUser = userId == UserHandle.USER_SYSTEM; - boolean wipeDevice; - if (factoryReset == null || !mInjector.isChangeEnabled(EXPLICIT_WIPE_BEHAVIOUR, - adminPackage, - userId)) { - // Legacy mode - wipeDevice = isSystemUser; + boolean isSystemUser = userId == UserHandle.USER_SYSTEM; + boolean wipeDevice; + if (factoryReset == null || !mInjector.isChangeEnabled(EXPLICIT_WIPE_BEHAVIOUR, + adminPackage, + userId)) { + // Legacy mode + wipeDevice = isSystemUser; + } else { + // Explicit behaviour + if (factoryReset) { + EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin( + /*admin=*/ null, + /*permission=*/ new String[]{MANAGE_DEVICE_POLICY_WIPE_DATA, + MASTER_CLEAR}, + USES_POLICY_WIPE_DATA, + adminPackage, + factoryReset ? UserHandle.USER_ALL : + getAffectedUser(calledOnParentInstance)); + wipeDevice = true; } else { - // Explicit behaviour - if (factoryReset) { - EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin( - /*admin=*/ null, - /*permission=*/ new String[]{MANAGE_DEVICE_POLICY_WIPE_DATA, - MASTER_CLEAR}, - USES_POLICY_WIPE_DATA, - adminPackage, - factoryReset ? UserHandle.USER_ALL : - getAffectedUser(calledOnParentInstance)); - wipeDevice = true; - } else { + mInjector.binderWithCleanCallingIdentity(() -> { Preconditions.checkCallAuthorization(!isSystemUser, "User %s is a system user and cannot be removed", userId); boolean isLastNonHeadlessUser = getUserInfo(userId).isFull() @@ -7871,9 +7873,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "Removing user %s would leave the device without any active users. " + "Consider factory resetting the device instead.", userId); - wipeDevice = false; - } + }); + wipeDevice = false; } + } + mInjector.binderWithCleanCallingIdentity(() -> { if (wipeDevice) { forceWipeDeviceNoLock( (flags & WIPE_EXTERNAL_STORAGE) != 0, diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java index 51e521d8ffe4..206af5b6aea6 100644 --- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java @@ -17,8 +17,10 @@ package com.android.server.wallpaper; import static android.app.WallpaperManager.COMMAND_REAPPLY; +import static android.app.WallpaperManager.FLAG_LOCK; import static android.app.WallpaperManager.FLAG_SYSTEM; import static android.os.FileObserver.CLOSE_WRITE; +import static android.os.UserHandle.MIN_SECONDARY_USER_ID; import static android.os.UserHandle.USER_SYSTEM; import static android.view.Display.DEFAULT_DISPLAY; @@ -106,6 +108,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.List; /** * Tests for the {@link WallpaperManagerService} class. @@ -172,12 +175,12 @@ public class WallpaperManagerServiceTests { sImageWallpaperComponentName = ComponentName.unflattenFromString( sContext.getResources().getString(R.string.image_wallpaper_component)); // Mock default wallpaper as image wallpaper if there is no pre-defined default wallpaper. - sDefaultWallpaperComponent = WallpaperManager.getCmfDefaultWallpaperComponent(sContext); + sDefaultWallpaperComponent = WallpaperManager.getDefaultWallpaperComponent(sContext); if (sDefaultWallpaperComponent == null) { sDefaultWallpaperComponent = sImageWallpaperComponentName; doReturn(sImageWallpaperComponentName).when(() -> - WallpaperManager.getCmfDefaultWallpaperComponent(any())); + WallpaperManager.getDefaultWallpaperComponent(any())); } else { sContext.addMockService(sDefaultWallpaperComponent, sWallpaperService); } @@ -262,6 +265,25 @@ public class WallpaperManagerServiceTests { } /** + * Tests that the fundamental fields are set by the main WallpaperData constructor + */ + @Test + public void testWallpaperDataConstructor() { + final int testUserId = MIN_SECONDARY_USER_ID; + for (int which: List.of(FLAG_LOCK, FLAG_SYSTEM)) { + WallpaperData newWallpaperData = new WallpaperData(testUserId, which); + assertEquals(which, newWallpaperData.mWhich); + assertEquals(testUserId, newWallpaperData.userId); + + WallpaperData wallpaperData = mService.getWallpaperSafeLocked(testUserId, which); + assertEquals(wallpaperData.cropFile.getAbsolutePath(), + newWallpaperData.cropFile.getAbsolutePath()); + assertEquals(wallpaperData.wallpaperFile.getAbsolutePath(), + newWallpaperData.wallpaperFile.getAbsolutePath()); + } + } + + /** * Tests that internal basic data should be correct after boot up. */ @Test @@ -405,10 +427,7 @@ public class WallpaperManagerServiceTests { fail("exception occurred while writing system wallpaper attributes"); } - WallpaperData shouldMatchSystem = new WallpaperData(systemWallpaperData.userId, - systemWallpaperData.wallpaperFile.getParentFile(), - systemWallpaperData.wallpaperFile.getAbsolutePath(), - systemWallpaperData.cropFile.getAbsolutePath()); + WallpaperData shouldMatchSystem = new WallpaperData(0, FLAG_SYSTEM); try { TypedXmlPullParser parser = Xml.newBinaryPullParser(); mService.mWallpaperDataParser.parseWallpaperAttributes(parser, shouldMatchSystem, true); |