Merge cherrypicks of [16663837, 16663579, 16682031, 16458641] into sc-v2-release.
Change-Id: I8ce0dc7b246a5679496cb09166a636d7d51acddc
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -2722,9 +2722,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();
|
||||
}
|
||||
@@ -7679,10 +7683,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;
|
||||
@@ -8211,8 +8221,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())) {
|
||||
|
||||
@@ -4122,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);
|
||||
@@ -4132,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() {
|
||||
|
||||
@@ -2728,10 +2728,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -99,6 +99,7 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
||||
@@ -131,6 +132,7 @@ import android.view.IWindowManager;
|
||||
import android.view.IWindowSession;
|
||||
import android.view.InsetsSource;
|
||||
import android.view.InsetsState;
|
||||
import android.view.InsetsVisibilities;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.Surface;
|
||||
@@ -147,6 +149,7 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -3076,6 +3079,50 @@ public class ActivityRecordTests extends WindowTestsBase {
|
||||
assertEquals(state.getSource(ITYPE_IME).getFrame(), imeSource.getFrame());
|
||||
}
|
||||
|
||||
@UseTestDisplay(addWindows = {W_ACTIVITY, W_INPUT_METHOD})
|
||||
@Test
|
||||
public void testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest()
|
||||
throws RemoteException {
|
||||
final WindowState app1 = createWindow(null, TYPE_APPLICATION, "app1");
|
||||
final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
|
||||
|
||||
mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_IME).setWindow(
|
||||
mImeWindow, null, null);
|
||||
mImeWindow.getControllableInsetProvider().setServerVisible(true);
|
||||
|
||||
// Simulate app2 is closing and let app1 is visible to be IME targets.
|
||||
makeWindowVisibleAndDrawn(app1, mImeWindow);
|
||||
mDisplayContent.setImeLayeringTarget(app1);
|
||||
mDisplayContent.updateImeInputAndControlTarget(app1);
|
||||
app2.mActivityRecord.commitVisibility(false, false);
|
||||
|
||||
// app1 requests IME visible.
|
||||
final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
|
||||
requestedVisibilities.setVisibility(ITYPE_IME, true);
|
||||
app1.setRequestedVisibilities(requestedVisibilities);
|
||||
mDisplayContent.getInsetsStateController().onInsetsModified(app1);
|
||||
|
||||
// Verify app1's IME insets is visible and app2's IME insets frozen flag set.
|
||||
assertTrue(app1.getInsetsState().peekSource(ITYPE_IME).isVisible());
|
||||
assertTrue(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
|
||||
|
||||
// Simulate switching to app2 to make it visible to be IME targets.
|
||||
makeWindowVisibleAndDrawn(app2);
|
||||
spyOn(app2);
|
||||
spyOn(app2.mClient);
|
||||
ArgumentCaptor<InsetsState> insetsStateCaptor = ArgumentCaptor.forClass(InsetsState.class);
|
||||
doReturn(true).when(app2).isReadyToDispatchInsetsState();
|
||||
mDisplayContent.setImeLayeringTarget(app2);
|
||||
mDisplayContent.updateImeInputAndControlTarget(app2);
|
||||
|
||||
// Verify after unfreezing app2's IME insets state, we won't dispatch visible IME insets
|
||||
// to client if the app didn't request IME visible.
|
||||
assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
|
||||
verify(app2.mClient, atLeastOnce()).insetsChanged(insetsStateCaptor.capture(), anyBoolean(),
|
||||
anyBoolean());
|
||||
assertFalse(insetsStateCaptor.getAllValues().get(0).peekSource(ITYPE_IME).isVisible());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInClosingAnimation_doNotHideSurface() {
|
||||
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
||||
|
||||
Reference in New Issue
Block a user