summaryrefslogtreecommitdiff
path: root/libs/WindowManager/Shell
diff options
context:
space:
mode:
Diffstat (limited to 'libs/WindowManager/Shell')
-rw-r--r--libs/WindowManager/Shell/res/values-fa/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-nl/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings.xml2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java79
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java78
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java51
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java116
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java70
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java30
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java21
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java28
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java41
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java58
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java14
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java21
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java22
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java4
39 files changed, 749 insertions, 274 deletions
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index ca7d077e0ef0..f646039df1f8 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -45,7 +45,7 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"٪۵۰ بالا"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"٪۳۰ بالا"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"تمام‌صفحه پایین"</string>
- <string name="one_handed_tutorial_title" msgid="4583241688067426350">"استفاده از «حالت تک حرکت»"</string>
+ <string name="one_handed_tutorial_title" msgid="4583241688067426350">"استفاده از حالت یک‌دستی"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"برای خارج شدن، از پایین صفحه‌نمایش تند به‌طرف بالا بکشید یا در هر جایی از بالای برنامه که می‌خواهید ضربه بزنید"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"آغاز «حالت تک حرکت»"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"خروج از «حالت تک حرکت»"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 69fc25a378cf..06aaad7d65ca 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -45,10 +45,10 @@
<string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bovenste scherm 50%"</string>
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Bovenste scherm 30%"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Onderste scherm op volledig scherm"</string>
- <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Bediening met één hand gebruiken"</string>
+ <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Bediening met 1 hand gebruiken"</string>
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Als je wilt afsluiten, swipe je omhoog vanaf de onderkant van het scherm of tik je ergens boven de app"</string>
- <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Bediening met één hand starten"</string>
- <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Bediening met één hand afsluiten"</string>
+ <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Bediening met 1 hand starten"</string>
+ <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Bediening met 1 hand afsluiten"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"Instellingen voor <xliff:g id="APP_NAME">%1$s</xliff:g>-bubbels"</string>
<string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Overloop"</string>
<string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Weer toevoegen aan stack"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 0af8d24a1783..aa666531996d 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -46,7 +46,7 @@
<string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"以 30% 的螢幕空間顯示頂端畫面"</string>
<string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"以全螢幕顯示底部畫面"</string>
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"使用單手模式"</string>
- <string name="one_handed_tutorial_description" msgid="3486582858591353067">"如要退出,請從螢幕底部向上滑動,或輕觸應用程式上的任何位置"</string>
+ <string name="one_handed_tutorial_description" msgid="3486582858591353067">"如要退出,請從螢幕底部向上滑動,或輕觸應用程式上方的任何位置"</string>
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"啟動單手模式"</string>
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"結束單手模式"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」對話框的設定"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 4b1955e56a6c..8cdb434d4f74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -62,7 +62,8 @@ import java.util.function.Consumer;
* Unified task organizer for all components in the shell.
* TODO(b/167582004): may consider consolidating this class and TaskOrganizer
*/
-public class ShellTaskOrganizer extends TaskOrganizer {
+public class ShellTaskOrganizer extends TaskOrganizer implements
+ SizeCompatUIController.SizeCompatUICallback {
// Intentionally using negative numbers here so the positive numbers can be used
// for task id specific listeners that will be added later.
@@ -158,6 +159,9 @@ public class ShellTaskOrganizer extends TaskOrganizer {
Context context, @Nullable SizeCompatUIController sizeCompatUI) {
super(taskOrganizerController, mainExecutor);
mSizeCompatUI = sizeCompatUI;
+ if (sizeCompatUI != null) {
+ sizeCompatUI.setSizeCompatUICallback(this);
+ }
}
@Override
@@ -481,6 +485,17 @@ public class ShellTaskOrganizer extends TaskOrganizer {
}
}
+ @Override
+ public void onSizeCompatRestartButtonClicked(int taskId) {
+ final TaskAppearedInfo info;
+ synchronized (mLock) {
+ info = mTasks.get(taskId);
+ }
+ if (info != null) {
+ restartTaskTopActivityProcessIfVisible(info.getTaskInfo().token);
+ }
+ }
+
/**
* Notifies {@link SizeCompatUIController} about the size compat info changed on the give Task
* to update the UI accordingly.
@@ -499,13 +514,12 @@ public class ShellTaskOrganizer extends TaskOrganizer {
if (taskListener == null || !taskListener.supportSizeCompatUI()
|| !taskInfo.topActivityInSizeCompat) {
mSizeCompatUI.onSizeCompatInfoChanged(taskInfo.displayId, taskInfo.taskId,
- null /* taskConfig */, null /* sizeCompatActivity*/,
- null /* taskListener */);
+ null /* taskConfig */, null /* taskListener */);
return;
}
mSizeCompatUI.onSizeCompatInfoChanged(taskInfo.displayId, taskInfo.taskId,
- taskInfo.configuration, taskInfo.topActivityToken, taskListener);
+ taskInfo.configuration, taskListener);
}
private TaskListener getTaskListener(RunningTaskInfo runningTaskInfo) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index b2ac61cf3f6e..a7996f056785 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -42,8 +42,6 @@ import android.view.animation.PathInterpolator;
import androidx.annotation.BinderThread;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.inputmethod.Completable;
-import com.android.internal.inputmethod.ResultCallbacks;
import com.android.internal.view.IInputMethodManager;
import java.util.ArrayList;
@@ -159,6 +157,14 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
+ private void dispatchImeControlTargetChanged(int displayId, boolean controlling) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImeControlTargetChanged(displayId, controlling);
+ }
+ }
+ }
+
private void dispatchVisibilityChanged(int displayId, boolean isShowing) {
synchronized (mPositionProcessors) {
for (ImePositionProcessor pp : mPositionProcessors) {
@@ -237,38 +243,52 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
protected void insetsControlChanged(InsetsState insetsState,
InsetsSourceControl[] activeControls) {
insetsChanged(insetsState);
+ InsetsSourceControl imeSourceControl = null;
if (activeControls != null) {
for (InsetsSourceControl activeControl : activeControls) {
if (activeControl == null) {
continue;
}
if (activeControl.getType() == InsetsState.ITYPE_IME) {
- final Point lastSurfacePosition = mImeSourceControl != null
- ? mImeSourceControl.getSurfacePosition() : null;
- final boolean positionChanged =
- !activeControl.getSurfacePosition().equals(lastSurfacePosition);
- final boolean leashChanged =
- !haveSameLeash(mImeSourceControl, activeControl);
- mImeSourceControl = activeControl;
- if (mAnimation != null) {
- if (positionChanged) {
- startAnimation(mImeShowing, true /* forceRestart */);
- }
- } else {
- if (leashChanged) {
- applyVisibilityToLeash();
- }
- if (!mImeShowing) {
- removeImeSurface();
- }
- }
+ imeSourceControl = activeControl;
+ }
+ }
+ }
+
+ final boolean hadImeSourceControl = mImeSourceControl != null;
+ final boolean hasImeSourceControl = imeSourceControl != null;
+ if (hadImeSourceControl != hasImeSourceControl) {
+ dispatchImeControlTargetChanged(mDisplayId, hasImeSourceControl);
+ }
+
+ if (hasImeSourceControl) {
+ final Point lastSurfacePosition = mImeSourceControl != null
+ ? mImeSourceControl.getSurfacePosition() : null;
+ final boolean positionChanged =
+ !imeSourceControl.getSurfacePosition().equals(lastSurfacePosition);
+ final boolean leashChanged =
+ !haveSameLeash(mImeSourceControl, imeSourceControl);
+ if (mAnimation != null) {
+ if (positionChanged) {
+ startAnimation(mImeShowing, true /* forceRestart */);
+ }
+ } else {
+ if (leashChanged) {
+ applyVisibilityToLeash(imeSourceControl);
}
+ if (!mImeShowing) {
+ removeImeSurface();
+ }
+ }
+ if (mImeSourceControl != null) {
+ mImeSourceControl.release(SurfaceControl::release);
}
+ mImeSourceControl = imeSourceControl;
}
}
- private void applyVisibilityToLeash() {
- SurfaceControl leash = mImeSourceControl.getLeash();
+ private void applyVisibilityToLeash(InsetsSourceControl imeSourceControl) {
+ SurfaceControl leash = imeSourceControl.getLeash();
if (leash != null) {
SurfaceControl.Transaction t = mTransactionPool.acquire();
if (mImeShowing) {
@@ -518,9 +538,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
try {
// Remove the IME surface to make the insets invisible for
// non-client controlled insets.
- final Completable.Void value = Completable.createVoid();
- imms.removeImeSurface(ResultCallbacks.of(value));
- Completable.getResult(value);
+ imms.removeImeSurface();
} catch (RemoteException e) {
Slog.e(TAG, "Failed to remove IME surface.", e);
}
@@ -580,6 +598,15 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
/**
+ * Called when the IME control target changed. So that the processor can restore its
+ * adjusted layout when the IME insets is not controlling by the current controller anymore.
+ *
+ * @param controlling indicates whether the current controller is controlling IME insets.
+ */
+ default void onImeControlTargetChanged(int displayId, boolean controlling) {
+ }
+
+ /**
* Called when the IME visibility changed.
*
* @param isShowing {@code true} if the IME is shown.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index ef113dc5e10a..97c89d042be0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -134,6 +134,18 @@ public class SystemWindows {
}
/**
+ * Sets the accessibility window for the given {@param shellRootLayer}.
+ */
+ public void setShellRootAccessibilityWindow(int displayId,
+ @WindowManager.ShellRootLayer int shellRootLayer, View view) {
+ PerDisplay pd = mPerDisplay.get(displayId);
+ if (pd == null) {
+ return;
+ }
+ pd.setShellRootAccessibilityWindow(shellRootLayer, view);
+ }
+
+ /**
* Sets the touchable region of a view's window. This will be cropped to the window size.
* @param view
* @param region
@@ -202,15 +214,9 @@ public class SystemWindows {
attrs.flags |= FLAG_HARDWARE_ACCELERATED;
viewRoot.setView(view, attrs);
mViewRoots.put(view, viewRoot);
-
- try {
- mWmService.setShellRootAccessibilityWindow(mDisplayId, shellRootLayer,
- viewRoot.getWindowToken());
- } catch (RemoteException e) {
- Slog.e(TAG, "Error setting accessibility window for " + mDisplayId + ":"
- + shellRootLayer, e);
- }
+ setShellRootAccessibilityWindow(shellRootLayer, view);
}
+
SysUiWindowManager addRoot(@WindowManager.ShellRootLayer int shellRootLayer) {
SysUiWindowManager wwm = mWwms.get(shellRootLayer);
if (wwm != null) {
@@ -240,6 +246,21 @@ public class SystemWindows {
return wwm.mContainerWindow;
}
+ void setShellRootAccessibilityWindow(@WindowManager.ShellRootLayer int shellRootLayer,
+ View view) {
+ SysUiWindowManager wwm = mWwms.get(shellRootLayer);
+ if (wwm == null) {
+ return;
+ }
+ try {
+ mWmService.setShellRootAccessibilityWindow(mDisplayId, shellRootLayer,
+ view != null ? mViewRoots.get(view).getWindowToken() : null);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error setting accessibility window for " + mDisplayId + ":"
+ + shellRootLayer, e);
+ }
+ }
+
void updateConfiguration(Configuration configuration) {
for (int i = 0; i < mWwms.size(); ++i) {
mWwms.valueAt(i).updateConfiguration(configuration);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index e42f511eb391..5b158d2063ba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -366,6 +366,7 @@ public final class SplitLayout {
private final int mDisplayId;
+ private boolean mImeShown;
private int mYOffsetForIme;
private float mDimValue1;
private float mDimValue2;
@@ -392,6 +393,7 @@ public final class SplitLayout {
if (!mInitialized || imeTargetPosition == SPLIT_POSITION_UNDEFINED) return 0;
mStartImeTop = showing ? hiddenTop : shownTop;
mEndImeTop = showing ? shownTop : hiddenTop;
+ mImeShown = showing;
// Update target dim values
mLastDim1 = mDimValue1;
@@ -414,7 +416,7 @@ public final class SplitLayout {
mSplitWindowManager.setInteractive(
!showing || imeTargetPosition == SPLIT_POSITION_UNDEFINED);
- return 0;
+ return needOffset ? IME_ANIMATION_NO_ALPHA : 0;
}
@Override
@@ -432,6 +434,17 @@ public final class SplitLayout {
mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
}
+ @Override
+ public void onImeControlTargetChanged(int displayId, boolean controlling) {
+ if (displayId != mDisplayId) return;
+ // Restore the split layout when wm-shell is not controlling IME insets anymore.
+ if (!controlling && mImeShown) {
+ reset();
+ mSplitWindowManager.setInteractive(true);
+ mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+ }
+ }
+
private int getTargetYOffset() {
final int desireOffset = Math.abs(mEndImeTop - mStartImeTop);
// Make sure to keep at least 30% visible for the top split.
@@ -461,8 +474,10 @@ public final class SplitLayout {
}
private void reset() {
- mYOffsetForIme = 0;
- mDimValue1 = mDimValue2 = 0.0f;
+ mImeShown = false;
+ mYOffsetForIme = mLastYOffset = mTargetYOffset = 0;
+ mDimValue1 = mLastDim1 = mTargetDim1 = 0.0f;
+ mDimValue2 = mLastDim2 = mTargetDim2 = 0.0f;
}
/* Adjust bounds with IME offset. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
index 53dd391a01af..75a1ddeccb22 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
@@ -19,8 +19,8 @@ package com.android.wm.shell.hidedisplaycutout;
import static android.view.Display.DEFAULT_DISPLAY;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Insets;
-import android.graphics.Point;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.Log;
@@ -40,13 +40,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.internal.R;
-import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import java.io.PrintWriter;
import java.util.List;
-import java.util.concurrent.Executor;
/**
* Manages the display areas of hide display cutout feature.
@@ -76,19 +75,29 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer {
@VisibleForTesting
int mRotation;
- /**
- * Handles rotation based on OnDisplayChangingListener callback.
- */
- private final DisplayChangeController.OnDisplayChangingListener mRotationController =
- (display, fromRotation, toRotation, wct) -> {
- mRotation = toRotation;
- updateBoundsAndOffsets(true /* enable */);
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- applyAllBoundsAndOffsets(wct, t);
- // Only apply t here since the server will do the wct.apply when the method
- // finishes.
- t.apply();
- };
+ private final DisplayController.OnDisplaysChangedListener mListener =
+ new DisplayController.OnDisplaysChangedListener() {
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+ DisplayLayout displayLayout =
+ mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+ if (displayLayout == null) {
+ return;
+ }
+ final boolean rotationChanged = mRotation != displayLayout.rotation();
+ mRotation = displayLayout.rotation();
+ if (rotationChanged || isDisplayBoundsChanged()) {
+ updateBoundsAndOffsets(true /* enabled */);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ applyAllBoundsAndOffsets(wct, t);
+ applyTransaction(wct, t);
+ }
+ }
+ };
HideDisplayCutoutOrganizer(Context context, DisplayController displayController,
ShellExecutor mainExecutor) {
@@ -154,10 +163,10 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer {
* Enables hide display cutout.
*/
void enableHideDisplayCutout() {
- mDisplayController.addDisplayChangingController(mRotationController);
- final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY);
- if (display != null) {
- mRotation = display.getRotation();
+ mDisplayController.addDisplayWindowListener(mListener);
+ final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+ if (displayLayout != null) {
+ mRotation = displayLayout.rotation();
}
final List<DisplayAreaAppearedInfo> displayAreaInfos =
registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
@@ -174,7 +183,7 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer {
*/
void disableHideDisplayCutout() {
updateBoundsAndOffsets(false /* enabled */);
- mDisplayController.removeDisplayChangingController(mRotationController);
+ mDisplayController.removeDisplayWindowListener(mListener);
unregisterOrganizer();
}
@@ -193,23 +202,35 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer {
@VisibleForTesting
Rect getDisplayBoundsOfNaturalOrientation() {
- Point realSize = new Point(0, 0);
- final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY);
- if (display != null) {
- display.getRealSize(realSize);
+ final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+ if (displayLayout == null) {
+ return new Rect();
}
final boolean isDisplaySizeFlipped = isDisplaySizeFlipped();
return new Rect(
0,
0,
- isDisplaySizeFlipped ? realSize.y : realSize.x,
- isDisplaySizeFlipped ? realSize.x : realSize.y);
+ isDisplaySizeFlipped ? displayLayout.height() : displayLayout.width(),
+ isDisplaySizeFlipped ? displayLayout.width() : displayLayout.height());
}
private boolean isDisplaySizeFlipped() {
return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270;
}
+ private boolean isDisplayBoundsChanged() {
+ final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+ if (displayLayout == null) {
+ return false;
+ }
+ final boolean isDisplaySizeFlipped = isDisplaySizeFlipped();
+ final int width = isDisplaySizeFlipped ? displayLayout.height() : displayLayout.width();
+ final int height = isDisplaySizeFlipped ? displayLayout.width() : displayLayout.height();
+ return mDefaultDisplayBounds.isEmpty()
+ || mDefaultDisplayBounds.width() != width
+ || mDefaultDisplayBounds.height() != height;
+ }
+
/**
* Updates bounds and offsets according to current state.
*
@@ -237,7 +258,6 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer {
mCurrentDisplayBounds.right);
}
mCurrentDisplayBounds.inset(mCurrentCutoutInsets);
-
// Replace the top bound with the max(status bar height, cutout height) if there is
// cutout on the top side.
mStatusBarHeight = getStatusBarHeight();
@@ -256,7 +276,7 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer {
}
private void initDefaultValuesIfNeeded() {
- if (!mDefaultDisplayBounds.isEmpty()) {
+ if (!isDisplayBoundsChanged()) {
return;
}
mDefaultDisplayBounds.set(getDisplayBoundsOfNaturalOrientation());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java
index 23171bb9575c..aced072c8c71 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java
@@ -91,7 +91,6 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
private boolean mPaused = true;
private boolean mPausedTargetAdjusted = false;
- private boolean mAdjustedWhileHidden = false;
DividerImeController(LegacySplitScreenTaskListener splits, TransactionPool pool,
ShellExecutor mainExecutor, TaskOrganizer taskOrganizer) {
@@ -123,7 +122,6 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
void reset() {
mPaused = true;
mPausedTargetAdjusted = false;
- mAdjustedWhileHidden = false;
mAnimation = null;
mAdjusted = mTargetAdjusted = false;
mImeWasShown = mTargetShown = false;
@@ -140,6 +138,19 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
? ADJUSTED_NONFOCUS_DIM : 0.f;
}
+
+ @Override
+ public void onImeControlTargetChanged(int displayId, boolean controlling) {
+ // Restore the split layout when wm-shell is not controlling IME insets anymore.
+ if (!controlling && mTargetShown) {
+ mPaused = false;
+ mTargetAdjusted = mTargetShown = false;
+ mTargetPrimaryDim = mTargetSecondaryDim = 0.f;
+ updateImeAdjustState(true /* force */);
+ startAsyncAnimation();
+ }
+ }
+
@Override
@ImeAnimationFlags
public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
@@ -151,8 +162,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
mShownTop = shownTop;
mTargetShown = imeShouldShow;
mSecondaryHasFocus = getSecondaryHasFocus(displayId);
- final boolean splitIsVisible = !getView().isHidden();
- final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
+ final boolean targetAdjusted = imeShouldShow && mSecondaryHasFocus
&& !imeIsFloating && !getLayout().mDisplayLayout.isLandscape()
&& !mSplits.mSplitScreenController.isMinimized();
if (mLastAdjustTop < 0) {
@@ -176,7 +186,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
}
mTargetAdjusted = targetAdjusted;
updateDimTargets();
- if (DEBUG) Slog.d(TAG, " ime starting. vis:" + splitIsVisible + " " + dumpState());
+ if (DEBUG) Slog.d(TAG, " ime starting. " + dumpState());
if (mAnimation != null || (mImeWasShown && imeShouldShow
&& mTargetAdjusted != mAdjusted)) {
// We need to animate adjustment independently of the IME position, so
@@ -184,13 +194,8 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
// different split's editor has gained focus while the IME is still visible.
startAsyncAnimation();
}
- if (splitIsVisible) {
- // If split is hidden, we don't want to trigger any relayouts that would cause the
- // divider to show again.
- updateImeAdjustState();
- } else {
- mAdjustedWhileHidden = true;
- }
+ updateImeAdjustState();
+
return (mTargetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0;
}
@@ -256,11 +261,6 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
mSplits.mSplitScreenController.setAdjustedForIme(mTargetShown && !mPaused);
}
- public void updateAdjustForIme() {
- updateImeAdjustState(mAdjustedWhileHidden);
- mAdjustedWhileHidden = false;
- }
-
@Override
public void onImePositionChanged(int displayId, int imeTop,
SurfaceControl.Transaction t) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
index 7e4010d5fa6f..362b40f33e89 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
@@ -408,7 +408,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
boolean isHidden() {
- return mSurfaceHidden;
+ return getVisibility() != View.VISIBLE || mSurfaceHidden;
}
/** Starts dragging the divider bar. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
index 261ff2f8de83..80ab166d0649 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
@@ -146,10 +146,8 @@ public class LegacySplitScreenController implements DisplayController.OnDisplays
new LegacySplitDisplayLayout(mContext, displayLayout, mSplits);
sdl.rotateTo(toRotation);
mRotateSplitLayout = sdl;
- final int position = isDividerVisible()
- ? (mMinimized ? mView.mSnapTargetBeforeMinimized.position
- : mView.getCurrentPosition())
- // snap resets to middle target when not in split-mode
+ // snap resets to middle target when not minimized and rotation changed.
+ final int position = mMinimized ? mView.mSnapTargetBeforeMinimized.position
: sdl.getSnapAlgorithm().getMiddleTarget().position;
DividerSnapAlgorithm snap = sdl.getSnapAlgorithm();
final DividerSnapAlgorithm.SnapTarget target =
@@ -229,9 +227,6 @@ public class LegacySplitScreenController implements DisplayController.OnDisplays
return;
}
mView.setHidden(showing);
- if (!showing) {
- mImePositionProcessor.updateAdjustForIme();
- }
mIsKeyguardShowing = showing;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index b5c54023c492..1cc7ed3afcf7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -95,7 +95,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
private final OneHandedTouchHandler mTouchHandler;
private final OneHandedState mState;
private final OneHandedTutorialHandler mTutorialHandler;
- private final OneHandedUiEventLogger mOneHandedUiEventLogger;
private final TaskStackListenerImpl mTaskStackListener;
private final IOverlayManager mOverlayManager;
private final ShellExecutor mMainExecutor;
@@ -105,6 +104,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
private OneHandedEventCallback mEventCallback;
private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer;
+ private OneHandedUiEventLogger mOneHandedUiEventLogger;
/**
* Handle rotation based on OnDisplayChangingListener callback
@@ -115,6 +115,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
return;
}
mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation, wct);
+ mOneHandedUiEventLogger.writeEvent(
+ OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT);
};
private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener =
@@ -498,6 +500,11 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
@VisibleForTesting
void onActivatedActionChanged() {
+ if (!isShortcutEnabled()) {
+ Slog.w(TAG, "Shortcut not enabled, skip onActivatedActionChanged()");
+ return;
+ }
+
if (!isOneHandedEnabled()) {
final boolean success = mOneHandedSettingsUtil.setOneHandedModeEnabled(
mContext.getContentResolver(), 1 /* Enabled for shortcut */, mUserId);
@@ -586,6 +593,10 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
mContext.getContentResolver(), mUserId);
setSwipeToNotificationEnabled(enabled);
+ mOneHandedUiEventLogger.writeEvent(enabled
+ ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_ON
+ : OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_OFF);
+
// Also checks one handed mode settings since they all need gesture overlay.
setEnabledGesturalOverlay(
enabled || mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
@@ -608,6 +619,11 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
}
@VisibleForTesting
+ boolean isShortcutEnabled() {
+ return mOneHandedSettingsUtil.getShortcutEnabled(mContext.getContentResolver(), mUserId);
+ }
+
+ @VisibleForTesting
boolean isSwipeToNotificationEnabled() {
return mIsSwipeToNotificationEnabled;
}
@@ -617,8 +633,11 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
mMainExecutor.execute(() -> stopOneHanded());
}
- // Reset and align shortcut one_handed_mode_activated status with current mState
- notifyShortcutState(mState.getState());
+ // If setting is pull screen, notify shortcut one_handed_mode_activated to reset
+ // and align status with current mState when function enabled.
+ if (isOneHandedEnabled() && !isSwipeToNotificationEnabled()) {
+ notifyShortcutState(mState.getState());
+ }
mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled);
@@ -717,6 +736,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
pw.println(mLockedDisabled);
pw.print(innerPrefix + "mUserId=");
pw.println(mUserId);
+ pw.print(innerPrefix + "isShortcutEnabled=");
+ pw.println(isShortcutEnabled());
if (mBackgroundPanelOrganizer != null) {
mBackgroundPanelOrganizer.dump(pw);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index da53b359a304..3baa69f0033a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.onehanded;
+import static com.android.internal.accessibility.AccessibilityShortcutController.ONE_HANDED_COMPONENT_NAME;
+
import android.annotation.IntDef;
import android.content.ContentResolver;
import android.database.ContentObserver;
@@ -34,6 +36,9 @@ import java.lang.annotation.RetentionPolicy;
public final class OneHandedSettingsUtil {
private static final String TAG = "OneHandedSettingsUtil";
+ private static final String ONE_HANDED_MODE_TARGET_NAME =
+ ONE_HANDED_COMPONENT_NAME.getShortClassName();
+
@IntDef(prefix = {"ONE_HANDED_TIMEOUT_"}, value = {
ONE_HANDED_TIMEOUT_NEVER,
ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS,
@@ -158,6 +163,17 @@ public final class OneHandedSettingsUtil {
}
/**
+ * Queries one-handed mode shortcut enabled in settings or not.
+ *
+ * @return true if user enabled one-handed shortcut in settings, false otherwise.
+ */
+ public boolean getShortcutEnabled(ContentResolver resolver, int userId) {
+ final String targets = Settings.Secure.getStringForUser(resolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId);
+ return targets != null ? targets.contains(ONE_HANDED_MODE_TARGET_NAME) : false;
+ }
+
+ /**
* Sets tutorial shown counts.
*
* @return true if the value was set, false on database errors.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java
index 38ffb07aa5a4..4e610fad05ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java
@@ -50,6 +50,8 @@ public class OneHandedUiEventLogger {
public static final int EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4 = 15;
public static final int EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8 = 16;
public static final int EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12 = 17;
+ public static final int EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_ON = 18;
+ public static final int EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_OFF = 19;
private static final String[] EVENT_TAGS = {
"one_handed_trigger_gesture_in",
@@ -69,7 +71,9 @@ public class OneHandedUiEventLogger {
"one_handed_settings_timeout_seconds_never",
"one_handed_settings_timeout_seconds_4",
"one_handed_settings_timeout_seconds_8",
- "one_handed_settings_timeout_seconds_12"
+ "one_handed_settings_timeout_seconds_12",
+ "one_handed_settings_show_notification_enabled_on",
+ "one_handed_settings_show_notification_enabled_off"
};
public OneHandedUiEventLogger(UiEventLogger uiEventLogger) {
@@ -152,7 +156,13 @@ public class OneHandedUiEventLogger {
ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_8(364),
@UiEvent(doc = "One-Handed mode timeout value changed to 12 seconds")
- ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_12(365);
+ ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_12(365),
+
+ @UiEvent(doc = "One-Handed mode show notification toggle on")
+ ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_ON(847),
+
+ @UiEvent(doc = "One-Handed mode show notification toggle off")
+ ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_OFF(848);
private final int mId;
@@ -247,6 +257,14 @@ public class OneHandedUiEventLogger {
mUiEventLogger.log(OneHandedSettingsTogglesEvent
.ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_12);
break;
+ case EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_ON:
+ mUiEventLogger.log(OneHandedSettingsTogglesEvent
+ .ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_ON);
+ break;
+ case EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_OFF:
+ mUiEventLogger.log(OneHandedSettingsTogglesEvent
+ .ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_OFF);
+ break;
default:
// Do nothing
break;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index 046c32071358..a4b866aa3f5e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.pip;
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.PictureInPictureParams;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -454,6 +455,56 @@ public class PipBoundsAlgorithm {
}
/**
+ * @return the normal bounds adjusted so that they fit the menu actions.
+ */
+ public Rect adjustNormalBoundsToFitMenu(@NonNull Rect normalBounds,
+ @Nullable Size minMenuSize) {
+ if (minMenuSize == null) {
+ return normalBounds;
+ }
+ if (normalBounds.width() >= minMenuSize.getWidth()
+ && normalBounds.height() >= minMenuSize.getHeight()) {
+ // The normal bounds can fit the menu as is, no need to adjust the bounds.
+ return normalBounds;
+ }
+ final Rect adjustedNormalBounds = new Rect();
+ final boolean needsWidthAdj = minMenuSize.getWidth() > normalBounds.width();
+ final boolean needsHeightAdj = minMenuSize.getHeight() > normalBounds.height();
+ final int adjWidth;
+ final int adjHeight;
+ if (needsWidthAdj && needsHeightAdj) {
+ // Both the width and the height are too small - find the edge that needs the larger
+ // adjustment and scale that edge. The other edge will scale beyond the minMenuSize
+ // when the aspect ratio is applied.
+ final float widthScaleFactor =
+ ((float) (minMenuSize.getWidth())) / ((float) (normalBounds.width()));
+ final float heightScaleFactor =
+ ((float) (minMenuSize.getHeight())) / ((float) (normalBounds.height()));
+ if (widthScaleFactor > heightScaleFactor) {
+ adjWidth = minMenuSize.getWidth();
+ adjHeight = Math.round(adjWidth / mPipBoundsState.getAspectRatio());
+ } else {
+ adjHeight = minMenuSize.getHeight();
+ adjWidth = Math.round(adjHeight * mPipBoundsState.getAspectRatio());
+ }
+ } else if (needsWidthAdj) {
+ // Width is too small - use the min menu size width instead.
+ adjWidth = minMenuSize.getWidth();
+ adjHeight = Math.round(adjWidth / mPipBoundsState.getAspectRatio());
+ } else {
+ // Height is too small - use the min menu size height instead.
+ adjHeight = minMenuSize.getHeight();
+ adjWidth = Math.round(adjHeight * mPipBoundsState.getAspectRatio());
+ }
+ adjustedNormalBounds.set(0, 0, adjWidth, adjHeight);
+ // Make sure the bounds conform to the aspect ratio and min edge size.
+ transformBoundsToAspectRatio(adjustedNormalBounds,
+ mPipBoundsState.getAspectRatio(), true /* useCurrentMinEdgeSize */,
+ true /* useCurrentSize */);
+ return adjustedNormalBounds;
+ }
+
+ /**
* Dumps internal states.
*/
public void dump(PrintWriter pw, String prefix) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 324a6e27a242..f367cd608f37 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -722,6 +722,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
}
+
+ final PipAnimationController.PipTransitionAnimator animator =
+ mPipAnimationController.getCurrentAnimator();
+ if (animator != null) {
+ animator.removeAllUpdateListeners();
+ animator.removeAllListeners();
+ animator.cancel();
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index bc8e1e72b830..a646b07c49dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -524,6 +524,15 @@ public class PhonePipMenuController implements PipMenuController {
mListeners.forEach(l -> l.onPipMenuStateChangeFinish(menuState));
}
mMenuState = menuState;
+ switch (mMenuState) {
+ case MENU_STATE_NONE:
+ mSystemWindows.setShellRootAccessibilityWindow(0, SHELL_ROOT_LAYER_PIP, null);
+ break;
+ default:
+ mSystemWindows.setShellRootAccessibilityWindow(0, SHELL_ROOT_LAYER_PIP,
+ mPipMenuView);
+ break;
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index f0bd8a2846ed..c816f18c2fc2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -246,10 +246,20 @@ public class PipResizeGestureHandler {
}
if (ev instanceof MotionEvent) {
+ MotionEvent mv = (MotionEvent) ev;
+ int action = mv.getActionMasked();
+ final Rect pipBounds = mPipBoundsState.getBounds();
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ if (!pipBounds.contains((int) mv.getRawX(), (int) mv.getRawY())
+ && mPhonePipMenuController.isMenuVisible()) {
+ mPhonePipMenuController.hideMenu();
+ }
+ }
+
if (mEnablePinchResize && mOngoingPinchToResize) {
- onPinchResize((MotionEvent) ev);
+ onPinchResize(mv);
} else if (mEnableDragCornerResize) {
- onDragCornerResize((MotionEvent) ev);
+ onDragCornerResize(mv);
}
}
}
@@ -450,7 +460,6 @@ public class PipResizeGestureHandler {
float x = ev.getX();
float y = ev.getY() - mOhmOffset;
if (action == MotionEvent.ACTION_DOWN) {
- final Rect currentPipBounds = mPipBoundsState.getBounds();
mLastResizeBounds.setEmpty();
mAllowGesture = isInValidSysUiState() && isWithinDragResizeRegion((int) x, (int) y);
if (mAllowGesture) {
@@ -458,11 +467,6 @@ public class PipResizeGestureHandler {
mDownPoint.set(x, y);
mDownBounds.set(mPipBoundsState.getBounds());
}
- if (!currentPipBounds.contains((int) x, (int) y)
- && mPhonePipMenuController.isMenuVisible()) {
- mPhonePipMenuController.hideMenu();
- }
-
} else if (mAllowGesture) {
switch (action) {
case MotionEvent.ACTION_POINTER_DOWN:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index b1086c575f49..0bcd1a363eb6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -726,12 +726,17 @@ public class PipTouchHandler {
}
private void animateToNormalSize(Runnable callback) {
+ // Save the current bounds as the user-resize bounds.
mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
- final Rect normalBounds = new Rect(mPipBoundsState.getNormalBounds());
+
+ final Size minMenuSize = mMenuController.getEstimatedMinMenuSize();
+ final Rect normalBounds = mPipBoundsState.getNormalBounds();
+ final Rect destBounds = mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds,
+ minMenuSize);
Rect restoredMovementBounds = new Rect();
- mPipBoundsAlgorithm.getMovementBounds(normalBounds,
+ mPipBoundsAlgorithm.getMovementBounds(destBounds,
mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
- mSavedSnapFraction = mMotionHelper.animateToExpandedState(normalBounds,
+ mSavedSnapFraction = mMotionHelper.animateToExpandedState(destBounds,
mPipBoundsState.getMovementBounds(), restoredMovementBounds, callback);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 70980191f103..a2e9b64046fd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -279,7 +279,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
private void checkIfPinnedTaskAppeared() {
final TaskInfo pinnedTask = getPinnedTaskInfo();
if (DEBUG) Log.d(TAG, "checkIfPinnedTaskAppeared(), task=" + pinnedTask);
- if (pinnedTask == null) return;
+ if (pinnedTask == null || pinnedTask.topActivity == null) return;
mPinnedTaskId = pinnedTask.taskId;
setState(STATE_PIP);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
index c981adee9b5c..1fc4d12def1f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
@@ -20,7 +20,6 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
-import android.os.IBinder;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
@@ -45,6 +44,13 @@ import java.util.function.Consumer;
*/
public class SizeCompatUIController implements DisplayController.OnDisplaysChangedListener,
DisplayImeController.ImePositionProcessor {
+
+ /** Callback for size compat UI interaction. */
+ public interface SizeCompatUICallback {
+ /** Called when the size compat restart button is clicked. */
+ void onSizeCompatRestartButtonClicked(int taskId);
+ }
+
private static final String TAG = "SizeCompatUIController";
/** Whether the IME is shown on display id. */
@@ -61,6 +67,8 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
private final DisplayImeController mImeController;
private final SyncTransactionQueue mSyncQueue;
+ private SizeCompatUICallback mCallback;
+
/** Only show once automatically in the process life. */
private boolean mHasShownHint;
@@ -76,29 +84,31 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
mImeController.addPositionProcessor(this);
}
+ /** Sets the callback for UI interactions. */
+ public void setSizeCompatUICallback(SizeCompatUICallback callback) {
+ mCallback = callback;
+ }
+
/**
* Called when the Task info changed. Creates and updates the size compat UI if there is an
* activity in size compat, or removes the UI if there is no size compat activity.
- *
* @param displayId display the task and activity are in.
* @param taskId task the activity is in.
* @param taskConfig task config to place the size compat UI with.
- * @param sizeCompatActivity the size compat activity in the task. Can be {@code null} if the
- * top activity in this Task is not in size compat.
* @param taskListener listener to handle the Task Surface placement.
*/
public void onSizeCompatInfoChanged(int displayId, int taskId,
- @Nullable Configuration taskConfig, @Nullable IBinder sizeCompatActivity,
+ @Nullable Configuration taskConfig,
@Nullable ShellTaskOrganizer.TaskListener taskListener) {
- if (taskConfig == null || sizeCompatActivity == null || taskListener == null) {
+ if (taskConfig == null || taskListener == null) {
// Null token means the current foreground activity is not in size compatibility mode.
removeLayout(taskId);
} else if (mActiveLayouts.contains(taskId)) {
// UI already exists, update the UI layout.
- updateLayout(taskId, taskConfig, sizeCompatActivity, taskListener);
+ updateLayout(taskId, taskConfig, taskListener);
} else {
// Create a new size compat UI.
- createLayout(displayId, taskId, taskConfig, sizeCompatActivity, taskListener);
+ createLayout(displayId, taskId, taskConfig, taskListener);
}
}
@@ -137,7 +147,7 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
}
private void createLayout(int displayId, int taskId, Configuration taskConfig,
- IBinder activityToken, ShellTaskOrganizer.TaskListener taskListener) {
+ ShellTaskOrganizer.TaskListener taskListener) {
final Context context = getOrCreateDisplayContext(displayId);
if (context == null) {
Log.e(TAG, "Cannot get context for display " + displayId);
@@ -145,17 +155,16 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
}
final SizeCompatUILayout layout = createLayout(context, displayId, taskId, taskConfig,
- activityToken, taskListener);
+ taskListener);
mActiveLayouts.put(taskId, layout);
layout.createSizeCompatButton(isImeShowingOnDisplay(displayId));
}
@VisibleForTesting
SizeCompatUILayout createLayout(Context context, int displayId, int taskId,
- Configuration taskConfig, IBinder activityToken,
- ShellTaskOrganizer.TaskListener taskListener) {
- final SizeCompatUILayout layout = new SizeCompatUILayout(mSyncQueue, context, taskConfig,
- taskId, activityToken, taskListener, mDisplayController.getDisplayLayout(displayId),
+ Configuration taskConfig, ShellTaskOrganizer.TaskListener taskListener) {
+ final SizeCompatUILayout layout = new SizeCompatUILayout(mSyncQueue, mCallback, context,
+ taskConfig, taskId, taskListener, mDisplayController.getDisplayLayout(displayId),
mHasShownHint);
// Only show hint for the first time.
mHasShownHint = true;
@@ -163,13 +172,12 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
}
private void updateLayout(int taskId, Configuration taskConfig,
- IBinder sizeCompatActivity,
ShellTaskOrganizer.TaskListener taskListener) {
final SizeCompatUILayout layout = mActiveLayouts.get(taskId);
if (layout == null) {
return;
}
- layout.updateSizeCompatInfo(taskConfig, sizeCompatActivity, taskListener,
+ layout.updateSizeCompatInfo(taskConfig, taskListener,
isImeShowingOnDisplay(layout.getDisplayId()));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
index c6d994ecde8d..a5e96d14dde6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
@@ -23,13 +23,11 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERL
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import android.annotation.Nullable;
-import android.app.ActivityClient;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Binder;
-import android.os.IBinder;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
@@ -48,11 +46,11 @@ class SizeCompatUILayout {
private static final String TAG = "SizeCompatUILayout";
private final SyncTransactionQueue mSyncQueue;
+ private final SizeCompatUIController.SizeCompatUICallback mCallback;
private Context mContext;
private Configuration mTaskConfig;
private final int mDisplayId;
private final int mTaskId;
- private IBinder mActivityToken;
private ShellTaskOrganizer.TaskListener mTaskListener;
private DisplayLayout mDisplayLayout;
@@ -72,15 +70,16 @@ class SizeCompatUILayout {
final int mPopupOffsetY;
boolean mShouldShowHint;
- SizeCompatUILayout(SyncTransactionQueue syncQueue, Context context, Configuration taskConfig,
- int taskId, IBinder activityToken, ShellTaskOrganizer.TaskListener taskListener,
+ SizeCompatUILayout(SyncTransactionQueue syncQueue,
+ SizeCompatUIController.SizeCompatUICallback callback, Context context,
+ Configuration taskConfig, int taskId, ShellTaskOrganizer.TaskListener taskListener,
DisplayLayout displayLayout, boolean hasShownHint) {
mSyncQueue = syncQueue;
+ mCallback = callback;
mContext = context.createConfigurationContext(taskConfig);
mTaskConfig = taskConfig;
mDisplayId = mContext.getDisplayId();
mTaskId = taskId;
- mActivityToken = activityToken;
mTaskListener = taskListener;
mDisplayLayout = displayLayout;
mShouldShowHint = !hasShownHint;
@@ -141,12 +140,11 @@ class SizeCompatUILayout {
}
/** Called when size compat info changed. */
- void updateSizeCompatInfo(Configuration taskConfig, IBinder activityToken,
+ void updateSizeCompatInfo(Configuration taskConfig,
ShellTaskOrganizer.TaskListener taskListener, boolean isImeShowing) {
final Configuration prevTaskConfig = mTaskConfig;
final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener;
mTaskConfig = taskConfig;
- mActivityToken = activityToken;
mTaskListener = taskListener;
// Update configuration.
@@ -253,7 +251,7 @@ class SizeCompatUILayout {
/** Called when the restart button is clicked. */
void onRestartButtonClicked() {
- ActivityClient.getInstance().restartActivityProcessIfVisible(mActivityToken);
+ mCallback.onSizeCompatRestartButtonClicked(mTaskId);
}
/** Called when the restart button is long clicked. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
index 9986154b051d..4e477ca104dd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
@@ -85,7 +85,10 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
}
View iconView = view.getIconView();
- if (iconView == null || iconView.getBackground() == null) {
+
+ // If the icon and the background are invisible, don't animate it
+ if (iconView == null || iconView.getLayoutParams().width == 0
+ || iconView.getLayoutParams().height == 0) {
mIconFadeOutDuration = 0;
mIconStartAlpha = 0;
mAppRevealDelay = 0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index df3fee043419..75dd561ffc61 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -18,6 +18,9 @@ package com.android.wm.shell.startingsurface;
import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
import android.annotation.ColorInt;
import android.annotation.NonNull;
@@ -47,6 +50,7 @@ import android.util.Slog;
import android.view.SurfaceControl;
import android.view.View;
import android.window.SplashScreenView;
+import android.window.StartingWindowInfo.StartingWindowType;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -77,6 +81,13 @@ public class SplashscreenContentDrawer {
// For example, an icon with the foreground 108*108 opaque pixels and it's background
// also 108*108 pixels, then do not enlarge this icon if only need to show foreground icon.
private static final float ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f);
+
+ /**
+ * If the developer doesn't specify a background for the icon, we slightly scale it up.
+ *
+ * The background is either manually specified in the theme or the Adaptive Icon
+ * background is used if it's different from the window background.
+ */
private static final float NO_BACKGROUND_SCALE = 192f / 160;
private final Context mContext;
private final IconProvider mIconProvider;
@@ -115,17 +126,17 @@ public class SplashscreenContentDrawer {
* view on background thread so the view and the drawable can be create and pre-draw in
* parallel.
*
- * @param emptyView Create a splash screen view without icon on it.
+ * @param suggestType Suggest type to create the splash screen view.
* @param consumer Receiving the SplashScreenView object, which will also be executed
* on splash screen thread. Note that the view can be null if failed.
*/
- void createContentView(Context context, boolean emptyView, ActivityInfo info, int taskId,
- Consumer<SplashScreenView> consumer) {
+ void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info,
+ int taskId, Consumer<SplashScreenView> consumer) {
mSplashscreenWorkerHandler.post(() -> {
SplashScreenView contentView;
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView");
- contentView = makeSplashScreenContentView(context, info, emptyView);
+ contentView = makeSplashScreenContentView(context, info, suggestType);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} catch (RuntimeException e) {
Slog.w(TAG, "failed creating starting window content at taskId: "
@@ -192,22 +203,45 @@ public class SplashscreenContentDrawer {
}
}
+ private static Drawable peekLegacySplashscreenContent(Context context,
+ SplashScreenWindowAttrs attrs) {
+ final TypedArray a = context.obtainStyledAttributes(R.styleable.Window);
+ final int resId = safeReturnAttrDefault((def) ->
+ a.getResourceId(R.styleable.Window_windowSplashscreenContent, def), 0);
+ a.recycle();
+ if (resId != 0) {
+ return context.getDrawable(resId);
+ }
+ if (attrs.mWindowBgResId != 0) {
+ return context.getDrawable(attrs.mWindowBgResId);
+ }
+ return null;
+ }
+
private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai,
- boolean emptyView) {
+ @StartingWindowType int suggestType) {
updateDensity();
getWindowAttrs(context, mTmpAttrs);
mLastPackageContextConfigHash = context.getResources().getConfiguration().hashCode();
- final int themeBGColor = mColorCache.getWindowColor(ai.packageName,
- mLastPackageContextConfigHash, mTmpAttrs.mWindowBgColor, mTmpAttrs.mWindowBgResId,
- () -> peekWindowBGColor(context, mTmpAttrs)).mBgColor;
- // TODO (b/173975965) Tracking the performance on improved splash screen.
+
+ final Drawable legacyDrawable = suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
+ ? peekLegacySplashscreenContent(context, mTmpAttrs) : null;
+ final int themeBGColor = legacyDrawable != null
+ ? getBGColorFromCache(ai, () -> estimateWindowBGColor(legacyDrawable))
+ : getBGColorFromCache(ai, () -> peekWindowBGColor(context, mTmpAttrs));
return new StartingWindowViewBuilder(context, ai)
.setWindowBGColor(themeBGColor)
- .makeEmptyView(emptyView)
+ .overlayDrawable(legacyDrawable)
+ .chooseStyle(suggestType)
.build();
}
+ private int getBGColorFromCache(ActivityInfo ai, IntSupplier windowBgColorSupplier) {
+ return mColorCache.getWindowColor(ai.packageName, mLastPackageContextConfigHash,
+ mTmpAttrs.mWindowBgColor, mTmpAttrs.mWindowBgResId, windowBgColorSupplier).mBgColor;
+ }
+
private static <T> T safeReturnAttrDefault(UnaryOperator<T> getMethod, T def) {
try {
return getMethod.apply(def);
@@ -228,7 +262,7 @@ public class SplashscreenContentDrawer {
attrs.mWindowBgColor = safeReturnAttrDefault((def) -> typedArray.getColor(
R.styleable.Window_windowSplashScreenBackground, def),
Color.TRANSPARENT);
- attrs.mReplaceIcon = safeReturnAttrDefault((def) -> typedArray.getDrawable(
+ attrs.mSplashScreenIcon = safeReturnAttrDefault((def) -> typedArray.getDrawable(
R.styleable.Window_windowSplashScreenAnimatedIcon), null);
attrs.mAnimationDuration = safeReturnAttrDefault((def) -> typedArray.getInt(
R.styleable.Window_windowSplashScreenAnimationDuration, def), 0);
@@ -241,7 +275,7 @@ public class SplashscreenContentDrawer {
if (DEBUG) {
Slog.d(TAG, "window attributes color: "
+ Integer.toHexString(attrs.mWindowBgColor)
- + " icon " + attrs.mReplaceIcon + " duration " + attrs.mAnimationDuration
+ + " icon " + attrs.mSplashScreenIcon + " duration " + attrs.mAnimationDuration
+ " brandImage " + attrs.mBrandingImage);
}
}
@@ -250,7 +284,7 @@ public class SplashscreenContentDrawer {
public static class SplashScreenWindowAttrs {
private int mWindowBgResId = 0;
private int mWindowBgColor = Color.TRANSPARENT;
- private Drawable mReplaceIcon = null;
+ private Drawable mSplashScreenIcon = null;
private Drawable mBrandingImage = null;
private int mIconBgColor = Color.TRANSPARENT;
private int mAnimationDuration = 0;
@@ -260,7 +294,8 @@ public class SplashscreenContentDrawer {
private final Context mContext;
private final ActivityInfo mActivityInfo;
- private boolean mEmptyView;
+ private Drawable mOverlayDrawable;
+ private int mSuggestType;
private int mThemeColor;
private Drawable mFinalIconDrawable;
private int mFinalIconSize = mIconSize;
@@ -275,22 +310,33 @@ public class SplashscreenContentDrawer {
return this;
}
- StartingWindowViewBuilder makeEmptyView(boolean empty) {
- mEmptyView = empty;
+ StartingWindowViewBuilder overlayDrawable(Drawable overlay) {
+ mOverlayDrawable = overlay;
+ return this;
+ }
+
+ StartingWindowViewBuilder chooseStyle(int suggestType) {
+ mSuggestType = suggestType;
return this;
}
SplashScreenView build() {
Drawable iconDrawable;
final int animationDuration;
- if (mEmptyView) {
- // empty splash screen case
+ if (mSuggestType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN
+ || mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
+ // empty or legacy splash screen case
animationDuration = 0;
mFinalIconSize = 0;
- } else if (mTmpAttrs.mReplaceIcon != null) {
+ } else if (mTmpAttrs.mSplashScreenIcon != null) {
// replaced icon, don't process
- iconDrawable = mTmpAttrs.mReplaceIcon;
+ iconDrawable = mTmpAttrs.mSplashScreenIcon;
animationDuration = mTmpAttrs.mAnimationDuration;
+
+ // There is no background below the icon, so scale the icon up
+ if (mTmpAttrs.mIconBgColor == Color.TRANSPARENT) {
+ mFinalIconSize *= NO_BACKGROUND_SCALE;
+ }
createIconDrawable(iconDrawable, false);
} else {
final float iconScale = (float) mIconSize / (float) mDefaultIconSize;
@@ -391,13 +437,15 @@ public class SplashscreenContentDrawer {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon");
final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext);
builder.setBackgroundColor(mThemeColor);
+ builder.setOverlayDrawable(mOverlayDrawable);
if (iconDrawable != null) {
builder.setIconSize(iconSize)
.setIconBackground(mTmpAttrs.mIconBgColor)
.setCenterViewDrawable(iconDrawable)
.setAnimationDurationMillis(animationDuration);
}
- if (mTmpAttrs.mBrandingImage != null) {
+ if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN
+ && mTmpAttrs.mBrandingImage != null) {
builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth,
mBrandingImageHeight);
}
@@ -405,20 +453,22 @@ public class SplashscreenContentDrawer {
if (DEBUG) {
Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView);
}
- if (mEmptyView) {
- splashScreenView.setNotCopyable();
+ if (mSuggestType != STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
+ splashScreenView.addOnAttachStateChangeListener(
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ SplashScreenView.applySystemBarsContrastColor(
+ v.getWindowInsetsController(),
+ splashScreenView.getInitBackgroundColor());
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ }
+ });
}
- splashScreenView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- SplashScreenView.applySystemBarsContrastColor(v.getWindowInsetsController(),
- splashScreenView.getInitBackgroundColor());
- }
- @Override
- public void onViewDetachedFromWindow(View v) {
- }
- });
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return splashScreenView;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index dae7055ede53..211941f44c8e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -162,6 +162,7 @@ public class SplashscreenIconDrawableFactory {
@Override
public void draw(Canvas canvas) {
+ canvas.clipPath(mMaskScaleOnly);
if (mMaskScaleOnly != null) {
canvas.drawPath(mMaskScaleOnly, mPaint);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 46db35a6e29f..4dc5447cbe65 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -20,6 +20,8 @@ import static android.content.Context.CONTEXT_RESTRICTED;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Choreographer.CALLBACK_INSETS_ANIMATION;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
@@ -32,7 +34,6 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
import android.os.RemoteCallback;
@@ -50,6 +51,7 @@ import android.widget.FrameLayout;
import android.window.SplashScreenView;
import android.window.SplashScreenView.SplashScreenViewParcelable;
import android.window.StartingWindowInfo;
+import android.window.StartingWindowInfo.StartingWindowType;
import android.window.TaskSnapshot;
import com.android.internal.R;
@@ -149,10 +151,11 @@ public class StartingSurfaceDrawer {
/**
* Called when a task need a splash screen starting window.
- * @param emptyView Whether drawing an empty frame without anything on it.
+ *
+ * @param suggestType The suggestion type to draw the splash screen.
*/
void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken,
- boolean emptyView) {
+ @StartingWindowType int suggestType) {
final RunningTaskInfo taskInfo = windowInfo.taskInfo;
final ActivityInfo activityInfo = taskInfo.topActivityInfo;
if (activityInfo == null) {
@@ -173,7 +176,8 @@ public class StartingSurfaceDrawer {
: com.android.internal.R.style.Theme_DeviceDefault_DayNight;
if (DEBUG_SPLASH_SCREEN) {
Slog.d(TAG, "addSplashScreen " + activityInfo.packageName
- + " theme=" + Integer.toHexString(theme) + " task= " + taskInfo.taskId);
+ + " theme=" + Integer.toHexString(theme) + " task=" + taskInfo.taskId
+ + " suggestType=" + suggestType);
}
// Obtain proper context to launch on the right display.
@@ -231,13 +235,19 @@ public class StartingSurfaceDrawer {
params.setFitInsetsTypes(0);
params.format = PixelFormat.TRANSLUCENT;
int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
- | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
final TypedArray a = context.obtainStyledAttributes(R.styleable.Window);
if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
}
+ if (suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
+ if (a.getBoolean(R.styleable.Window_windowDrawsSystemBarBackgrounds, false)) {
+ windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ }
+ } else {
+ windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ }
params.layoutInDisplayCutoutMode = a.getInt(
R.styleable.Window_windowLayoutInDisplayCutoutMode,
params.layoutInDisplayCutoutMode);
@@ -288,6 +298,8 @@ public class StartingSurfaceDrawer {
// create splash screen view finished.
final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier();
final FrameLayout rootLayout = new FrameLayout(context);
+ rootLayout.setPadding(0, 0, 0, 0);
+ rootLayout.setFitsSystemWindows(false);
final Runnable setViewSynchronized = () -> {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addSplashScreenView");
// waiting for setContentView before relayoutWindow
@@ -310,12 +322,12 @@ public class StartingSurfaceDrawer {
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
};
- mSplashscreenContentDrawer.createContentView(context, emptyView, activityInfo, taskId,
+ mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId,
viewSupplier::setView);
try {
final WindowManager wm = context.getSystemService(WindowManager.class);
- if (addWindow(taskId, appToken, rootLayout, wm, params)) {
+ if (addWindow(taskId, appToken, rootLayout, wm, params, suggestType)) {
// We use the splash screen worker thread to create SplashScreenView while adding
// the window, as otherwise Choreographer#doFrame might be delayed on this thread.
// And since Choreographer#doFrame won't happen immediately after adding the window,
@@ -335,8 +347,10 @@ public class StartingSurfaceDrawer {
int getStartingWindowBackgroundColorForTask(int taskId) {
StartingWindowRecord startingWindowRecord = mStartingWindowRecords.get(taskId);
- if (startingWindowRecord == null || startingWindowRecord.mContentView == null) return 0;
- return ((ColorDrawable) startingWindowRecord.mContentView.getBackground()).getColor();
+ if (startingWindowRecord == null || startingWindowRecord.mContentView == null) {
+ return 0;
+ }
+ return startingWindowRecord.mContentView.getInitBackgroundColor();
}
private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> {
@@ -378,7 +392,7 @@ public class StartingSurfaceDrawer {
return;
}
final StartingWindowRecord tView = new StartingWindowRecord(appToken,
- null/* decorView */, surface);
+ null/* decorView */, surface, STARTING_WINDOW_TYPE_SNAPSHOT);
mStartingWindowRecords.put(taskId, tView);
}
@@ -448,7 +462,7 @@ public class StartingSurfaceDrawer {
}
protected boolean addWindow(int taskId, IBinder appToken, View view, WindowManager wm,
- WindowManager.LayoutParams params) {
+ WindowManager.LayoutParams params, @StartingWindowType int suggestType) {
boolean shouldSaveView = true;
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addRootView");
@@ -468,14 +482,15 @@ public class StartingSurfaceDrawer {
}
if (shouldSaveView) {
removeWindowNoAnimate(taskId);
- saveSplashScreenRecord(appToken, taskId, view);
+ saveSplashScreenRecord(appToken, taskId, view, suggestType);
}
return shouldSaveView;
}
- private void saveSplashScreenRecord(IBinder appToken, int taskId, View view) {
+ private void saveSplashScreenRecord(IBinder appToken, int taskId, View view,
+ @StartingWindowType int suggestType) {
final StartingWindowRecord tView = new StartingWindowRecord(appToken, view,
- null/* TaskSnapshotWindow */);
+ null/* TaskSnapshotWindow */, suggestType);
mStartingWindowRecords.put(taskId, tView);
}
@@ -492,14 +507,18 @@ public class StartingSurfaceDrawer {
Slog.v(TAG, "Removing splash screen window for task: " + taskId);
}
if (record.mContentView != null) {
- if (playRevealAnimation) {
- mSplashscreenContentDrawer.applyExitAnimation(record.mContentView,
- leash, frame,
- () -> removeWindowInner(record.mDecorView, true));
+ if (record.mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
+ removeWindowInner(record.mDecorView, false);
} else {
- // the SplashScreenView has been copied to client, hide the view to skip
- // default exit animation
- removeWindowInner(record.mDecorView, true);
+ if (playRevealAnimation) {
+ mSplashscreenContentDrawer.applyExitAnimation(record.mContentView,
+ leash, frame,
+ () -> removeWindowInner(record.mDecorView, true));
+ } else {
+ // the SplashScreenView has been copied to client, hide the view to skip
+ // default exit animation
+ removeWindowInner(record.mDecorView, true);
+ }
}
} else {
// shouldn't happen
@@ -536,6 +555,7 @@ public class StartingSurfaceDrawer {
private final TaskSnapshotWindow mTaskSnapshotWindow;
private SplashScreenView mContentView;
private boolean mSetSplashScreen;
+ private @StartingWindowType int mSuggestType;
StartingWindowRecord(IBinder appToken, View decorView,
TaskSnapshotWindow taskSnapshotWindow) {
@@ -544,6 +564,14 @@ public class StartingSurfaceDrawer {
mTaskSnapshotWindow = taskSnapshotWindow;
}
+ StartingWindowRecord(IBinder appToken, View decorView,
+ TaskSnapshotWindow taskSnapshotWindow, @StartingWindowType int suggestType) {
+ mAppToken = appToken;
+ mDecorView = decorView;
+ mTaskSnapshotWindow = taskSnapshotWindow;
+ mSuggestType = suggestType;
+ }
+
private void setSplashScreenView(SplashScreenView splashScreenView) {
if (mSetSplashScreen) {
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index 9c1dde925762..eaa89d8e3ab5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -17,6 +17,7 @@ package com.android.wm.shell.startingsurface;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
@@ -31,6 +32,7 @@ import android.os.Trace;
import android.util.Slog;
import android.view.SurfaceControl;
import android.window.StartingWindowInfo;
+import android.window.StartingWindowInfo.StartingWindowType;
import android.window.TaskOrganizer;
import android.window.TaskSnapshot;
@@ -106,10 +108,6 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
mTaskLaunchingCallback = listener;
}
- private boolean shouldSendToListener(int suggestionType) {
- return suggestionType != STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
- }
-
/**
* Called when a task need a starting window.
*/
@@ -120,12 +118,9 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
final int suggestionType = mStartingWindowTypeAlgorithm.getSuggestedWindowType(
windowInfo);
final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
- if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
- mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken,
- false /* emptyView */);
- } else if (suggestionType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN) {
+ if (isSplashScreenType(suggestionType)) {
mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken,
- true /* emptyView */);
+ suggestionType);
} else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
final TaskSnapshot snapshot = windowInfo.mTaskSnapshot;
mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken,
@@ -133,7 +128,7 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
} else /* suggestionType == STARTING_WINDOW_TYPE_NONE */ {
// Don't add a staring window.
}
- if (mTaskLaunchingCallback != null && shouldSendToListener(suggestionType)) {
+ if (mTaskLaunchingCallback != null && isSplashScreenType(suggestionType)) {
int taskId = runningTaskInfo.taskId;
int color = mStartingSurfaceDrawer.getStartingWindowBackgroundColorForTask(taskId);
mTaskLaunchingCallback.accept(taskId, suggestionType, color);
@@ -143,6 +138,12 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
});
}
+ private static boolean isSplashScreenType(@StartingWindowType int suggestionType) {
+ return suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN
+ || suggestionType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN
+ || suggestionType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN;
+ }
+
public void copySplashScreenView(int taskId) {
mSplashScreenExecutor.execute(() -> {
mStartingSurfaceDrawer.copySplashScreenView(taskId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index acf7f3367d71..382d5806e3c2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.startingsurface;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.graphics.Color.WHITE;
import static android.graphics.Color.alpha;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -63,6 +64,7 @@ import android.graphics.RectF;
import android.hardware.HardwareBuffer;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.Trace;
import android.util.MergedConfiguration;
import android.util.Slog;
@@ -116,11 +118,15 @@ public class TaskSnapshotWindow {
private static final boolean DEBUG = StartingSurfaceDrawer.DEBUG_TASK_SNAPSHOT;
private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
+ private static final long DELAY_REMOVAL_TIME_GENERAL = 100;
+ private static final long DELAY_REMOVAL_TIME_IME_VISIBLE = 350;
+
//tmp vars for unused relayout params
private static final Point TMP_SURFACE_SIZE = new Point();
private final Window mWindow;
private final Runnable mClearWindowHandler;
+ private final long mDelayRemovalTime;
private final ShellExecutor mSplashScreenExecutor;
private final SurfaceControl mSurfaceControl;
private final IWindowSession mSession;
@@ -132,8 +138,10 @@ public class TaskSnapshotWindow {
private final RectF mTmpDstFrame = new RectF();
private final CharSequence mTitle;
private boolean mHasDrawn;
+ private long mShownTime;
private boolean mSizeMismatch;
private final Paint mBackgroundPaint = new Paint();
+ private final int mActivityType;
private final int mStatusBarColor;
private final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
private final int mOrientationOnCreation;
@@ -190,6 +198,7 @@ public class TaskSnapshotWindow {
final Point taskSize = snapshot.getTaskSize();
final Rect taskBounds = new Rect(0, 0, taskSize.x, taskSize.y);
final int orientation = snapshot.getOrientation();
+ final int activityType = runningTaskInfo.topActivityType;
final int displayId = runningTaskInfo.displayId;
final IWindowSession session = WindowManagerGlobal.getWindowSession();
@@ -207,10 +216,13 @@ public class TaskSnapshotWindow {
taskDescription.setBackgroundColor(WHITE);
}
+ final long delayRemovalTime = snapshot.hasImeSurface() ? DELAY_REMOVAL_TIME_IME_VISIBLE
+ : DELAY_REMOVAL_TIME_GENERAL;
+
final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
- windowFlags, windowPrivateFlags, taskBounds, orientation,
- topWindowInsetsState, clearWindowHandler, splashScreenExecutor);
+ windowFlags, windowPrivateFlags, taskBounds, orientation, activityType,
+ delayRemovalTime, topWindowInsetsState, clearWindowHandler, splashScreenExecutor);
final Window window = snapshotSurface.mWindow;
final InsetsState mTmpInsetsState = new InsetsState();
@@ -248,7 +260,8 @@ public class TaskSnapshotWindow {
public TaskSnapshotWindow(SurfaceControl surfaceControl,
TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
- int currentOrientation, InsetsState topWindowInsetsState, Runnable clearWindowHandler,
+ int currentOrientation, int activityType, long delayRemovalTime,
+ InsetsState topWindowInsetsState, Runnable clearWindowHandler,
ShellExecutor splashScreenExecutor) {
mSplashScreenExecutor = splashScreenExecutor;
mSession = WindowManagerGlobal.getWindowSession();
@@ -264,6 +277,8 @@ public class TaskSnapshotWindow {
windowPrivateFlags, appearance, taskDescription, 1f, topWindowInsetsState);
mStatusBarColor = taskDescription.getStatusBarColor();
mOrientationOnCreation = currentOrientation;
+ mActivityType = activityType;
+ mDelayRemovalTime = delayRemovalTime;
mTransaction = new SurfaceControl.Transaction();
mClearWindowHandler = clearWindowHandler;
}
@@ -286,6 +301,17 @@ public class TaskSnapshotWindow {
}
void remove() {
+ final long now = SystemClock.uptimeMillis();
+ if ((now - mShownTime < mDelayRemovalTime)
+ // Show the latest content as soon as possible for unlocking to home.
+ && mActivityType != ACTIVITY_TYPE_HOME) {
+ final long delayTime = mShownTime + mDelayRemovalTime - now;
+ mSplashScreenExecutor.executeDelayed(() -> remove(), delayTime);
+ if (DEBUG) {
+ Slog.d(TAG, "Defer removing snapshot surface in " + delayTime);
+ }
+ return;
+ }
try {
if (DEBUG) {
Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
@@ -326,6 +352,7 @@ public class TaskSnapshotWindow {
} else {
drawSizeMatchSnapshot();
}
+ mShownTime = SystemClock.uptimeMillis();
mHasDrawn = true;
reportDrawn();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
index 5a134b806745..848eff4b56f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
@@ -18,11 +18,13 @@ package com.android.wm.shell.startingsurface.phone;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
@@ -54,30 +56,38 @@ public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgor
final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
final boolean useEmptySplashScreen =
(parameter & TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN) != 0;
+ final boolean legacySplashScreen =
+ ((parameter & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN) != 0);
final boolean topIsHome = windowInfo.taskInfo.topActivityType == ACTIVITY_TYPE_HOME;
if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
- Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
- + " taskSwitch " + taskSwitch
- + " processRunning " + processRunning
- + " allowTaskSnapshot " + allowTaskSnapshot
- + " activityCreated " + activityCreated
- + " useEmptySplashScreen " + useEmptySplashScreen
- + " topIsHome " + topIsHome);
+ Slog.d(TAG, "preferredStartingWindowType newTask:" + newTask
+ + " taskSwitch:" + taskSwitch
+ + " processRunning:" + processRunning
+ + " allowTaskSnapshot:" + allowTaskSnapshot
+ + " activityCreated:" + activityCreated
+ + " useEmptySplashScreen:" + useEmptySplashScreen
+ + " legacySplashScreen:" + legacySplashScreen
+ + " topIsHome:" + topIsHome);
}
+
+ final int visibleSplashScreenType = legacySplashScreen
+ ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
+ : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+
if (!topIsHome) {
if (!processRunning) {
return useEmptySplashScreen
? STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN
- : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ : visibleSplashScreenType;
}
if (newTask) {
return useEmptySplashScreen
? STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN
- : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ : visibleSplashScreenType;
}
if (taskSwitch && !activityCreated) {
- return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ return visibleSplashScreenType;
}
}
if (taskSwitch && allowTaskSnapshot) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index df0a856db73c..cf5bd3ace806 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -48,6 +48,7 @@ import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
import android.window.TaskAppearedInfo;
+import android.window.WindowContainerToken;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -289,7 +290,6 @@ public class ShellTaskOrganizerTests {
public void testOnSizeCompatActivityChanged() {
final RunningTaskInfo taskInfo1 = createTaskInfo(12, WINDOWING_MODE_FULLSCREEN);
taskInfo1.displayId = DEFAULT_DISPLAY;
- taskInfo1.topActivityToken = mock(IBinder.class);
taskInfo1.topActivityInSizeCompat = false;
final TrackingTaskListener taskListener = new TrackingTaskListener();
mOrganizer.addListenerForType(taskListener, TASK_LISTENER_TYPE_FULLSCREEN);
@@ -297,23 +297,22 @@ public class ShellTaskOrganizerTests {
// sizeCompatActivity is null if top activity is not in size compat.
verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
- null /* taskConfig */, null /* sizeCompatActivity*/, null /* taskListener */);
+ null /* taskConfig */, null /* taskListener */);
// sizeCompatActivity is non-null if top activity is in size compat.
clearInvocations(mSizeCompatUI);
final RunningTaskInfo taskInfo2 =
createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode());
taskInfo2.displayId = taskInfo1.displayId;
- taskInfo2.topActivityToken = taskInfo1.topActivityToken;
taskInfo2.topActivityInSizeCompat = true;
mOrganizer.onTaskInfoChanged(taskInfo2);
verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
- taskInfo1.configuration, taskInfo1.topActivityToken, taskListener);
+ taskInfo1.configuration, taskListener);
clearInvocations(mSizeCompatUI);
mOrganizer.onTaskVanished(taskInfo1);
verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
- null /* taskConfig */, null /* sizeCompatActivity*/, null /* taskListener */);
+ null /* taskConfig */, null /* taskListener */);
}
@Test
@@ -433,6 +432,18 @@ public class ShellTaskOrganizerTests {
assertEquals(listener.invisibleLocusTasks.size(), 0);
}
+ @Test
+ public void testOnSizeCompatRestartButtonClicked() throws RemoteException {
+ RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
+ task1.token = mock(WindowContainerToken.class);
+
+ mOrganizer.onTaskAppeared(task1, null);
+
+ mOrganizer.onSizeCompatRestartButtonClicked(task1.taskId);
+
+ verify(mTaskOrganizerController).restartTaskTopActivityProcessIfVisible(task1.token);
+ }
+
private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
index 963757045453..3c124bafc18a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
@@ -50,6 +50,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import org.junit.Before;
@@ -82,6 +83,8 @@ public class HideDisplayCutoutOrganizerTest {
@Mock
private Display mDisplay;
@Mock
+ private DisplayLayout mDisplayLayout;
+ @Mock
private IWindowContainerToken mMockRealToken;
private WindowContainerToken mToken;
@@ -95,6 +98,7 @@ public class HideDisplayCutoutOrganizerTest {
MockitoAnnotations.initMocks(this);
when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
+ when(mMockDisplayController.getDisplayLayout(anyInt())).thenReturn(mDisplayLayout);
HideDisplayCutoutOrganizer organizer = new HideDisplayCutoutOrganizer(
mContext, mMockDisplayController, mMockMainExecutor);
@@ -152,7 +156,7 @@ public class HideDisplayCutoutOrganizerTest {
.getDisplayCutoutInsetsOfNaturalOrientation();
mContext.getOrCreateTestableResources().addOverride(
R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait);
- doReturn(Surface.ROTATION_0).when(mDisplay).getRotation();
+ doReturn(Surface.ROTATION_0).when(mDisplayLayout).rotation();
mOrganizer.enableHideDisplayCutout();
verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
@@ -171,7 +175,7 @@ public class HideDisplayCutoutOrganizerTest {
.getDisplayCutoutInsetsOfNaturalOrientation();
mContext.getOrCreateTestableResources().addOverride(
R.dimen.status_bar_height_landscape, mFakeStatusBarHeightLandscape);
- doReturn(Surface.ROTATION_90).when(mDisplay).getRotation();
+ doReturn(Surface.ROTATION_90).when(mDisplayLayout).rotation();
mOrganizer.enableHideDisplayCutout();
verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
@@ -190,7 +194,7 @@ public class HideDisplayCutoutOrganizerTest {
.getDisplayCutoutInsetsOfNaturalOrientation();
mContext.getOrCreateTestableResources().addOverride(
R.dimen.status_bar_height_landscape, mFakeStatusBarHeightLandscape);
- doReturn(Surface.ROTATION_270).when(mDisplay).getRotation();
+ doReturn(Surface.ROTATION_270).when(mDisplayLayout).rotation();
mOrganizer.enableHideDisplayCutout();
verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
@@ -219,4 +223,22 @@ public class HideDisplayCutoutOrganizerTest {
assertThat(mOrganizer.mOffsetX).isEqualTo(0);
assertThat(mOrganizer.mOffsetY).isEqualTo(0);
}
+
+ @Test
+ public void testDisplaySizeChange() {
+ doReturn(100).when(mDisplayLayout).width();
+ doReturn(200).when(mDisplayLayout).height();
+ doReturn(mFakeDefaultCutoutInsets).when(mOrganizer)
+ .getDisplayCutoutInsetsOfNaturalOrientation();
+ mContext.getOrCreateTestableResources().addOverride(
+ R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait);
+ doReturn(Surface.ROTATION_0).when(mDisplayLayout).rotation();
+ mOrganizer.enableHideDisplayCutout();
+ assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(0, 15, 100, 200));
+
+ doReturn(200).when(mDisplayLayout).width();
+ doReturn(400).when(mDisplayLayout).height();
+ mOrganizer.updateBoundsAndOffsets(true);
+ assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(0, 15, 200, 400));
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 950900337918..be786fb55b30 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -118,6 +118,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
mDefaultTapAppToExitEnabled);
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
mDefaultSwipeToNotificationEnabled);
+ when(mMockSettingsUitl.getShortcutEnabled(any(), anyInt())).thenReturn(false);
when(mMockDisplayAreaOrganizer.getLastDisplayBounds()).thenReturn(
new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height()));
@@ -341,6 +342,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
when(mSpiedTransitionState.getState()).thenReturn(STATE_ACTIVE);
when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
+ when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
mSpiedOneHandedController.onActivatedActionChanged();
verify(mSpiedOneHandedController, never()).startOneHanded();
@@ -352,6 +354,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(false);
+ when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
mSpiedOneHandedController.onActivatedActionChanged();
verify(mSpiedOneHandedController, never()).startOneHanded();
@@ -363,6 +366,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
+ when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
mSpiedOneHandedController.onActivatedActionChanged();
verify(mSpiedOneHandedController).startOneHanded();
@@ -374,6 +378,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
when(mSpiedTransitionState.getState()).thenReturn(STATE_ENTERING);
when(mSpiedTransitionState.isTransitioning()).thenReturn(true);
when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
+ when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
mSpiedOneHandedController.onActivatedActionChanged();
verify(mSpiedTransitionState, never()).setState(STATE_EXITING);
@@ -384,6 +389,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
when(mSpiedTransitionState.getState()).thenReturn(STATE_EXITING);
when(mSpiedTransitionState.isTransitioning()).thenReturn(true);
when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true);
+ when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
mSpiedOneHandedController.onActivatedActionChanged();
verify(mSpiedTransitionState, never()).setState(STATE_ENTERING);
@@ -392,6 +398,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
@Test
public void testOneHandedDisabled_shortcutTrigger_thenAutoEnabled() {
when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false);
+ when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(false);
@@ -417,6 +424,7 @@ public class OneHandedControllerTest extends OneHandedTestCase {
when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(true);
when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
+ when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(true);
mSpiedOneHandedController.registerEventCallback(mMockEventCallback);
mSpiedOneHandedController.onActivatedActionChanged();
@@ -425,11 +433,11 @@ public class OneHandedControllerTest extends OneHandedTestCase {
}
@Test
- public void testNotifyShortcutState_whenUpdateOneHandedEnabled() {
- when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false);
+ public void testNotifyShortcutState_whenSetOneHandedEnabled() {
+ when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(true);
when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
- when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(true);
+ when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(false);
mSpiedOneHandedController.registerEventCallback(mMockEventCallback);
mSpiedOneHandedController.setOneHandedEnabled(true);
@@ -448,4 +456,31 @@ public class OneHandedControllerTest extends OneHandedTestCase {
// Verify no NPE crash and mMockShellMainExecutor never be execute.
verify(mMockShellMainExecutor, never()).execute(any());
}
+
+ @Test
+ public void testShortcutEnable_ableToAutoEnableOneHandedMode() {
+ when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false);
+ when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
+ when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
+ when(mSpiedOneHandedController.isShortcutEnabled()).thenReturn(true);
+ when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(false);
+ when(mMockSettingsUitl.setOneHandedModeEnabled(any(), anyInt(), anyInt())).thenReturn(
+ false /* To avoid test runner create Toast */);
+ mSpiedOneHandedController.onActivatedActionChanged();
+
+ verify(mSpiedOneHandedController).notifyUserConfigChanged(anyBoolean());
+ }
+
+ @Test
+ public void testShortcutDisable_shouldNotAutoEnableOneHandedMode() {
+ when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false);
+ when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
+ when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
+ when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(false);
+ when(mMockSettingsUitl.setOneHandedModeEnabled(any(), anyInt(), anyInt())).thenReturn(true);
+ mSpiedOneHandedController.onActivatedActionChanged();
+
+ verify(mMockSettingsUitl, never()).setOneHandedModeEnabled(any(), anyInt(), anyInt());
+ verify(mSpiedOneHandedController, never()).notifyUserConfigChanged(anyBoolean());
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
index a0c6d1138698..90f898aa09da 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
@@ -402,6 +402,64 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
assertBoundsInclusionWithMargin("useDefaultBounds", defaultBounds, actualBounds);
}
+ @Test
+ public void adjustNormalBoundsToFitMenu_alreadyFits() {
+ final Rect normalBounds = new Rect(0, 0, 400, 711);
+ final Size minMenuSize = new Size(396, 292);
+ mPipBoundsState.setAspectRatio(
+ ((float) normalBounds.width()) / ((float) normalBounds.height()));
+
+ final Rect bounds =
+ mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds, minMenuSize);
+
+ assertEquals(normalBounds, bounds);
+ }
+
+ @Test
+ public void adjustNormalBoundsToFitMenu_widthTooSmall() {
+ final Rect normalBounds = new Rect(0, 0, 297, 528);
+ final Size minMenuSize = new Size(396, 292);
+ mPipBoundsState.setAspectRatio(
+ ((float) normalBounds.width()) / ((float) normalBounds.height()));
+
+ final Rect bounds =
+ mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds, minMenuSize);
+
+ assertEquals(minMenuSize.getWidth(), bounds.width());
+ assertEquals(minMenuSize.getWidth() / mPipBoundsState.getAspectRatio(),
+ bounds.height(), 0.3f);
+ }
+
+ @Test
+ public void adjustNormalBoundsToFitMenu_heightTooSmall() {
+ final Rect normalBounds = new Rect(0, 0, 400, 280);
+ final Size minMenuSize = new Size(396, 292);
+ mPipBoundsState.setAspectRatio(
+ ((float) normalBounds.width()) / ((float) normalBounds.height()));
+
+ final Rect bounds =
+ mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds, minMenuSize);
+
+ assertEquals(minMenuSize.getHeight(), bounds.height());
+ assertEquals(minMenuSize.getHeight() * mPipBoundsState.getAspectRatio(),
+ bounds.width(), 0.3f);
+ }
+
+ @Test
+ public void adjustNormalBoundsToFitMenu_widthAndHeightTooSmall() {
+ final Rect normalBounds = new Rect(0, 0, 350, 280);
+ final Size minMenuSize = new Size(396, 292);
+ mPipBoundsState.setAspectRatio(
+ ((float) normalBounds.width()) / ((float) normalBounds.height()));
+
+ final Rect bounds =
+ mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds, minMenuSize);
+
+ assertEquals(minMenuSize.getWidth(), bounds.width());
+ assertEquals(minMenuSize.getWidth() / mPipBoundsState.getAspectRatio(),
+ bounds.height(), 0.3f);
+ }
+
private void overrideDefaultAspectRatio(float aspectRatio) {
final TestableResources res = mContext.getOrCreateTestableResources();
res.addOverride(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java
index 9845d4650d20..10fd7d705967 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java
@@ -22,7 +22,6 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
import android.content.res.Configuration;
-import android.os.IBinder;
import android.testing.AndroidTestingRunner;
import android.view.LayoutInflater;
import android.widget.Button;
@@ -52,7 +51,7 @@ import org.mockito.MockitoAnnotations;
public class SizeCompatHintPopupTest extends ShellTestCase {
@Mock private SyncTransactionQueue mSyncTransactionQueue;
- @Mock private IBinder mActivityToken;
+ @Mock private SizeCompatUIController.SizeCompatUICallback mCallback;
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
@Mock private DisplayLayout mDisplayLayout;
@@ -64,8 +63,9 @@ public class SizeCompatHintPopupTest extends ShellTestCase {
MockitoAnnotations.initMocks(this);
final int taskId = 1;
- mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mContext, new Configuration(),
- taskId, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/);
+ mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext,
+ new Configuration(), taskId, mTaskListener, mDisplayLayout,
+ false /* hasShownHint */);
mHint = (SizeCompatHintPopup)
LayoutInflater.from(mContext).inflate(R.layout.size_compat_mode_hint, null);
mHint.inject(mLayout);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java
index 5a43925a5677..a20a5e9e8d91 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java
@@ -22,7 +22,6 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
import android.content.res.Configuration;
-import android.os.IBinder;
import android.testing.AndroidTestingRunner;
import android.view.LayoutInflater;
import android.widget.ImageButton;
@@ -51,8 +50,10 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class SizeCompatRestartButtonTest extends ShellTestCase {
+ private static final int TASK_ID = 1;
+
@Mock private SyncTransactionQueue mSyncTransactionQueue;
- @Mock private IBinder mActivityToken;
+ @Mock private SizeCompatUIController.SizeCompatUICallback mCallback;
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
@Mock private DisplayLayout mDisplayLayout;
@@ -63,9 +64,9 @@ public class SizeCompatRestartButtonTest extends ShellTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
- final int taskId = 1;
- mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mContext, new Configuration(),
- taskId, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/);
+ mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext,
+ new Configuration(), TASK_ID, mTaskListener, mDisplayLayout,
+ false /* hasShownHint */);
mButton = (SizeCompatRestartButton)
LayoutInflater.from(mContext).inflate(R.layout.size_compat_ui, null);
mButton.inject(mLayout);
@@ -75,12 +76,11 @@ public class SizeCompatRestartButtonTest extends ShellTestCase {
@Test
public void testOnClick() {
- doNothing().when(mLayout).onRestartButtonClicked();
-
final ImageButton button = mButton.findViewById(R.id.size_compat_restart_button);
button.performClick();
verify(mLayout).onRestartButtonClicked();
+ verify(mCallback).onSizeCompatRestartButtonClicked(TASK_ID);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java
index 806a90b7832a..8839f58ea889 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java
@@ -27,7 +27,6 @@ import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.res.Configuration;
-import android.os.IBinder;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
@@ -61,7 +60,6 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
private @Mock DisplayController mMockDisplayController;
private @Mock DisplayLayout mMockDisplayLayout;
private @Mock DisplayImeController mMockImeController;
- private @Mock IBinder mMockActivityToken;
private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener;
private @Mock SyncTransactionQueue mMockSyncQueue;
private @Mock SizeCompatUILayout mMockLayout;
@@ -77,8 +75,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
mMockImeController, mMockSyncQueue) {
@Override
SizeCompatUILayout createLayout(Context context, int displayId, int taskId,
- Configuration taskConfig, IBinder activityToken,
- ShellTaskOrganizer.TaskListener taskListener) {
+ Configuration taskConfig, ShellTaskOrganizer.TaskListener taskListener) {
return mMockLayout;
}
};
@@ -97,21 +94,21 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
// Verify that the restart button is added with non-null size compat info.
mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
- mMockActivityToken, mMockTaskListener);
+ mMockTaskListener);
verify(mController).createLayout(any(), eq(DISPLAY_ID), eq(TASK_ID), eq(taskConfig),
- eq(mMockActivityToken), eq(mMockTaskListener));
+ eq(mMockTaskListener));
// Verify that the restart button is updated with non-null new size compat info.
final Configuration newTaskConfig = new Configuration();
mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, newTaskConfig,
- mMockActivityToken, mMockTaskListener);
+ mMockTaskListener);
- verify(mMockLayout).updateSizeCompatInfo(taskConfig, mMockActivityToken, mMockTaskListener,
+ verify(mMockLayout).updateSizeCompatInfo(taskConfig, mMockTaskListener,
false /* isImeShowing */);
// Verify that the restart button is removed with null size compat info.
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, null, null, mMockTaskListener);
+ mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, null, mMockTaskListener);
verify(mMockLayout).release();
}
@@ -120,7 +117,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
public void testOnDisplayRemoved() {
final Configuration taskConfig = new Configuration();
mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
- mMockActivityToken, mMockTaskListener);
+ mMockTaskListener);
mController.onDisplayRemoved(DISPLAY_ID + 1);
@@ -135,7 +132,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
public void testOnDisplayConfigurationChanged() {
final Configuration taskConfig = new Configuration();
mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
- mMockActivityToken, mMockTaskListener);
+ mMockTaskListener);
final Configuration newTaskConfig = new Configuration();
mController.onDisplayConfigurationChanged(DISPLAY_ID + 1, newTaskConfig);
@@ -151,7 +148,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
public void testChangeButtonVisibilityOnImeShowHide() {
final Configuration taskConfig = new Configuration();
mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
- mMockActivityToken, mMockTaskListener);
+ mMockTaskListener);
mController.onImeVisibilityChanged(DISPLAY_ID, true /* isShowing */);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
index f33cfe86224f..ee4c81547bbd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
@@ -21,20 +21,16 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.app.ActivityClient;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.os.IBinder;
import android.testing.AndroidTestingRunner;
import android.view.DisplayInfo;
import android.view.SurfaceControl;
@@ -66,7 +62,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
private static final int TASK_ID = 1;
@Mock private SyncTransactionQueue mSyncTransactionQueue;
- @Mock private IBinder mActivityToken;
+ @Mock private SizeCompatUIController.SizeCompatUICallback mCallback;
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
@Mock private DisplayLayout mDisplayLayout;
@Mock private SizeCompatRestartButton mButton;
@@ -80,8 +76,9 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
MockitoAnnotations.initMocks(this);
mTaskConfig = new Configuration();
- mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mContext, new Configuration(),
- TASK_ID, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/);
+ mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext,
+ new Configuration(), TASK_ID, mTaskListener, mDisplayLayout,
+ false /* hasShownHint */);
spyOn(mLayout);
spyOn(mLayout.mButtonWindowManager);
@@ -145,7 +142,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
// No diff
clearInvocations(mLayout);
- mLayout.updateSizeCompatInfo(mTaskConfig, mActivityToken, mTaskListener,
+ mLayout.updateSizeCompatInfo(mTaskConfig, mTaskListener,
false /* isImeShowing */);
verify(mLayout, never()).updateButtonSurfacePosition();
@@ -156,7 +153,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
clearInvocations(mLayout);
final ShellTaskOrganizer.TaskListener newTaskListener = mock(
ShellTaskOrganizer.TaskListener.class);
- mLayout.updateSizeCompatInfo(mTaskConfig, mActivityToken, newTaskListener,
+ mLayout.updateSizeCompatInfo(mTaskConfig, newTaskListener,
false /* isImeShowing */);
verify(mLayout).release();
@@ -166,7 +163,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
clearInvocations(mLayout);
final Configuration newTaskConfiguration = new Configuration();
newTaskConfiguration.windowConfiguration.setBounds(new Rect(0, 1000, 0, 2000));
- mLayout.updateSizeCompatInfo(newTaskConfiguration, mActivityToken, newTaskListener,
+ mLayout.updateSizeCompatInfo(newTaskConfiguration, newTaskListener,
false /* isImeShowing */);
verify(mLayout).updateButtonSurfacePosition();
@@ -228,12 +225,9 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
@Test
public void testOnRestartButtonClicked() {
- spyOn(ActivityClient.getInstance());
- doNothing().when(ActivityClient.getInstance()).restartActivityProcessIfVisible(any());
-
mLayout.onRestartButtonClicked();
- verify(ActivityClient.getInstance()).restartActivityProcessIfVisible(mActivityToken);
+ verify(mCallback).onSizeCompatRestartButtonClicked(TASK_ID);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index 903e63ad6554..5061b2369bb2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -15,6 +15,8 @@
*/
package com.android.wm.shell.startingsurface;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
@@ -91,7 +93,7 @@ public class StartingSurfaceDrawerTests {
@Override
protected boolean addWindow(int taskId, IBinder appToken,
- View view, WindowManager wm, WindowManager.LayoutParams params) {
+ View view, WindowManager wm, WindowManager.LayoutParams params, int suggestType) {
// listen for addView
mAddWindowForTask = taskId;
mViewThemeResId = view.getContext().getThemeResId();
@@ -145,9 +147,11 @@ public class StartingSurfaceDrawerTests {
final int taskId = 1;
final StartingWindowInfo windowInfo =
createWindowInfo(taskId, android.R.style.Theme);
- mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder, false);
+ mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder,
+ STARTING_WINDOW_TYPE_SPLASH_SCREEN);
waitHandlerIdle(mTestHandler);
- verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any());
+ verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any(),
+ eq(STARTING_WINDOW_TYPE_SPLASH_SCREEN));
assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId, null, null, false);
@@ -161,9 +165,11 @@ public class StartingSurfaceDrawerTests {
final int taskId = 1;
final StartingWindowInfo windowInfo =
createWindowInfo(taskId, 0);
- mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder, false);
+ mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder,
+ STARTING_WINDOW_TYPE_SPLASH_SCREEN);
waitHandlerIdle(mTestHandler);
- verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any());
+ verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any(),
+ eq(STARTING_WINDOW_TYPE_SPLASH_SCREEN));
assertNotEquals(mStartingSurfaceDrawer.mViewThemeResId, 0);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
index 5945840a8fa2..a098a6863493 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.startingsurface;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -81,7 +82,8 @@ public class TaskSnapshotWindowTest {
mWindow = new TaskSnapshotWindow(new SurfaceControl(), snapshot, "Test",
createTaskDescription(Color.WHITE, Color.RED, Color.BLUE),
0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */,
- taskBounds, ORIENTATION_PORTRAIT, new InsetsState(),
+ taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD,
+ 100 /* delayRemovalTime */, new InsetsState(),
null /* clearWindow */, new TestShellExecutor());
}