diff options
| author | 2022-02-14 23:57:02 +0000 | |
|---|---|---|
| committer | 2022-02-14 23:57:02 +0000 | |
| commit | 5409ef1ab7ea2138a5e22f7e0d30b837ce0c4f04 (patch) | |
| tree | 9cdc6ca664c398de7055bb70f9b2360a006e38c6 | |
| parent | 5dbc71e1f0f4878ac05106e3ef5ba96c120111f3 (diff) | |
| parent | 2b87be68b86accaadfd2bdf5efe68f1a4d4cd1f9 (diff) | |
Merge "Merge SP2A.220305.012" into stage-aosp-master
27 files changed, 395 insertions, 163 deletions
diff --git a/core/java/android/app/ServiceStartNotAllowedException.java b/core/java/android/app/ServiceStartNotAllowedException.java index 33285b2190eb..b1f47eee4bfd 100644 --- a/core/java/android/app/ServiceStartNotAllowedException.java +++ b/core/java/android/app/ServiceStartNotAllowedException.java @@ -40,4 +40,11 @@ public abstract class ServiceStartNotAllowedException extends IllegalStateExcept return new BackgroundServiceStartNotAllowedException(message); } } + + @Override + public synchronized Throwable getCause() { + // "Cause" is often used for clustering exceptions, and developers don't want to have it + // for this exception. b/210890426 + return null; + } } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 3712caeddaf5..fca4c698c49c 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -1488,27 +1488,18 @@ public class WallpaperManager { mContext.getUserId()); if (fd != null) { FileOutputStream fos = null; - final Bitmap tmp = BitmapFactory.decodeStream(resources.openRawResource(resid)); + boolean ok = false; try { - // If the stream can't be decoded, treat it as an invalid input. - if (tmp != null) { - fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); - tmp.compress(Bitmap.CompressFormat.PNG, 100, fos); - // The 'close()' is the trigger for any server-side image manipulation, - // so we must do that before waiting for completion. - fos.close(); - completion.waitForCompletion(); - } else { - throw new IllegalArgumentException( - "Resource 0x" + Integer.toHexString(resid) + " is invalid"); - } + fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); + copyStreamToWallpaperFile(resources.openRawResource(resid), fos); + // The 'close()' is the trigger for any server-side image manipulation, + // so we must do that before waiting for completion. + fos.close(); + completion.waitForCompletion(); } finally { // Might be redundant but completion shouldn't wait unless the write // succeeded; this is a fallback if it threw past the close+wait. IoUtils.closeQuietly(fos); - if (tmp != null) { - tmp.recycle(); - } } } } catch (RemoteException e) { @@ -1750,22 +1741,13 @@ public class WallpaperManager { result, which, completion, mContext.getUserId()); if (fd != null) { FileOutputStream fos = null; - final Bitmap tmp = BitmapFactory.decodeStream(bitmapData); try { - // If the stream can't be decoded, treat it as an invalid input. - if (tmp != null) { - fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); - tmp.compress(Bitmap.CompressFormat.PNG, 100, fos); - fos.close(); - completion.waitForCompletion(); - } else { - throw new IllegalArgumentException("InputStream is invalid"); - } + fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); + copyStreamToWallpaperFile(bitmapData, fos); + fos.close(); + completion.waitForCompletion(); } finally { IoUtils.closeQuietly(fos); - if (tmp != null) { - tmp.recycle(); - } } } } catch (RemoteException e) { diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java index d0719eeca04e..b4ae56f23443 100644 --- a/core/java/com/android/internal/app/LocalePickerWithRegion.java +++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java @@ -159,6 +159,14 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O } @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + // In order to make the list view work with CollapsingToolbarLayout, + // we have to enable the nested scrolling feature of the list view. + getListView().setNestedScrollingEnabled(true); + } + + @Override public boolean onOptionsItemSelected(MenuItem menuItem) { int id = menuItem.getItemId(); switch (id) { diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml index 0cdaa206c156..1b8032b7077b 100644 --- a/libs/WindowManager/Shell/res/values/config.xml +++ b/libs/WindowManager/Shell/res/values/config.xml @@ -43,6 +43,9 @@ <!-- PiP minimum size, which is a % based off the shorter side of display width and height --> <fraction name="config_pipShortestEdgePercent">40%</fraction> + <!-- Show PiP enter split icon, which allows apps to directly enter splitscreen from PiP. --> + <bool name="config_pipEnableEnterSplitButton">false</bool> + <!-- Animation duration when using long press on recents to dock --> <integer name="long_press_dock_anim_duration">250</integer> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 620c291b357b..14433c233273 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -1724,6 +1724,7 @@ public class BubbleStackView extends FrameLayout /** * Changes the expanded state of the stack. + * Don't call this directly, call mBubbleData#setExpanded. * * @param shouldExpand whether the bubble stack should appear expanded */ @@ -1770,7 +1771,7 @@ public class BubbleStackView extends FrameLayout } else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) { mManageEduView.hide(); } else { - setExpanded(false); + mBubbleData.setExpanded(false); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java index da4bbe81a3e6..e1475efcdb57 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java @@ -104,8 +104,6 @@ public class PipMenuView extends FrameLayout { private static final float MENU_BACKGROUND_ALPHA = 0.3f; private static final float DISABLED_ACTION_ALPHA = 0.54f; - private static final boolean ENABLE_ENTER_SPLIT = true; - private int mMenuState; private boolean mAllowMenuTimeout = true; private boolean mAllowTouches = true; @@ -277,6 +275,8 @@ public class PipMenuView extends FrameLayout { boolean resizeMenuOnShow, boolean withDelay, boolean showResizeHandle) { mAllowMenuTimeout = allowMenuTimeout; mDidLastShowMenuResize = resizeMenuOnShow; + final boolean enableEnterSplit = + mContext.getResources().getBoolean(R.bool.config_pipEnableEnterSplitButton); if (mMenuState != menuState) { // Disallow touches if the menu needs to resize while showing, and we are transitioning // to/from a full menu state. @@ -297,7 +297,7 @@ public class PipMenuView extends FrameLayout { mDismissButton.getAlpha(), 1f); ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA, mEnterSplitButton.getAlpha(), - ENABLE_ENTER_SPLIT && mFocusedTaskAllowSplitScreen ? 1f : 0f); + enableEnterSplit && mFocusedTaskAllowSplitScreen ? 1f : 0f); if (menuState == MENU_STATE_FULL) { mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim, enterSplitAnim); diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index e69582f52ebf..f72a8dc08c9c 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -378,7 +378,8 @@ android:clickable="true"/> </LinearLayout> </LinearLayout> - <FrameLayout + + <LinearLayout android:id="@+id/button_layout" android:orientation="horizontal" android:layout_width="match_parent" @@ -390,9 +391,10 @@ android:clickable="false" android:focusable="false"> - <FrameLayout + <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_weight="1" android:layout_gravity="start|center_vertical" android:orientation="vertical"> <Button @@ -401,12 +403,13 @@ android:layout_height="wrap_content" android:text="@string/turn_off_airplane_mode" android:ellipsize="end" + android:maxLines="1" style="@style/Widget.Dialog.Button.BorderButton" android:clickable="true" android:focusable="true"/> - </FrameLayout> + </LinearLayout> - <FrameLayout + <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" @@ -417,10 +420,13 @@ android:layout_height="wrap_content" android:text="@string/inline_done_button" style="@style/Widget.Dialog.Button" + android:maxLines="1" + android:ellipsize="end" android:clickable="true" android:focusable="true"/> - </FrameLayout> - </FrameLayout> + </LinearLayout> + </LinearLayout> + </LinearLayout> </androidx.core.widget.NestedScrollView> </LinearLayout> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 051a30ccb524..f26159f5176a 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -942,8 +942,9 @@ </style> <style name="InternetDialog.NetworkSummary"> - <item name="android:layout_marginEnd">34dp</item> + <item name="android:layout_marginEnd">7dp</item> <item name="android:ellipsize">end</item> + <item name="android:maxLines">2</item> <item name="android:textAppearance">@style/TextAppearance.InternetDialog.Secondary</item> </style> diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java index 0934b32a71e4..b920a17a0c1c 100644 --- a/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java +++ b/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java @@ -16,12 +16,15 @@ package com.android.systemui.flags; +import android.content.res.Resources; import android.util.SparseBooleanArray; +import androidx.annotation.BoolRes; import androidx.annotation.NonNull; import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import java.io.FileDescriptor; @@ -38,8 +41,11 @@ import javax.inject.Inject; @SysUISingleton public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable { SparseBooleanArray mAccessedFlags = new SparseBooleanArray(); + private Resources mResources; + @Inject - public FeatureFlagManager(DumpManager dumpManager) { + public FeatureFlagManager(DumpManager dumpManager, @Main Resources resources) { + mResources = resources; dumpManager.registerDumpable("SysUIFlags", this); } @@ -51,7 +57,20 @@ public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable { @Override public boolean isEnabled(BooleanFlag flag) { - return isEnabled(flag.getId(), flag.getDefault()); + boolean def = flag.getDefault(); + if (flag.hasResourceOverride()) { + try { + def = isEnabledInOverlay(flag.getResourceOverride()); + } catch (Resources.NotFoundException e) { + // no-op + } + } + + return isEnabled(flag.getId(), def); + } + + private boolean isEnabledInOverlay(@BoolRes int resId) { + return mResources.getBoolean(resId); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java index 0340904cbd9d..b2658c9f9bdb 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java @@ -16,6 +16,8 @@ package com.android.keyguard; +import android.util.Log; + /** * Defines constants for the Keyguard. */ @@ -25,7 +27,7 @@ public class KeyguardConstants { * Turns on debugging information for the whole Keyguard. This is very verbose and should only * be used temporarily for debugging. */ - public static final boolean DEBUG = false; + public static final boolean DEBUG = Log.isLoggable("Keyguard", Log.DEBUG); public static final boolean DEBUG_SIM_STATES = true; public static final boolean DEBUG_BIOMETRIC_WAKELOCK = true; } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java index 66c51d278dab..e2716e992c48 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java @@ -159,7 +159,9 @@ public class MediaProjectionPermissionActivity extends Activity mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true); final Window w = mDialog.getWindow(); - w.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + // QS is not closed when pressing CastTile. Match the type of the dialog shown from the + // tile. + w.setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); w.addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); mDialog.show(); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index ca63ec269bf4..0d11070fd220 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -86,6 +86,7 @@ import androidx.constraintlayout.widget.ConstraintLayout; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition; +import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.QuickStepContract; @@ -162,6 +163,7 @@ public class ScreenshotView extends FrameLayout implements private GestureDetector mSwipeDetector; private SwipeDismissHandler mSwipeDismissHandler; private InputMonitorCompat mInputMonitor; + private InputChannelCompat.InputEventReceiver mInputEventReceiver; private boolean mShowScrollablePreview; private String mPackageName = ""; @@ -302,8 +304,8 @@ public class ScreenshotView extends FrameLayout implements private void startInputListening() { stopInputListening(); mInputMonitor = new InputMonitorCompat("Screenshot", Display.DEFAULT_DISPLAY); - mInputMonitor.getInputReceiver(Looper.getMainLooper(), Choreographer.getInstance(), - ev -> { + mInputEventReceiver = mInputMonitor.getInputReceiver( + Looper.getMainLooper(), Choreographer.getInstance(), ev -> { if (ev instanceof MotionEvent) { MotionEvent event = (MotionEvent) ev; if (event.getActionMasked() == MotionEvent.ACTION_DOWN @@ -320,6 +322,10 @@ public class ScreenshotView extends FrameLayout implements mInputMonitor.dispose(); mInputMonitor = null; } + if (mInputEventReceiver != null) { + mInputEventReceiver.dispose(); + mInputEventReceiver = null; + } } @Override // ViewGroup diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java index 5993f1dee3a7..c29905bc7008 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java @@ -384,9 +384,9 @@ public class NotificationGroupManagerLegacy implements // * Only necessary when all notifications in the group use GROUP_ALERT_SUMMARY // * Only necessary when at least one notification in the group is on a priority channel if (group.summary.getSbn().getNotification().getGroupAlertBehavior() - != Notification.GROUP_ALERT_SUMMARY) { + == Notification.GROUP_ALERT_CHILDREN) { if (SPEW) { - Log.d(TAG, "getPriorityConversationAlertOverride: summary != GROUP_ALERT_SUMMARY"); + Log.d(TAG, "getPriorityConversationAlertOverride: summary == GROUP_ALERT_CHILDREN"); } return null; } @@ -529,8 +529,10 @@ public class NotificationGroupManagerLegacy implements mIsolatedEntries.put(entry.getKey(), entry.getSbn()); if (groupKeysChanged) { updateSuppression(mGroupMap.get(oldGroupKey)); - updateSuppression(mGroupMap.get(newGroupKey)); } + // Always update the suppression of the group from which you're isolated, in case + // this entry was or now is the alertOverride for that group. + updateSuppression(mGroupMap.get(newGroupKey)); } else if (!wasGroupChild && isGroupChild) { onEntryBecomingChild(entry); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 73a48c3b5cb0..c14e2f96320c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -130,6 +130,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable public static final float BACKGROUND_ALPHA_DIMMED = 0.7f; private static final String TAG = "StackScroller"; + private static final boolean SPEW = Log.isLoggable(TAG, Log.VERBOSE); // Usage: // adb shell setprop persist.debug.nssl true && adb reboot @@ -3156,6 +3157,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable AnimationEvent event = new AnimationEvent(row, type); event.headsUpFromBottom = onBottom; mAnimationEvents.add(event); + if (SPEW) { + Log.v(TAG, "Generating HUN animation event: " + + " isHeadsUp=" + isHeadsUp + + " type=" + type + + " onBottom=" + onBottom + + " row=" + row.getEntry().getKey()); + } } mHeadsUpChangeAnimations.clear(); mAddedHeadsUpChildren.clear(); @@ -4679,7 +4687,22 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) { - if (mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed)) { + final boolean add = mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed); + if (SPEW) { + Log.v(TAG, "generateHeadsUpAnimation:" + + " willAdd=" + add + + " isHeadsUp=" + isHeadsUp + + " row=" + row.getEntry().getKey()); + } + if (add) { + // If we're hiding a HUN we just started showing THIS FRAME, then remove that event, + // and do not add the disappear event either. + if (!isHeadsUp && mHeadsUpChangeAnimations.remove(new Pair<>(row, true))) { + if (SPEW) { + Log.v(TAG, "generateHeadsUpAnimation: previous hun appear animation cancelled"); + } + return; + } mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp)); mNeedsAnimation = true; if (!mIsExpanded && !mWillExpand && !isHeadsUp) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt index 83ab8cb80b29..4ba794fe8408 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt @@ -6,6 +6,7 @@ import android.animation.ValueAnimator import android.content.Context import android.database.ContentObserver import android.os.Handler +import android.os.PowerManager import android.provider.Settings import android.view.Surface import android.view.View @@ -50,9 +51,10 @@ class UnlockedScreenOffAnimationController @Inject constructor( private val keyguardViewMediatorLazy: dagger.Lazy<KeyguardViewMediator>, private val keyguardStateController: KeyguardStateController, private val dozeParameters: dagger.Lazy<DozeParameters>, - private val globalSettings: GlobalSettings + private val globalSettings: GlobalSettings, + private val powerManager: PowerManager, + private val handler: Handler = Handler() ) : WakefulnessLifecycle.Observer { - private val handler = Handler() private lateinit var statusBar: StatusBar private lateinit var lightRevealScrim: LightRevealScrim @@ -205,10 +207,18 @@ class UnlockedScreenOffAnimationController @Inject constructor( lightRevealAnimationPlaying = true lightRevealAnimator.start() handler.postDelayed({ - aodUiAnimationPlaying = true - - // Show AOD. That'll cause the KeyguardVisibilityHelper to call #animateInKeyguard. - statusBar.notificationPanelViewController.showAodUi() + // Only run this callback if the device is sleeping (not interactive). This callback + // is removed in onStartedWakingUp, but since that event is asynchronously + // dispatched, a race condition could make it possible for this callback to be run + // as the device is waking up. That results in the AOD UI being shown while we wake + // up, with unpredictable consequences. + if (!powerManager.isInteractive) { + aodUiAnimationPlaying = true + + // Show AOD. That'll cause the KeyguardVisibilityHelper to call + // #animateInKeyguard. + statusBar.notificationPanelViewController.showAodUi() + } }, (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong()) } else { decidedToAnimateGoingToSleep = false diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java index 634763866d02..856bbeaa85e4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java @@ -25,15 +25,14 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; -import android.content.Context; +import android.content.res.Resources; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; -import com.android.systemui.util.settings.SecureSettings; import org.junit.After; import org.junit.Before; @@ -53,14 +52,14 @@ import java.io.StringWriter; public class FeatureFlagManagerTest extends SysuiTestCase { FeatureFlagManager mFeatureFlagManager; - @Mock private Context mContext; @Mock private DumpManager mDumpManager; + @Mock private Resources mResources; @Before public void setup() { MockitoAnnotations.initMocks(this); - mFeatureFlagManager = new FeatureFlagManager(mDumpManager); + mFeatureFlagManager = new FeatureFlagManager(mDumpManager, mResources); } @After @@ -70,6 +69,24 @@ public class FeatureFlagManagerTest extends SysuiTestCase { verifyNoMoreInteractions(mDumpManager); } + + @Test + public void testSimpleFlag() { + BooleanFlag flagA = new BooleanFlag(100, false); + BooleanFlag flagB = new BooleanFlag(200, true); + + assertThat(mFeatureFlagManager.isEnabled(flagA)).isFalse(); + assertThat(mFeatureFlagManager.isEnabled(flagB)).isTrue(); + } + + @Test + public void testResourceOverride() { + when(mResources.getBoolean(1)).thenReturn(true); + BooleanFlag flag = new BooleanFlag(100, false, 1); + + assertThat(mFeatureFlagManager.isEnabled(flag)).isTrue(); + } + @Test public void testIsEnabled() { mFeatureFlagManager.setEnabled(1, true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java index 1be27da27d25..6d170b673cc3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java @@ -178,20 +178,68 @@ public class NotificationGroupManagerLegacyTest extends SysuiTestCase { } /** + * Helper for testing various sibling counts + */ + private void helpTestAlertOverrideWithSiblings(int numSiblings) { + helpTestAlertOverride( + /* numSiblings */ numSiblings, + /* summaryAlert */ Notification.GROUP_ALERT_SUMMARY, + /* childAlert */ Notification.GROUP_ALERT_SUMMARY, + /* siblingAlert */ Notification.GROUP_ALERT_SUMMARY, + /* expectAlertOverride */ true); + } + + @Test + public void testAlertOverrideWithParentAlertAll() { + // tests that summary can have GROUP_ALERT_ALL and this still works + helpTestAlertOverride( + /* numSiblings */ 1, + /* summaryAlert */ Notification.GROUP_ALERT_ALL, + /* childAlert */ Notification.GROUP_ALERT_SUMMARY, + /* siblingAlert */ Notification.GROUP_ALERT_SUMMARY, + /* expectAlertOverride */ true); + } + + @Test + public void testAlertOverrideWithParentAlertChild() { + // Tests that if the summary alerts CHILDREN, there's no alertOverride + helpTestAlertOverride( + /* numSiblings */ 1, + /* summaryAlert */ Notification.GROUP_ALERT_CHILDREN, + /* childAlert */ Notification.GROUP_ALERT_SUMMARY, + /* siblingAlert */ Notification.GROUP_ALERT_SUMMARY, + /* expectAlertOverride */ false); + } + + @Test + public void testAlertOverrideWithChildrenAlertAll() { + // Tests that if the children alert ALL, there's no alertOverride + helpTestAlertOverride( + /* numSiblings */ 1, + /* summaryAlert */ Notification.GROUP_ALERT_SUMMARY, + /* childAlert */ Notification.GROUP_ALERT_ALL, + /* siblingAlert */ Notification.GROUP_ALERT_ALL, + /* expectAlertOverride */ false); + } + + /** * This tests, for a group with a priority entry and the given number of siblings, that: * 1) the priority entry is identified as the alertOverride for the group * 2) the onAlertOverrideChanged method is called at that time * 3) when the priority entry is removed, these are reversed */ - private void helpTestAlertOverrideWithSiblings(int numSiblings) { - int groupAlert = Notification.GROUP_ALERT_SUMMARY; + private void helpTestAlertOverride(int numSiblings, + @Notification.GroupAlertBehavior int summaryAlert, + @Notification.GroupAlertBehavior int childAlert, + @Notification.GroupAlertBehavior int siblingAlert, + boolean expectAlertOverride) { // Create entries in an order so that the priority entry can be deemed the newest child. NotificationEntry[] siblings = new NotificationEntry[numSiblings]; for (int i = 0; i < numSiblings; i++) { - siblings[i] = mGroupTestHelper.createChildNotification(groupAlert); + siblings[i] = mGroupTestHelper.createChildNotification(siblingAlert); } - NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert); - NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert); + NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(childAlert); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(summaryAlert); // The priority entry is an important conversation. when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry))) @@ -208,6 +256,14 @@ public class NotificationGroupManagerLegacyTest extends SysuiTestCase { } mGroupManager.onEntryAdded(priorityEntry); + if (!expectAlertOverride) { + // Test expectation is that there will NOT be an alert, so verify that! + NotificationGroup summaryGroup = + mGroupManager.getGroupForSummary(summaryEntry.getSbn()); + assertNull(summaryGroup.alertOverride); + return; + } + // Verify that the summary group has the priority child as its alertOverride NotificationGroup summaryGroup = mGroupManager.getGroupForSummary(summaryEntry.getSbn()); assertEquals(priorityEntry, summaryGroup.alertOverride); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt index a8a33dabf1aa..fb8c9858be0b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt @@ -17,6 +17,8 @@ package com.android.systemui.statusbar.phone import android.animation.Animator +import android.os.Handler +import android.os.PowerManager import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.View @@ -28,13 +30,20 @@ import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.StatusBarStateControllerImpl import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.settings.GlobalSettings +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito +import org.mockito.Mockito.`when` +import org.mockito.Mockito.anyLong +import org.mockito.Mockito.mockingDetails +import org.mockito.Mockito.never import org.mockito.Mockito.spy +import org.mockito.Mockito.times +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest @@ -52,13 +61,19 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var globalSettings: GlobalSettings @Mock - private lateinit var statusbar: StatusBar + private lateinit var statusBar: StatusBar + @Mock + private lateinit var notificationPanelViewController: NotificationPanelViewController @Mock private lateinit var lightRevealScrim: LightRevealScrim @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock private lateinit var statusBarStateController: StatusBarStateControllerImpl + @Mock + private lateinit var powerManager: PowerManager + @Mock + private lateinit var handler: Handler @Before fun setUp() { @@ -71,9 +86,24 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { dagger.Lazy<KeyguardViewMediator> { keyguardViewMediator }, keyguardStateController, dagger.Lazy<DozeParameters> { dozeParameters }, - globalSettings + globalSettings, + powerManager, + handler = handler ) - controller.initialize(statusbar, lightRevealScrim) + controller.initialize(statusBar, lightRevealScrim) + `when`(statusBar.notificationPanelViewController).thenReturn( + notificationPanelViewController) + + // Screen off does not run if the panel is expanded, so we should say it's collapsed to test + // screen off. + `when`(notificationPanelViewController.isFullyCollapsed).thenReturn(true) + } + + @After + fun cleanUp() { + // Tell the screen off controller to cancel the animations and clean up its state, or + // subsequent tests will act unpredictably as the animator continues running. + controller.onStartedWakingUp() } @Test @@ -89,4 +119,51 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { listener.value.onAnimationEnd(null) Mockito.verify(animator).setListener(null) } + + /** + * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal + * animation to start. If the device is woken up during the screen off, we should *never* do + * this. + * + * This test confirms that we do show the AOD UI when the device is not woken up + * (PowerManager#isInteractive = false). + */ + @Test + fun testAodUiShownIfNotInteractive() { + `when`(dozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true) + `when`(powerManager.isInteractive).thenReturn(false) + + val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java) + controller.onStartedGoingToSleep() + + verify(handler).postDelayed(callbackCaptor.capture(), anyLong()) + + callbackCaptor.value.run() + + verify(notificationPanelViewController, times(1)).showAodUi() + } + + /** + * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal + * animation to start. If the device is woken up during the screen off, we should *never* do + * this. + * + * This test confirms that we do not show the AOD UI when the device is woken up during screen + * off (PowerManager#isInteractive = true). + */ + @Test + fun testAodUiNotShownIfInteractive() { + `when`(dozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true) + `when`(powerManager.isInteractive).thenReturn(true) + + val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java) + controller.onStartedGoingToSleep() + + mockingDetails(handler).printInvocations() + + verify(handler).postDelayed(callbackCaptor.capture(), anyLong()) + callbackCaptor.value.run() + + verify(notificationPanelViewController, never()).showAodUi() + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 15a92dcf26b7..ecfa1aaf49dd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -1275,6 +1275,22 @@ public class BubblesTest extends SysuiTestCase { assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } + @Test + public void testStackViewOnBackPressed_updatesBubbleDataExpandState() { + mBubbleController.updateBubble(mBubbleEntry); + + // Expand the stack + mBubbleData.setExpanded(true); + assertStackExpanded(); + + // Hit back + BubbleStackView stackView = mBubbleController.getStackView(); + stackView.onBackPressed(); + + // Make sure we're collapsed + assertStackCollapsed(); + } + /** Creates a bubble using the userId and package. */ private Bubble createBubble(int userId, String pkg) { final UserHandle userHandle = new UserHandle(userId); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java index 43b181ed3ab9..6207b76e840f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java @@ -1091,6 +1091,22 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } + @Test + public void testStackViewOnBackPressed_updatesBubbleDataExpandState() { + mBubbleController.updateBubble(mBubbleEntry); + + // Expand the stack + mBubbleData.setExpanded(true); + assertStackExpanded(); + + // Hit back + BubbleStackView stackView = mBubbleController.getStackView(); + stackView.onBackPressed(); + + // Make sure we're collapsed + assertStackCollapsed(); + } + /** * Sets the bubble metadata flags for this entry. These flags are normally set by * NotificationManagerService when the notification is sent, however, these tests do not diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index cbc2c0c6c8ac..22dd2c05c157 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -50,8 +50,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.util.MathUtils; -import android.util.MutableFloat; -import android.util.MutableInt; import android.util.Slog; import android.util.TimeUtils; import android.view.Display; @@ -1325,7 +1323,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Animate the screen brightness when the screen is on or dozing. // Skip the animation when the screen is off or suspended or transition to/from VR. - boolean brightnessAdjusted = false; if (!mPendingScreenOff) { if (mSkipScreenOnBrightnessRamp) { if (state == Display.STATE_ON) { @@ -1413,19 +1410,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // slider event so notify as if the system changed the brightness. userInitiatedChange = false; } - notifyBrightnessTrackerChanged(brightnessState, userInitiatedChange, + notifyBrightnessChanged(brightnessState, userInitiatedChange, hadUserBrightnessPoint); } // We save the brightness info *after* the brightness setting has been changed and // adjustments made so that the brightness info reflects the latest value. - brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting(), animateValue); + saveBrightnessInfo(getScreenBrightnessSetting(), animateValue); } else { - brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting()); - } - - if (brightnessAdjusted) { - postBrightnessChangeRunnable(); + saveBrightnessInfo(getScreenBrightnessSetting()); } // Log any changes to what is currently driving the brightness setting. @@ -1541,50 +1534,31 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call public BrightnessInfo getBrightnessInfo() { synchronized (mCachedBrightnessInfo) { return new BrightnessInfo( - mCachedBrightnessInfo.brightness.value, - mCachedBrightnessInfo.adjustedBrightness.value, - mCachedBrightnessInfo.brightnessMin.value, - mCachedBrightnessInfo.brightnessMax.value, - mCachedBrightnessInfo.hbmMode.value, - mCachedBrightnessInfo.hbmTransitionPoint.value); + mCachedBrightnessInfo.brightness, + mCachedBrightnessInfo.adjustedBrightness, + mCachedBrightnessInfo.brightnessMin, + mCachedBrightnessInfo.brightnessMax, + mCachedBrightnessInfo.hbmMode, + mCachedBrightnessInfo.highBrightnessTransitionPoint); } } - private boolean saveBrightnessInfo(float brightness) { - return saveBrightnessInfo(brightness, brightness); + private void saveBrightnessInfo(float brightness) { + saveBrightnessInfo(brightness, brightness); } - private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) { + private void saveBrightnessInfo(float brightness, float adjustedBrightness) { synchronized (mCachedBrightnessInfo) { - boolean changed = false; - - changed |= - mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightness, - brightness); - changed |= - mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.adjustedBrightness, - adjustedBrightness); - changed |= - mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMin, - mHbmController.getCurrentBrightnessMin()); - changed |= - mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMax, - mHbmController.getCurrentBrightnessMax()); - changed |= - mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode, - mHbmController.getHighBrightnessMode()); - changed |= - mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.hbmTransitionPoint, - mHbmController.getTransitionPoint()); - - return changed; + mCachedBrightnessInfo.brightness = brightness; + mCachedBrightnessInfo.adjustedBrightness = adjustedBrightness; + mCachedBrightnessInfo.brightnessMin = mHbmController.getCurrentBrightnessMin(); + mCachedBrightnessInfo.brightnessMax = mHbmController.getCurrentBrightnessMax(); + mCachedBrightnessInfo.hbmMode = mHbmController.getHighBrightnessMode(); + mCachedBrightnessInfo.highBrightnessTransitionPoint = + mHbmController.getTransitionPoint(); } } - void postBrightnessChangeRunnable() { - mHandler.post(mOnBrightnessChangeRunnable); - } - private HighBrightnessModeController createHbmControllerLocked() { final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig(); @@ -1597,7 +1571,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData, () -> { sendUpdatePowerStateLocked(); - postBrightnessChangeRunnable(); + mHandler.post(mOnBrightnessChangeRunnable); // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern. if (mAutomaticBrightnessController != null) { mAutomaticBrightnessController.update(); @@ -2099,7 +2073,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private void setCurrentScreenBrightness(float brightnessValue) { if (brightnessValue != mCurrentScreenBrightnessSetting) { mCurrentScreenBrightnessSetting = brightnessValue; - postBrightnessChangeRunnable(); + mHandler.post(mOnBrightnessChangeRunnable); } } @@ -2151,7 +2125,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call return true; } - private void notifyBrightnessTrackerChanged(float brightness, boolean userInitiated, + private void notifyBrightnessChanged(float brightness, boolean userInitiated, boolean hadUserDataPoint) { final float brightnessInNits = convertToNits(brightness); if (mPowerRequest.useAutoBrightness && brightnessInNits >= 0.0f @@ -2262,17 +2236,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call pw.println(" mColorFadeFadesConfig=" + mColorFadeFadesConfig); pw.println(" mColorFadeEnabled=" + mColorFadeEnabled); synchronized (mCachedBrightnessInfo) { - pw.println(" mCachedBrightnessInfo.brightness=" + - mCachedBrightnessInfo.brightness.value); + pw.println(" mCachedBrightnessInfo.brightness=" + mCachedBrightnessInfo.brightness); pw.println(" mCachedBrightnessInfo.adjustedBrightness=" + - mCachedBrightnessInfo.adjustedBrightness.value); + mCachedBrightnessInfo.adjustedBrightness); pw.println(" mCachedBrightnessInfo.brightnessMin=" + - mCachedBrightnessInfo.brightnessMin.value); + mCachedBrightnessInfo.brightnessMin); pw.println(" mCachedBrightnessInfo.brightnessMax=" + - mCachedBrightnessInfo.brightnessMax.value); - pw.println(" mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode.value); - pw.println(" mCachedBrightnessInfo.hbmTransitionPoint=" + - mCachedBrightnessInfo.hbmTransitionPoint.value); + mCachedBrightnessInfo.brightnessMax); + pw.println(" mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode); + pw.println(" mCachedBrightnessInfo.highBrightnessTransitionPoint=" + + mCachedBrightnessInfo.highBrightnessTransitionPoint); } pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig); pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig); @@ -2690,31 +2663,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } static class CachedBrightnessInfo { - public MutableFloat brightness = new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT); - public MutableFloat adjustedBrightness = - new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT); - public MutableFloat brightnessMin = - new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT); - public MutableFloat brightnessMax = - new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT); - public MutableInt hbmMode = new MutableInt(BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); - public MutableFloat hbmTransitionPoint = - new MutableFloat(HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID); - - public boolean checkAndSetFloat(MutableFloat mf, float f) { - if (mf.value != f) { - mf.value = f; - return true; - } - return false; - } - - public boolean checkAndSetInt(MutableInt mi, int i) { - if (mi.value != i) { - mi.value = i; - return true; - } - return false; - } + public float brightness; + public float adjustedBrightness; + public float brightnessMin; + public float brightnessMax; + public int hbmMode; + public float highBrightnessTransitionPoint; } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index a4fbb504beb1..f580bd078a0d 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2730,9 +2730,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } boolean isResizeable() { + return isResizeable(/* checkPictureInPictureSupport */ true); + } + + boolean isResizeable(boolean checkPictureInPictureSupport) { return mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(info.resizeMode) - || info.supportsPictureInPicture() + || (info.supportsPictureInPicture() && checkPictureInPictureSupport) // If the activity can be embedded, it should inherit the bounds of task fragment. || isEmbedded(); } @@ -6921,7 +6925,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override void prepareSurfaces() { - final boolean show = isVisible() || isAnimating(TRANSITION | PARENTS, + final boolean show = isVisible() || isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS); if (mSurfaceControl != null) { @@ -7691,10 +7695,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // orientation with insets applied. return; } - // Activity should be resizable if the task is. + // Not using Task#isResizeable() or ActivityRecord#isResizeable() directly because app + // compatibility testing showed that android:supportsPictureInPicture="true" alone is not + // sufficient signal for not letterboxing an app. + // TODO(214602463): Remove multi-window check since orientation and aspect ratio + // restrictions should always be applied in multi-window. final boolean isResizeable = task != null - ? task.isResizeable() || isResizeable() - : isResizeable(); + // Activity should be resizable if the task is. + ? task.isResizeable(/* checkPictureInPictureSupport */ false) + || isResizeable(/* checkPictureInPictureSupport */ false) + : isResizeable(/* checkPictureInPictureSupport */ false); if (WindowConfiguration.inMultiWindowMode(windowingMode) && isResizeable) { // Ignore orientation request for resizable apps in multi window. return; @@ -8223,8 +8233,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final float maxAspectRatio = info.getMaxAspectRatio(); final Task rootTask = getRootTask(); final float minAspectRatio = getMinAspectRatio(); + // Not using ActivityRecord#isResizeable() directly because app compatibility testing + // showed that android:supportsPictureInPicture="true" alone is not sufficient signal for + // not letterboxing an app. + // TODO(214602463): Remove multi-window check since orientation and aspect ratio + // restrictions should always be applied in multi-window. if (task == null || rootTask == null - || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets() + || (inMultiWindowMode() && isResizeable(/* checkPictureInPictureSupport */ false) && !fixedOrientationLetterboxed) || (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1) || isInVrUiMode(getConfiguration())) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 40549548da62..42c6dd43ebce 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1067,8 +1067,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mAppTransition = new AppTransition(mWmService.mContext, mWmService, this); mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier); - mTransitionController.registerLegacyListener( - mWmService.mActivityManagerAppTransitionNotifier); mAppTransition.registerListenerLocked(mFixedRotationTransitionListener); mAppTransitionController = new AppTransitionController(mWmService, this); mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this); @@ -4124,9 +4122,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * which controls the visibility and animation of the input method window. */ void updateImeInputAndControlTarget(WindowState target) { - if (target != null && target.mActivityRecord != null) { - target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false; - } if (mImeInputTarget != target) { ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target); setImeInputTarget(target); @@ -4134,6 +4129,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp .getRawInsetsState().getSourceOrDefaultVisibility(ITYPE_IME)); updateImeControlTarget(); } + // Unfreeze IME insets after the new target updated, in case updateAboveInsetsState may + // deliver unrelated IME insets change to the non-IME requester. + if (target != null && target.mActivityRecord != null) { + target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false; + } } void updateImeControlTarget() { diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 3d9061b63ff9..d69d32effc76 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -3315,6 +3315,7 @@ public class DisplayPolicy { } void release() { + mDisplayContent.mTransitionController.unregisterLegacyListener(mAppTransitionListener); mHandler.post(mGestureNavigationSettingsObserver::unregister); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index a8dd26e51911..632c63708549 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -2731,10 +2731,14 @@ class Task extends TaskFragment { } boolean isResizeable() { + return isResizeable(/* checkPictureInPictureSupport */ true); + } + + boolean isResizeable(boolean checkPictureInPictureSupport) { final boolean forceResizable = mAtmService.mForceResizableActivities && getActivityType() == ACTIVITY_TYPE_STANDARD; return forceResizable || ActivityInfo.isResizeableMode(mResizeMode) - || mSupportsPictureInPicture; + || (mSupportsPictureInPicture && checkPictureInPictureSupport); } /** diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index e05457010df8..929ec3b929b2 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -430,6 +430,10 @@ class TransitionController { mLegacyListeners.add(listener); } + void unregisterLegacyListener(WindowManagerInternal.AppTransitionListener listener) { + mLegacyListeners.remove(listener); + } + void dispatchLegacyAppTransitionPending() { for (int i = 0; i < mLegacyListeners.size(); ++i) { mLegacyListeners.get(i).onAppTransitionPendingLocked(); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 42766bdb0732..6970c7942a50 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -137,6 +137,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub void setWindowManager(WindowManagerService wms) { mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController); + mTransitionController.registerLegacyListener(wms.mActivityManagerAppTransitionNotifier); } TransitionController getTransitionController() { |