summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java4
-rw-r--r--apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java4
-rw-r--r--api/test-current.txt12
-rw-r--r--cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java1
-rw-r--r--core/java/android/annotation/NonNull.java4
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl1
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java32
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java6
-rw-r--r--core/java/android/view/Display.java7
-rw-r--r--core/java/android/view/IWindowSession.aidl7
-rw-r--r--core/java/android/view/SurfaceControl.java24
-rw-r--r--core/java/android/view/ViewRootImpl.java10
-rw-r--r--core/java/android/view/WindowlessWindowManager.java5
-rw-r--r--core/java/android/widget/RadioGroup.java19
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java24
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java9
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java14
-rw-r--r--core/java/com/android/internal/widget/ConversationLayout.java61
-rw-r--r--core/jni/android_view_SurfaceControl.cpp23
-rw-r--r--core/res/res/layout/resolver_empty_states.xml106
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java9
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java9
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp2
-rw-r--r--libs/hwui/tests/unit/SkiaPipelineTests.cpp37
-rw-r--r--media/java/android/media/MediaMetrics.java95
-rw-r--r--packages/SettingsLib/res/values/strings.xml4
-rw-r--r--packages/SystemUI/res/layout/bubble_dismiss_target.xml2
-rw-r--r--packages/SystemUI/res/layout/global_actions_grid_item_v2.xml8
-rw-r--r--packages/SystemUI/res/layout/pip_dismiss_view.xml35
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java188
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java149
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java253
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt8
-rw-r--r--services/core/java/com/android/server/Watchdog.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java22
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java56
-rw-r--r--services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java83
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java64
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java166
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java43
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java9
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java5
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java16
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java7
-rw-r--r--services/core/java/com/android/server/wm/Session.java14
-rw-r--r--services/core/java/com/android/server/wm/ShellRoot.java32
-rw-r--r--services/core/java/com/android/server/wm/Task.java15
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java11
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java30
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java4
-rw-r--r--services/incremental/IncrementalService.cpp201
-rw-r--r--services/incremental/IncrementalService.h6
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java25
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java1
-rw-r--r--telephony/common/android/telephony/LocationAccessPolicy.java2
91 files changed, 1444 insertions, 1004 deletions
diff --git a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
index 8633c9613138..8139a2e963c5 100644
--- a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
@@ -30,6 +30,7 @@ import android.util.MergedConfiguration;
import android.view.DisplayCutout;
import android.view.IWindow;
import android.view.IWindowSession;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.View;
@@ -120,6 +121,7 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase {
new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
final MergedConfiguration mOutMergedConfiguration = new MergedConfiguration();
final InsetsState mOutInsetsState = new InsetsState();
+ final InsetsSourceControl[] mOutControls = new InsetsSourceControl[0];
final IWindow mWindow;
final View mView;
final WindowManager.LayoutParams mParams;
@@ -152,7 +154,7 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase {
mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrame,
mOutContentInsets, mOutVisibleInsets, mOutStableInsets,
mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration,
- mOutSurfaceControl, mOutInsetsState, mOutSurfaceSize,
+ mOutSurfaceControl, mOutInsetsState, mOutControls, mOutSurfaceSize,
mOutBlastSurfaceControl);
}
}
diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
index 4ac3adfd19ce..c72cc9d635e0 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
@@ -29,6 +29,7 @@ import android.view.Display;
import android.view.DisplayCutout;
import android.view.IWindowSession;
import android.view.InputChannel;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.View;
import android.view.WindowManager;
@@ -91,6 +92,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
final DisplayCutout.ParcelableWrapper mOutDisplayCutout =
new DisplayCutout.ParcelableWrapper();
final InsetsState mOutInsetsState = new InsetsState();
+ final InsetsSourceControl[] mOutControls = new InsetsSourceControl[0];
TestWindow() {
mLayoutParams.setTitle(TestWindow.class.getName());
@@ -109,7 +111,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
long startTime = SystemClock.elapsedRealtimeNanos();
session.addToDisplay(this, mSeq, mLayoutParams, View.VISIBLE,
Display.DEFAULT_DISPLAY, mOutFrame, mOutContentInsets, mOutStableInsets,
- mOutDisplayCutout, inputChannel, mOutInsetsState);
+ mOutDisplayCutout, inputChannel, mOutInsetsState, mOutControls);
final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
state.addExtraResult("add", elapsedTimeNsOfAdd);
diff --git a/api/test-current.txt b/api/test-current.txt
index 629ce4e6470e..5de6c2ae4c82 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4814,7 +4814,14 @@ package android.view {
public final class Display {
method @NonNull public android.graphics.ColorSpace[] getSupportedWideColorGamut();
+ method public int getType();
method public boolean hasAccess(int);
+ field public static final int TYPE_EXTERNAL = 2; // 0x2
+ field public static final int TYPE_INTERNAL = 1; // 0x1
+ field public static final int TYPE_OVERLAY = 4; // 0x4
+ field public static final int TYPE_UNKNOWN = 0; // 0x0
+ field public static final int TYPE_VIRTUAL = 5; // 0x5
+ field public static final int TYPE_WIFI = 3; // 0x3
}
public class FocusFinder {
@@ -4852,6 +4859,11 @@ package android.view {
method public abstract String asyncImpl() default "";
}
+ public final class SurfaceControl implements android.os.Parcelable {
+ method public static long acquireFrameRateFlexibilityToken();
+ method public static void releaseFrameRateFlexibilityToken(long);
+ }
+
public class SurfaceControlViewHost {
method public void relayout(android.view.WindowManager.LayoutParams);
method public void setView(@NonNull android.view.View, @NonNull android.view.WindowManager.LayoutParams);
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
index 2a7cfd306174..d5da0b42402c 100644
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
+++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
@@ -68,6 +68,7 @@ public class TestDrive {
};
private static final String[] DEFAULT_PULL_SOURCES = {
"AID_SYSTEM",
+ "AID_RADIO"
};
private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName());
diff --git a/core/java/android/annotation/NonNull.java b/core/java/android/annotation/NonNull.java
index a95bf3b8061e..c5aff9d6794e 100644
--- a/core/java/android/annotation/NonNull.java
+++ b/core/java/android/annotation/NonNull.java
@@ -30,8 +30,8 @@ import java.lang.annotation.Target;
* <p>
* This is a marker annotation and it has no specific attributes.
*
- * @paramDoc This value must never be {@code null}.
- * @returnDoc This value will never be {@code null}.
+ * @paramDoc This value cannot be {@code null}.
+ * @returnDoc This value cannot be {@code null}.
* @hide
*/
@Retention(SOURCE)
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index e476993f003f..b7ceb6ae1b4c 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -299,7 +299,6 @@ interface IActivityTaskManager {
in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations);
void suppressResizeConfigChanges(boolean suppress);
- void moveTasksToFullscreenStack(int fromStackId, boolean onTop);
boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds);
boolean isInMultiWindowMode(in IBinder token);
boolean isInPictureInPictureMode(in IBinder token);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index f216db6fc717..fc48e7f18f5f 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -979,17 +979,14 @@ public final class BluetoothAdapter {
8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) {
@Override
protected Integer recompute(Void query) {
+ // This function must be called while holding the
+ // mServiceLock, and with mService not null. The public
+ // getState() method makes this guarantee.
try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.getState();
- }
+ return mService.getState();
} catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
+ throw e.rethrowFromSystemServer();
}
- return BluetoothAdapter.STATE_OFF;
}
};
@@ -1016,7 +1013,24 @@ public final class BluetoothAdapter {
@RequiresPermission(Manifest.permission.BLUETOOTH)
@AdapterState
public int getState() {
- int state = mBluetoothGetStateCache.query(null);
+ int state = BluetoothAdapter.STATE_OFF;
+
+ try {
+ mServiceLock.readLock().lock();
+ // The test for mService must either be outside the cache, or
+ // the cache must be invalidated when mService changes.
+ if (mService != null) {
+ state = mBluetoothGetStateCache.query(null);
+ }
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof RemoteException) {
+ Log.e(TAG, "", e.getCause());
+ } else {
+ throw e;
+ }
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
// Consider all internal states as OFF
if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index f531e12b0748..f944dd78dc3d 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -55,6 +55,7 @@ import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.InputEventReceiver;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.SurfaceControl;
@@ -190,6 +191,7 @@ public abstract class WallpaperService extends Service {
new DisplayCutout.ParcelableWrapper();
DisplayCutout mDispatchedDisplayCutout = DisplayCutout.NO_CUTOUT;
final InsetsState mInsetsState = new InsetsState();
+ final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
private final Point mSurfaceSize = new Point();
@@ -878,7 +880,7 @@ public abstract class WallpaperService extends Service {
if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets,
mDisplayCutout, inputChannel,
- mInsetsState) < 0) {
+ mInsetsState, mTempControls) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
@@ -903,7 +905,7 @@ public abstract class WallpaperService extends Service {
View.VISIBLE, 0, -1, mWinFrame, mContentInsets,
mVisibleInsets, mStableInsets, mBackdropFrame,
mDisplayCutout, mMergedConfiguration, mSurfaceControl,
- mInsetsState, mSurfaceSize, mTmpSurfaceControl);
+ mInsetsState, mTempControls, mSurfaceSize, mTmpSurfaceControl);
if (mSurfaceControl.isValid()) {
mSurfaceHolder.mSurface.copyFrom(mSurfaceControl);
mSurfaceControl.release();
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 0ccb1e055c46..4469fdbb12ec 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -253,12 +253,14 @@ public final class Display {
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
public static final int TYPE_UNKNOWN = 0;
/**
* Display type: Physical display connected through an internal port.
* @hide
*/
+ @TestApi
public static final int TYPE_INTERNAL = 1;
/**
@@ -266,6 +268,7 @@ public final class Display {
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
public static final int TYPE_EXTERNAL = 2;
/**
@@ -273,12 +276,14 @@ public final class Display {
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
public static final int TYPE_WIFI = 3;
/**
* Display type: Overlay display.
* @hide
*/
+ @TestApi
public static final int TYPE_OVERLAY = 4;
/**
@@ -286,6 +291,7 @@ public final class Display {
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
public static final int TYPE_VIRTUAL = 5;
/**
@@ -569,6 +575,7 @@ public final class Display {
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
public int getType() {
return mType;
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 45e51f756489..81bfcb07ab6d 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -29,6 +29,7 @@ import android.view.IWindow;
import android.view.IWindowId;
import android.view.MotionEvent;
import android.view.WindowManager;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -46,7 +47,7 @@ interface IWindowSession {
in int viewVisibility, in int layerStackId, out Rect outFrame,
out Rect outContentInsets, out Rect outStableInsets,
out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel,
- out InsetsState insetsState);
+ out InsetsState insetsState, out InsetsSourceControl[] activeControls);
int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outContentInsets,
out Rect outStableInsets, out InsetsState insetsState);
@@ -106,8 +107,8 @@ interface IWindowSession {
out Rect outBackdropFrame,
out DisplayCutout.ParcelableWrapper displayCutout,
out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
- out InsetsState insetsState, out Point outSurfaceSize,
- out SurfaceControl outBlastSurfaceControl);
+ out InsetsState insetsState, out InsetsSourceControl[] activeControls,
+ out Point outSurfaceSize, out SurfaceControl outBlastSurfaceControl);
/*
* Notify the window manager that an application is relaunching and
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index a37c1cbc76ad..b5f9df72f756 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -32,6 +32,7 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
@@ -216,6 +217,9 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeSetFrameRate(
long transactionObj, long nativeObject, float frameRate, int compatibility);
+ private static native long nativeAcquireFrameRateFlexibilityToken();
+ private static native void nativeReleaseFrameRateFlexibilityToken(long token);
+
private final CloseGuard mCloseGuard = CloseGuard.get();
private String mName;
/**
@@ -2868,4 +2872,24 @@ public final class SurfaceControl implements Parcelable {
}
}
}
+
+ /**
+ * Acquire a frame rate flexibility token, which allows surface flinger to freely switch display
+ * frame rates. This is used by CTS tests to put the device in a consistent state. See
+ * ISurfaceComposer::acquireFrameRateFlexibilityToken().
+ * @hide
+ */
+ @TestApi
+ public static long acquireFrameRateFlexibilityToken() {
+ return nativeAcquireFrameRateFlexibilityToken();
+ }
+
+ /**
+ * Release a frame rate flexibility token.
+ * @hide
+ */
+ @TestApi
+ public static void releaseFrameRateFlexibilityToken(long token) {
+ nativeReleaseFrameRateFlexibilityToken(token);
+ }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1e96a1c21ac3..750b1eddd222 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -21,6 +21,7 @@ import static android.view.Display.INVALID_DISPLAY;
import static android.view.InputDevice.SOURCE_CLASS_NONE;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.LAST_TYPE;
import static android.view.View.PFLAG_DRAW_ANIMATION;
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
@@ -558,7 +559,8 @@ public final class ViewRootImpl implements ViewParent,
final DisplayCutout.ParcelableWrapper mPendingDisplayCutout =
new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
boolean mPendingAlwaysConsumeSystemBars;
- private InsetsState mTempInsets = new InsetsState();
+ private final InsetsState mTempInsets = new InsetsState();
+ private final InsetsSourceControl[] mTempControls = new InsetsSourceControl[LAST_TYPE + 1];
final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
= new ViewTreeObserver.InternalInsetsInfo();
@@ -1003,7 +1005,7 @@ public final class ViewRootImpl implements ViewParent,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mDisplayCutout, inputChannel,
- mTempInsets);
+ mTempInsets, mTempControls);
setFrame(mTmpFrame);
} catch (RemoteException e) {
mAdded = false;
@@ -1028,6 +1030,7 @@ public final class ViewRootImpl implements ViewParent,
(res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0;
mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;
mInsetsController.onStateChanged(mTempInsets);
+ mInsetsController.onControlsChanged(mTempControls);
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
mAttachInfo.mRootView = null;
@@ -7356,7 +7359,7 @@ public final class ViewRootImpl implements ViewParent,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame,
mPendingDisplayCutout, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
- mSurfaceSize, mBlastSurfaceControl);
+ mTempControls, mSurfaceSize, mBlastSurfaceControl);
if (mSurfaceControl.isValid()) {
if (!mUseBLASTAdapter) {
mSurface.copyFrom(mSurfaceControl);
@@ -7386,6 +7389,7 @@ public final class ViewRootImpl implements ViewParent,
}
setFrame(mTmpFrame);
mInsetsController.onStateChanged(mTempInsets);
+ mInsetsController.onControlsChanged(mTempControls);
return relayoutResult;
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 144f8e3a7108..39ed4018c65c 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -104,7 +104,7 @@ public class WindowlessWindowManager implements IWindowSession {
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
- InsetsState outInsetsState) {
+ InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
.setParent(mRootSurface)
.setFormat(attrs.format)
@@ -179,7 +179,8 @@ public class WindowlessWindowManager implements IWindowSession {
Rect outStableInsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
+ SurfaceControl outBLASTSurfaceControl) {
final State state;
synchronized (this) {
state = mStateForWindow.get(window.asBinder());
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 71ccb595278b..849488d42bcf 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -484,21 +485,21 @@ public class RadioGroup extends LinearLayout {
super.onInitializeAccessibilityNodeInfo(info);
if (this.getOrientation() == HORIZONTAL) {
info.setCollectionInfo(AccessibilityNodeInfo.CollectionInfo.obtain(1,
- getVisibleChildCount(), false,
+ getVisibleChildWithTextCount(), false,
AccessibilityNodeInfo.CollectionInfo.SELECTION_MODE_SINGLE));
} else {
info.setCollectionInfo(
- AccessibilityNodeInfo.CollectionInfo.obtain(getVisibleChildCount(),
+ AccessibilityNodeInfo.CollectionInfo.obtain(getVisibleChildWithTextCount(),
1, false,
AccessibilityNodeInfo.CollectionInfo.SELECTION_MODE_SINGLE));
}
}
- private int getVisibleChildCount() {
+ private int getVisibleChildWithTextCount() {
int count = 0;
for (int i = 0; i < getChildCount(); i++) {
if (this.getChildAt(i) instanceof RadioButton) {
- if (((RadioButton) this.getChildAt(i)).getVisibility() == VISIBLE) {
+ if (isVisibleWithText((RadioButton) this.getChildAt(i))) {
count++;
}
}
@@ -513,15 +514,19 @@ public class RadioGroup extends LinearLayout {
int index = 0;
for (int i = 0; i < getChildCount(); i++) {
if (this.getChildAt(i) instanceof RadioButton) {
- RadioButton radioButton = (RadioButton) this.getChildAt(i);
- if (radioButton == child) {
+ RadioButton button = (RadioButton) this.getChildAt(i);
+ if (button == child) {
return index;
}
- if (radioButton.getVisibility() == VISIBLE) {
+ if (isVisibleWithText(button)) {
index++;
}
}
}
return -1;
}
+
+ private boolean isVisibleWithText(RadioButton button) {
+ return button.getVisibility() == VISIBLE && !TextUtils.isEmpty(button.getText());
+ }
} \ No newline at end of file
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index 9fc0da83c504..d43333e507a6 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -55,6 +55,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
private static final String TAG = "AbstractMultiProfilePagerAdapter";
static final int PROFILE_PERSONAL = 0;
static final int PROFILE_WORK = 1;
+
@IntDef({PROFILE_PERSONAL, PROFILE_WORK})
@interface Profile {}
@@ -365,7 +366,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
UserHandle listUserHandle = listAdapter.getUserHandle();
if (!listUserHandle.equals(mWorkProfileUserHandle)
|| !mInjector.isQuietModeEnabled(mWorkProfileUserHandle)
- || !hasResolvedAppsInWorkProfile(listAdapter)) {
+ || listAdapter.getCount() == 0) {
return false;
}
DevicePolicyEventLogger
@@ -382,20 +383,6 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
return true;
}
- /**
- * Returns {@code true} if there is at least one app resolved in the work profile,
- * regardless of whether the work profile is enabled or not.
- */
- private boolean hasResolvedAppsInWorkProfile(ResolverListAdapter listAdapter) {
- List<ResolverActivity.ResolvedComponentInfo> userStateIndependentWorkResolvers =
- listAdapter.mResolverListController.getUserStateIndependentResolversAsUser(
- listAdapter.getIntents(), mWorkProfileUserHandle);
- return userStateIndependentWorkResolvers.stream()
- .anyMatch(resolvedComponentInfo ->
- resolvedComponentInfo.getResolveInfoAt(0).targetUserId
- == UserHandle.USER_CURRENT);
- }
-
private void maybeShowNoAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
UserHandle listUserHandle = listAdapter.getUserHandle();
if (mWorkProfileUserHandle != null
@@ -529,6 +516,13 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
return false;
}
+ boolean shouldShowEmptyStateScreen(ResolverListAdapter listAdapter) {
+ int count = listAdapter.getUnfilteredCount();
+ return (count == 0 && listAdapter.getPlaceholderCount() == 0)
+ || (listAdapter.getUserHandle().equals(mWorkProfileUserHandle)
+ && isQuietModeEnabled(mWorkProfileUserHandle));
+ }
+
protected class ProfileDescriptor {
final ViewGroup rootView;
private final ViewGroup mEmptyStateView;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 35253b68aac7..fc3f20f7a556 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -994,7 +994,7 @@ public class ResolverActivity extends Activity implements
if (isAutolaunching() || maybeAutolaunchActivity()) {
return;
}
- if (isResolverListEmpty(listAdapter)) {
+ if (mMultiProfilePagerAdapter.shouldShowEmptyStateScreen(listAdapter)) {
mMultiProfilePagerAdapter.showEmptyResolverListEmptyState(listAdapter);
} else {
mMultiProfilePagerAdapter.showListView(listAdapter);
@@ -1641,16 +1641,11 @@ public class ResolverActivity extends Activity implements
private void setupViewVisibilities() {
ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();
- if (!isResolverListEmpty(activeListAdapter)) {
+ if (!mMultiProfilePagerAdapter.shouldShowEmptyStateScreen(activeListAdapter)) {
addUseDifferentAppLabelIfNecessary(activeListAdapter);
}
}
- private boolean isResolverListEmpty(ResolverListAdapter listAdapter) {
- int count = listAdapter.getUnfilteredCount();
- return count == 0 && listAdapter.getPlaceholderCount() == 0;
- }
-
/**
* Add a label to signify that the user can pick a different app.
* @param adapter The adapter used to provide data to item views.
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 3f897a5f26bf..033ac72dda4e 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -121,23 +121,13 @@ public class ResolverListController {
List<Intent> intents,
UserHandle userHandle) {
int baseFlags = PackageManager.MATCH_DEFAULT_ONLY
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
| (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0);
return getResolversForIntentAsUserInternal(intents, userHandle, baseFlags);
}
- /**
- * Returns a list of resolved intents which is user state-independent. This means it will
- * return the same results regardless of whether the {@code userHandle} user is disabled or not.
- */
- public List<ResolverActivity.ResolvedComponentInfo> getUserStateIndependentResolversAsUser(
- List<Intent> intents,
- UserHandle userHandle) {
- int baseFlags = PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
- return getResolversForIntentAsUserInternal(intents, userHandle, baseFlags);
- }
-
private List<ResolverActivity.ResolvedComponentInfo> getResolversForIntentAsUserInternal(
List<Intent> intents,
UserHandle userHandle,
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 5a979ac97c54..26684201019c 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -40,7 +40,6 @@ import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
@@ -387,14 +386,17 @@ public class ConversationLayout extends FrameLayout
/** @hide */
public void setUnreadCount(int unreadCount) {
- mUnreadBadge.setVisibility(mIsCollapsed && unreadCount > 1 ? VISIBLE : GONE);
- CharSequence text = unreadCount >= 100
- ? getResources().getString(R.string.unread_convo_overflow, 99)
- : String.format(Locale.getDefault(), "%d", unreadCount);
- mUnreadBadge.setText(text);
- mUnreadBadge.setBackgroundTintList(ColorStateList.valueOf(mLayoutColor));
- boolean needDarkText = ColorUtils.calculateLuminance(mLayoutColor) > 0.5f;
- mUnreadBadge.setTextColor(needDarkText ? Color.BLACK : Color.WHITE);
+ boolean visible = mIsCollapsed && unreadCount > 1;
+ mUnreadBadge.setVisibility(visible ? VISIBLE : GONE);
+ if (visible) {
+ CharSequence text = unreadCount >= 100
+ ? getResources().getString(R.string.unread_convo_overflow, 99)
+ : String.format(Locale.getDefault(), "%d", unreadCount);
+ mUnreadBadge.setText(text);
+ mUnreadBadge.setBackgroundTintList(ColorStateList.valueOf(mLayoutColor));
+ boolean needDarkText = ColorUtils.calculateLuminance(mLayoutColor) > 0.5f;
+ mUnreadBadge.setTextColor(needDarkText ? Color.BLACK : Color.WHITE);
+ }
}
private void addRemoteInputHistoryToMessages(
@@ -537,37 +539,26 @@ public class ConversationLayout extends FrameLayout
}
private void updateImageMessages() {
- boolean displayExternalImage = false;
- ArraySet<View> newMessages = new ArraySet<>();
- if (mIsCollapsed) {
-
- // When collapsed, we're displaying all image messages in a dedicated container
- // on the right of the layout instead of inline. Let's add all isolated images there
- int imageIndex = 0;
- for (int i = 0; i < mGroups.size(); i++) {
- MessagingGroup messagingGroup = mGroups.get(i);
- MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage();
- if (isolatedMessage != null) {
- newMessages.add(isolatedMessage.getView());
- displayExternalImage = true;
- if (imageIndex
- != mImageMessageContainer.indexOfChild(isolatedMessage.getView())) {
- mImageMessageContainer.removeView(isolatedMessage.getView());
- mImageMessageContainer.addView(isolatedMessage.getView(), imageIndex);
- }
- imageIndex++;
- }
+ View newMessage = null;
+ if (mIsCollapsed && mGroups.size() > 0) {
+
+ // When collapsed, we're displaying the image message in a dedicated container
+ // on the right of the layout instead of inline. Let's add the isolated image there
+ MessagingGroup messagingGroup = mGroups.get(mGroups.size() -1);
+ MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage();
+ if (isolatedMessage != null) {
+ newMessage = isolatedMessage.getView();
}
}
// Remove all messages that don't belong into the image layout
- for (int i = 0; i < mImageMessageContainer.getChildCount(); i++) {
- View child = mImageMessageContainer.getChildAt(i);
- if (!newMessages.contains(child)) {
- mImageMessageContainer.removeView(child);
- i--;
+ View previousMessage = mImageMessageContainer.getChildAt(0);
+ if (previousMessage != newMessage) {
+ mImageMessageContainer.removeView(previousMessage);
+ if (newMessage != null) {
+ mImageMessageContainer.addView(newMessage);
}
}
- mImageMessageContainer.setVisibility(displayExternalImage ? VISIBLE : GONE);
+ mImageMessageContainer.setVisibility(newMessage != null ? VISIBLE : GONE);
}
private void bindFacePile() {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index b2ca0a7bcbe3..b11c4c92ff33 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -29,11 +29,13 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_view_SurfaceSession.h>
+#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
+#include <private/gui/ComposerService.h>
#include <stdio.h>
#include <system/graphics.h>
#include <ui/ConfigStoreTypes.h>
@@ -624,6 +626,23 @@ static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj,
transaction->setFrameRate(ctrl, frameRate, static_cast<int8_t>(compatibility));
}
+static jlong nativeAcquireFrameRateFlexibilityToken(JNIEnv* env, jclass clazz) {
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<IBinder> token;
+ status_t result = composer->acquireFrameRateFlexibilityToken(&token);
+ if (result < 0) {
+ ALOGE("Failed acquiring frame rate flexibility token: %s (%d)", strerror(-result), result);
+ return 0;
+ }
+ token->incStrong((void*)nativeAcquireFrameRateFlexibilityToken);
+ return reinterpret_cast<jlong>(token.get());
+}
+
+static void nativeReleaseFrameRateFlexibilityToken(JNIEnv* env, jclass clazz, jlong tokenLong) {
+ sp<IBinder> token(reinterpret_cast<IBinder*>(tokenLong));
+ token->decStrong((void*)nativeAcquireFrameRateFlexibilityToken);
+}
+
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
jlongArray array = env->NewLongArray(displayIds.size());
@@ -1474,6 +1493,10 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetShadowRadius },
{"nativeSetFrameRate", "(JJFI)V",
(void*)nativeSetFrameRate },
+ {"nativeAcquireFrameRateFlexibilityToken", "()J",
+ (void*)nativeAcquireFrameRateFlexibilityToken },
+ {"nativeReleaseFrameRateFlexibilityToken", "(J)V",
+ (void*)nativeReleaseFrameRateFlexibilityToken },
{"nativeGetPhysicalDisplayIds", "()[J",
(void*)nativeGetPhysicalDisplayIds },
{"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
diff --git a/core/res/res/layout/resolver_empty_states.xml b/core/res/res/layout/resolver_empty_states.xml
index a41d717a83bd..5890bed11b07 100644
--- a/core/res/res/layout/resolver_empty_states.xml
+++ b/core/res/res/layout/resolver_empty_states.xml
@@ -19,62 +19,66 @@
android:id="@+id/resolver_empty_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
android:gravity="center_horizontal"
android:visibility="gone"
- android:paddingTop="48dp"
- android:paddingBottom="48dp"
android:paddingStart="24dp"
android:paddingEnd="24dp">
- <ImageView
- android:id="@+id/resolver_empty_state_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_centerHorizontal="true" />
- <TextView
- android:id="@+id/resolver_empty_state_title"
- android:layout_below="@+id/resolver_empty_state_icon"
- android:layout_marginTop="8dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:fontFamily="@string/config_headlineFontFamilyMedium"
- android:textColor="@color/resolver_empty_state_text"
- android:textSize="14sp"
- android:layout_centerHorizontal="true" />
- <TextView
- android:id="@+id/resolver_empty_state_subtitle"
- android:layout_below="@+id/resolver_empty_state_title"
- android:layout_marginTop="4dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/resolver_empty_state_text"
- android:textSize="12sp"
- android:gravity="center_horizontal"
- android:layout_centerHorizontal="true" />
- <Button
- android:id="@+id/resolver_empty_state_button"
- android:layout_below="@+id/resolver_empty_state_subtitle"
- android:layout_marginTop="16dp"
- android:text="@string/resolver_switch_on_work"
- android:layout_width="wrap_content"
+ <RelativeLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:fontFamily="@string/config_headlineFontFamilyMedium"
- android:textSize="14sp"
- android:textColor="?attr/colorAccent"
- android:layout_centerHorizontal="true"
- android:background="@drawable/resolver_turn_on_work_button_ripple_background"/>
- <ProgressBar
- android:id="@+id/resolver_empty_state_progress"
- style="@style/Widget.Material.Light.ProgressBar"
- android:visibility="gone"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:indeterminate="true"
- android:layout_alignTop="@+id/resolver_empty_state_icon"
- android:layout_alignBottom="@+id/resolver_empty_state_button"
- android:layout_centerHorizontal="true"
- android:layout_below="@+id/resolver_empty_state_subtitle"
- android:indeterminateTint="?attr/colorAccent"/>
+ android:paddingTop="48dp"
+ android:paddingBottom="48dp"
+ android:gravity="center_horizontal">
+ <ImageView
+ android:id="@+id/resolver_empty_state_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_centerHorizontal="true" />
+ <TextView
+ android:id="@+id/resolver_empty_state_title"
+ android:layout_below="@+id/resolver_empty_state_icon"
+ android:layout_marginTop="8dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@string/config_headlineFontFamilyMedium"
+ android:textColor="@color/resolver_empty_state_text"
+ android:textSize="14sp"
+ android:layout_centerHorizontal="true" />
+ <TextView
+ android:id="@+id/resolver_empty_state_subtitle"
+ android:layout_below="@+id/resolver_empty_state_title"
+ android:layout_marginTop="4dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/resolver_empty_state_text"
+ android:textSize="12sp"
+ android:gravity="center_horizontal"
+ android:layout_centerHorizontal="true" />
+ <Button
+ android:id="@+id/resolver_empty_state_button"
+ android:layout_below="@+id/resolver_empty_state_subtitle"
+ android:layout_marginTop="16dp"
+ android:text="@string/resolver_switch_on_work"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@string/config_headlineFontFamilyMedium"
+ android:textSize="14sp"
+ android:textColor="?attr/colorAccent"
+ android:layout_centerHorizontal="true"
+ android:background="@drawable/resolver_turn_on_work_button_ripple_background"/>
+ <ProgressBar
+ android:id="@+id/resolver_empty_state_progress"
+ style="@style/Widget.Material.Light.ProgressBar"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:indeterminate="true"
+ android:layout_alignTop="@+id/resolver_empty_state_icon"
+ android:layout_alignBottom="@+id/resolver_empty_state_button"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@+id/resolver_empty_state_subtitle"
+ android:indeterminateTint="?attr/colorAccent"/>
+ </RelativeLayout>
<TextView android:id="@+id/empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index bc0cdc1e029b..583c75102d52 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -1339,15 +1339,8 @@ public class ChooserActivityTest {
createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
List<ResolvedComponentInfo> workResolvedComponentInfos =
createResolvedComponentsForTest(workProfileTargets);
- when(sOverrides.workResolverListController.getUserStateIndependentResolversAsUser(
- Mockito.isA(List.class),
- Mockito.isA(UserHandle.class)))
- .thenReturn(new ArrayList<>(workResolvedComponentInfos));
sOverrides.isQuietModeEnabled = true;
- // When work profile is disabled, we get 0 results when we query the work profile
- // intents.
- setupResolverControllers(personalResolvedComponentInfos,
- /* workResolvedComponentInfos */ new ArrayList<>());
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendTextIntent();
sendIntent.setType("TestType");
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 0bf8663c7a85..eb39d58019d9 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -614,15 +614,8 @@ public class ResolverActivityTest {
createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
List<ResolvedComponentInfo> workResolvedComponentInfos =
createResolvedComponentsForTest(workProfileTargets);
- when(sOverrides.workResolverListController.getUserStateIndependentResolversAsUser(
- Mockito.isA(List.class),
- Mockito.isA(UserHandle.class)))
- .thenReturn(new ArrayList<>(workResolvedComponentInfos));
sOverrides.isQuietModeEnabled = true;
- // When work profile is disabled, we get 0 results when we query the work profile
- // intents.
- setupResolverControllers(personalResolvedComponentInfos,
- /* workResolvedComponentInfos */ new ArrayList<>());
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
Intent sendIntent = createSendImageIntent();
sendIntent.setType("TestType");
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 41aa1ff80e3c..5088494d6a07 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -418,9 +418,9 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
auto data = picture->serialize();
savePictureAsync(data, mCapturedFile);
mCaptureSequence = 0;
+ mCaptureMode = CaptureMode::None;
}
}
- mCaptureMode = CaptureMode::None;
mRecorder.reset();
}
}
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 90bcd1c0e370..1208062d9da0 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -403,3 +403,40 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) {
renderThread.destroyRenderingContext();
EXPECT_FALSE(pipeline->isSurfaceReady());
}
+
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, pictureCallback) {
+ // create a pipeline and add a picture callback
+ auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+ int callbackCount = 0;
+ pipeline->setPictureCapturedCallback(
+ [&callbackCount](sk_sp<SkPicture>&& picture) { callbackCount += 1; });
+
+ // create basic red frame and render it
+ auto redNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+ redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
+ LayerUpdateQueue layerUpdateQueue;
+ SkRect dirty = SkRectMakeLargest();
+ std::vector<sp<RenderNode>> renderNodes;
+ renderNodes.push_back(redNode);
+ bool opaque = true;
+ android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
+ auto surface = SkSurface::MakeRasterN32Premul(1, 1);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+ SkMatrix::I());
+
+ // verify the callback was called
+ EXPECT_EQ(1, callbackCount);
+
+ // render a second frame and check the callback count
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+ SkMatrix::I());
+ EXPECT_EQ(2, callbackCount);
+
+ // unset the callback, render another frame, check callback was not invoked
+ pipeline->setPictureCapturedCallback(nullptr);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+ SkMatrix::I());
+ EXPECT_EQ(2, callbackCount);
+}
diff --git a/media/java/android/media/MediaMetrics.java b/media/java/android/media/MediaMetrics.java
index 88a829546989..540955f3b393 100644
--- a/media/java/android/media/MediaMetrics.java
+++ b/media/java/android/media/MediaMetrics.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Bundle;
@@ -24,6 +25,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
+import java.util.Objects;
/**
* MediaMetrics is the Java interface to the MediaMetrics service.
@@ -50,6 +52,77 @@ public class MediaMetrics {
private static final Charset MEDIAMETRICS_CHARSET = StandardCharsets.UTF_8;
/**
+ * Key interface.
+ *
+ * The presence of this {@code Key} interface on an object allows
+ * it to be used to set metrics.
+ *
+ * @param <T> type of value associated with {@code Key}.
+ */
+ public interface Key<T> {
+ /**
+ * Returns the internal name of the key.
+ */
+ @NonNull
+ String getName();
+
+ /**
+ * Returns the class type of the associated value.
+ */
+ @NonNull
+ Class<T> getValueClass();
+ }
+
+ /**
+ * Returns a Key object with the correct interface for MediaMetrics.
+ *
+ * @param name The name of the key.
+ * @param type The class type of the value represented by the key.
+ * @param <T> The type of value.
+ * @return a new key interface.
+ */
+ @NonNull
+ public static <T> Key<T> createKey(@NonNull String name, @NonNull Class<T> type) {
+ // Implementation specific.
+ return new Key<T>() {
+ private final String mName = name;
+ private final Class<T> mType = type;
+
+ @Override
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ @Override
+ @NonNull
+ public Class<T> getValueClass() {
+ return mType;
+ }
+
+ /**
+ * Return true if the name and the type of two objects are the same.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof Key)) {
+ return false;
+ }
+ Key<?> other = (Key<?>) obj;
+ return mName.equals(other.getName()) && mType.equals(other.getValueClass());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mType);
+ }
+ };
+ }
+
+ /**
* Item records properties and delivers to the MediaMetrics service
*
*/
@@ -202,6 +275,28 @@ public class MediaMetrics {
}
/**
+ * Sets a metrics typed key
+ * @param key
+ * @param value
+ * @param <T>
+ * @return
+ */
+ @NonNull
+ public <T> Item set(@NonNull Key<T> key, @Nullable T value) {
+ if (value instanceof Integer) {
+ putInt(key.getName(), (int) value);
+ } else if (value instanceof Long) {
+ putLong(key.getName(), (long) value);
+ } else if (value instanceof Double) {
+ putDouble(key.getName(), (double) value);
+ } else if (value instanceof String) {
+ putString(key.getName(), (String) value);
+ }
+ // if value is null, etc. no error is raised.
+ return this;
+ }
+
+ /**
* Sets the property with key to an integer (32 bit) value.
*
* @param key
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 07f4a9a799ad..53e7921879d1 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -566,7 +566,7 @@
<!-- [CHAR LIMIT=50] Title for adb wireless pair by QR code preference -->
<string name="adb_pair_method_qrcode_title">Pair device with QR code</string>
<!-- [CHAR LIMIT=NONE] Summary for adb wireless pair by QR code preference -->
- <string name="adb_pair_method_qrcode_summary">Pair new devices using QR code Scanner</string>
+ <string name="adb_pair_method_qrcode_summary">Pair new devices using QR code scanner</string>
<!-- [CHAR LIMIT=50] Title for adb wireless pair by pairing code preference -->
<string name="adb_pair_method_code_title">Pair device with pairing code</string>
<!-- [CHAR LIMIT=NONE] Summary for adb wireless pair by pairing code preference -->
@@ -604,7 +604,7 @@
<!-- [CHAR LIMIT=NONE] Adb Wireless QR code pairing scanner title -->
<string name="adb_wireless_qrcode_pairing_title">Scan QR code</string>
<!-- [CHAR LIMIT=NONE] Adb Wireless QR code pairing description -->
- <string name="adb_wireless_qrcode_pairing_description">Pair device over Wi\u2011Fi by scanning a QR Code</string>
+ <string name="adb_wireless_qrcode_pairing_description">Pair device over Wi\u2011Fi by scanning a QR code</string>
<!-- [CHAR LIMIT=NONE] Toast message when trying to enable Wi-Fi debugging and no Wi-Fi network connected -->
<string name="adb_wireless_no_network_msg">Please connect to a Wi\u2011Fi network</string>
<!--Adb wireless search Keywords [CHAR LIMIT=NONE]-->
diff --git a/packages/SystemUI/res/layout/bubble_dismiss_target.xml b/packages/SystemUI/res/layout/bubble_dismiss_target.xml
index ca085b69c35d..f5cd727a6d03 100644
--- a/packages/SystemUI/res/layout/bubble_dismiss_target.xml
+++ b/packages/SystemUI/res/layout/bubble_dismiss_target.xml
@@ -17,7 +17,7 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
- android:layout_height="@dimen/pip_dismiss_gradient_height"
+ android:layout_height="@dimen/floating_dismiss_gradient_height"
android:layout_gravity="bottom|center_horizontal">
<FrameLayout
diff --git a/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml
index 50aa212c94a6..cb53fe619b24 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml
@@ -27,7 +27,7 @@
android:paddingRight="@dimen/global_actions_grid_item_side_margin"
android:layout_marginRight="3dp"
android:layout_marginLeft="3dp"
- android:background="@drawable/rounded_bg_full">
+ android:background="@drawable/control_background">
<LinearLayout
android:layout_width="@dimen/global_actions_grid_item_width"
android:layout_height="@dimen/global_actions_grid_item_height"
@@ -42,7 +42,7 @@
android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
android:scaleType="centerInside"
- android:tint="@color/global_actions_text" />
+ android:tint="@color/control_default_foreground" />
<TextView
android:id="@*android:id/message"
@@ -53,7 +53,7 @@
android:singleLine="true"
android:gravity="center"
android:textSize="12dp"
- android:textColor="@color/global_actions_text"
+ android:textColor="@color/control_default_foreground"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
@@ -62,7 +62,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
- android:textColor="@color/global_actions_text"
+ android:textColor="@color/control_default_foreground"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/pip_dismiss_view.xml b/packages/SystemUI/res/layout/pip_dismiss_view.xml
deleted file mode 100644
index 2cc4b220fe2b..000000000000
--- a/packages/SystemUI/res/layout/pip_dismiss_view.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="@dimen/pip_dismiss_gradient_height"
- android:alpha="0">
-
- <TextView
- android:id="@+id/pip_dismiss_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|center_horizontal"
- android:text="@string/pip_phone_dismiss_hint"
- android:textColor="#FFFFFFFF"
- android:textSize="14sp"
- android:shadowColor="@android:color/black"
- android:shadowDx="-2"
- android:shadowDy="2"
- android:shadowRadius="0.01" />
-
-</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9b9fbed0d904..bce5fac76cfc 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -955,7 +955,7 @@
<dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen>
<!-- The height of the gradient indicating the dismiss edge when moving a PIP. -->
- <dimen name="pip_dismiss_gradient_height">176dp</dimen>
+ <dimen name="floating_dismiss_gradient_height">176dp</dimen>
<!-- The bottom margin of the PIP drag to dismiss info text shown when moving a PIP. -->
<dimen name="pip_dismiss_text_bottom_margin">24dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index caee8ccb6970..88f4176f5eac 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -34,6 +34,7 @@ import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
/**
@@ -50,6 +51,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
private boolean mDismissing;
protected boolean mResumed;
private CountDownTimer mCountdownTimer = null;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
// To avoid accidental lockout due to events while the device in in the pocket, ignore
// any passwords with length less than or equal to this length.
@@ -61,6 +63,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
}
@Override
@@ -151,6 +154,8 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
}
+
+ mKeyguardUpdateMonitor.setCredentialAttempted();
mPendingLockCheck = LockPatternChecker.checkCredential(
mLockPatternUtils,
password,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 48c6bd114d4a..ad92f8f623e4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -282,6 +282,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
@Override
public void onPatternDetected(final List<LockPatternView.Cell> pattern) {
+ mKeyguardUpdateMonitor.setCredentialAttempted();
mLockPatternView.disableInput();
if (mPendingLockCheck != null) {
mPendingLockCheck.cancel(false);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 57e3f14d7aed..88d6943b4071 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -223,6 +223,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private int mRingMode;
private int mPhoneState;
private boolean mKeyguardIsVisible;
+ private boolean mCredentialAttempted;
private boolean mKeyguardGoingAway;
private boolean mGoingToSleep;
private boolean mBouncer;
@@ -498,11 +499,21 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
/**
+ * Updates KeyguardUpdateMonitor's internal state to know if credential was attempted on
+ * bouncer. Note that this does not care if the credential was correct/incorrect. This is
+ * cleared when the user leaves the bouncer (unlocked, screen off, back to lockscreen, etc)
+ */
+ public void setCredentialAttempted() {
+ mCredentialAttempted = true;
+ updateBiometricListeningState();
+ }
+
+ /**
* Updates KeyguardUpdateMonitor's internal state to know if keyguard is goingAway
*/
public void setKeyguardGoingAway(boolean goingAway) {
mKeyguardGoingAway = goingAway;
- updateFingerprintListeningState();
+ updateBiometricListeningState();
}
/**
@@ -664,6 +675,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
updateFingerprintListeningState();
} else {
setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
+ mFingerprintCancelSignal = null;
+ mFaceCancelSignal = null;
}
if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
@@ -679,6 +692,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
getCurrentUser());
}
+ if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT
+ || msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
+ mFingerprintLockedOut = true;
+ }
+
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -688,6 +706,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
private void handleFingerprintLockoutReset() {
+ mFingerprintLockedOut = false;
updateFingerprintListeningState();
}
@@ -1274,6 +1293,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private CancellationSignal mFaceCancelSignal;
private FingerprintManager mFpm;
private FaceManager mFaceManager;
+ private boolean mFingerprintLockedOut;
/**
* When we receive a
@@ -1820,13 +1840,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
private boolean shouldListenForFingerprint() {
+ final boolean allowedOnBouncer =
+ !(mFingerprintLockedOut && mBouncer && mCredentialAttempted);
+
// Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
// instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
final boolean shouldListen = (mKeyguardIsVisible || !mDeviceInteractive ||
(mBouncer && !mKeyguardGoingAway) || mGoingToSleep ||
shouldListenForFingerprintAssistant() || (mKeyguardOccluded && mIsDreaming))
&& !mSwitchingUser && !isFingerprintDisabled(getCurrentUser())
- && (!mKeyguardGoingAway || !mDeviceInteractive) && mIsPrimaryUser;
+ && (!mKeyguardGoingAway || !mDeviceInteractive) && mIsPrimaryUser
+ && allowedOnBouncer;
return shouldListen;
}
@@ -2372,6 +2396,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// camera requests dismiss keyguard (tapping on photos for example). When these happen,
// face auth should resume.
mSecureCameraLaunched = false;
+ } else {
+ mCredentialAttempted = false;
}
for (int i = 0; i < mCallbacks.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index eff693436451..044feaa117c8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -514,7 +514,7 @@ public class BubbleStackView extends FrameLayout {
mDismissTargetContainer = new FrameLayout(context);
mDismissTargetContainer.setLayoutParams(new FrameLayout.LayoutParams(
MATCH_PARENT,
- getResources().getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height),
+ getResources().getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height),
Gravity.BOTTOM));
mDismissTargetContainer.setClipChildren(false);
mDismissTargetContainer.addView(targetView);
@@ -523,7 +523,7 @@ public class BubbleStackView extends FrameLayout {
// Start translated down so the target springs up.
targetView.setTranslationY(
- getResources().getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height));
+ getResources().getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height));
// Save the MagneticTarget instance for the newly set up view - we'll add this to the
// MagnetizedObjects.
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index f2303e622f8d..fe1e6328820d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -55,13 +55,19 @@ class ControlsFavoritingActivity @Inject constructor(
companion object {
private const val TAG = "ControlsFavoritingActivity"
+
+ // If provided and no structure is available, use as the title
const val EXTRA_APP = "extra_app_label"
+
+ // If provided, show this structure page first
+ const val EXTRA_STRUCTURE = "extra_structure"
private const val TOOLTIP_PREFS_KEY = Prefs.Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT
private const val TOOLTIP_MAX_SHOWN = 2
}
private var component: ComponentName? = null
private var appName: CharSequence? = null
+ private var structureExtra: CharSequence? = null
private lateinit var structurePager: ViewPager2
private lateinit var statusText: TextView
@@ -111,6 +117,7 @@ class ControlsFavoritingActivity @Inject constructor(
val collator = Collator.getInstance(resources.configuration.locales[0])
comparator = compareBy(collator) { it.structureName }
appName = intent.getCharSequenceExtra(EXTRA_APP)
+ structureExtra = intent.getCharSequenceExtra(EXTRA_STRUCTURE) ?: ""
component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
bindViews()
@@ -137,9 +144,15 @@ class ControlsFavoritingActivity @Inject constructor(
listOfStructures = controlsByStructure.map {
StructureContainer(it.key, AllModel(it.value, favoriteKeys, emptyZoneString))
}.sortedWith(comparator)
+
+ val structureIndex = listOfStructures.indexOfFirst {
+ sc -> sc.structureName == structureExtra
+ }.let { if (it == -1) 0 else it }
+
executor.execute {
doneButton.isEnabled = true
structurePager.adapter = StructureAdapter(listOfStructures)
+ structurePager.setCurrentItem(structureIndex)
if (error) {
statusText.text = resources.getText(R.string.controls_favorite_load_error)
} else {
@@ -247,7 +260,10 @@ class ControlsFavoritingActivity @Inject constructor(
requireViewById<Button>(R.id.other_apps).apply {
visibility = View.VISIBLE
setOnClickListener {
- this@ControlsFavoritingActivity.onBackPressed()
+ val i = Intent()
+ i.setComponent(
+ ComponentName(context, ControlsProviderSelectorActivity::class.java))
+ context.startActivity(i)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 6e527e29a848..208d9117e088 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -45,6 +45,7 @@ import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.StructureInfo
+import com.android.systemui.controls.management.ControlsFavoritingActivity
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.dagger.qualifiers.Background
@@ -92,21 +93,8 @@ class ControlsUiControllerImpl @Inject constructor (
private lateinit var lastItems: List<SelectionItem>
private var popup: ListPopupWindow? = null
private var activeDialog: Dialog? = null
- private val addControlsItem: SelectionItem
private var hidden = true
- init {
- val addDrawable = context.getDrawable(R.drawable.ic_add).apply {
- setTint(context.resources.getColor(R.color.control_secondary_text, null))
- }
- addControlsItem = SelectionItem(
- context.resources.getString(R.string.controls_providers_title),
- "",
- addDrawable,
- EMPTY_COMPONENT
- )
- }
-
override val available: Boolean
get() = controlsController.get().available
@@ -184,7 +172,7 @@ class ControlsUiControllerImpl @Inject constructor (
inflater.inflate(R.layout.controls_no_favorites, parent, true)
val viewGroup = parent.requireViewById(R.id.controls_no_favorites_group) as ViewGroup
- viewGroup.setOnClickListener(launchSelectorActivityListener(context))
+ viewGroup.setOnClickListener { v: View -> startProviderSelectorActivity(v.context) }
val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
subtitle.setText(context.resources.getString(R.string.quick_controls_subtitle))
@@ -198,16 +186,28 @@ class ControlsUiControllerImpl @Inject constructor (
}
}
- private fun launchSelectorActivityListener(context: Context): (View) -> Unit {
- return { _ ->
- val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
- context.sendBroadcast(closeDialog)
+ private fun startFavoritingActivity(context: Context, si: StructureInfo) {
+ val i = Intent(context, ControlsFavoritingActivity::class.java).apply {
+ putExtra(ControlsFavoritingActivity.EXTRA_APP,
+ controlsListingController.get().getAppLabel(si.componentName))
+ putExtra(ControlsFavoritingActivity.EXTRA_STRUCTURE, si.structure)
+ putExtra(Intent.EXTRA_COMPONENT_NAME, si.componentName)
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ startActivity(context, i)
+ }
- val i = Intent()
- i.setComponent(ComponentName(context, ControlsProviderSelectorActivity::class.java))
- i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
- context.startActivity(i)
+ private fun startProviderSelectorActivity(context: Context) {
+ val i = Intent(context, ControlsProviderSelectorActivity::class.java).apply {
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
}
+ startActivity(context, i)
+ }
+
+ private fun startActivity(context: Context, intent: Intent) {
+ val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
+ context.sendBroadcast(closeDialog)
+ context.startActivity(intent)
}
private fun showControlsView(items: List<SelectionItem>) {
@@ -248,7 +248,7 @@ class ControlsUiControllerImpl @Inject constructor (
) {
when (pos) {
// 0: Add Control
- 0 -> launchSelectorActivityListener(view.context)(parent)
+ 0 -> startFavoritingActivity(view.context, selectedStructure)
else -> Log.w(ControlsUiController.TAG,
"Unsupported index ($pos) on 'more' menu selection")
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index fdd859373685..4dd5e87d2c93 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -489,6 +489,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mAdapter = new MyAdapter();
+ mDepthController.setShowingHomeControls(shouldShowControls());
ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, getWalletPanelViewController(),
mDepthController, mSysuiColorExtractor, mStatusBarService,
mNotificationShadeWindowController,
@@ -1780,8 +1781,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
if (mBackgroundDrawable == null) {
mBackgroundDrawable = new ScrimDrawable();
- mScrimAlpha = mBlurUtils.supportsBlursOnWindows()
- ? ScrimController.BLUR_SCRIM_ALPHA : ScrimController.BUSY_SCRIM_ALPHA;
+ if (mControlsUiController != null) {
+ mScrimAlpha = 1.0f;
+ } else {
+ mScrimAlpha = mBlurUtils.supportsBlursOnWindows()
+ ? ScrimController.BLUR_SCRIM_ALPHA : ScrimController.BUSY_SCRIM_ALPHA;
+ }
}
getWindow().setBackgroundDrawable(mBackgroundDrawable);
}
@@ -1841,8 +1846,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
if (!(mBackgroundDrawable instanceof ScrimDrawable)) {
return;
}
- ((ScrimDrawable) mBackgroundDrawable).setColor(colors.supportsDarkText() ? Color.WHITE
- : Color.BLACK, animate);
+ boolean hasControls = mControlsUiController != null;
+ ((ScrimDrawable) mBackgroundDrawable).setColor(
+ !hasControls && colors.supportsDarkText() ? Color.WHITE : Color.BLACK, animate);
View decorView = getWindow().getDecorView();
if (colors.supportsDarkText()) {
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
deleted file mode 100644
index b7258117c48c..000000000000
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.pip.phone;
-
-import android.content.Context;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.widget.FrameLayout;
-
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.shared.system.WindowManagerWrapper;
-
-/**
- * Displays the dismiss UI and target for floating objects.
- */
-public class PipDismissViewController {
-
- // This delay controls how long to wait before we show the target when the user first moves
- // the PIP, to prevent the target from animating if the user just wants to fling the PIP
- public static final int SHOW_TARGET_DELAY = 100;
- private static final int SHOW_TARGET_DURATION = 350;
- private static final int HIDE_TARGET_DURATION = 225;
-
- private Context mContext;
- private WindowManager mWindowManager;
- private View mDismissView;
-
- // Used for dismissing a bubble -- bubble should be in the target to be considered a dismiss
- private View mTargetView;
- private int mTargetSlop;
- private Point mWindowSize;
- private int[] mLoc = new int[2];
- private boolean mIntersecting;
- private Vibrator mVibe;
-
- public PipDismissViewController(Context context) {
- mContext = context;
- mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- mVibe = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
- }
-
- /**
- * Creates the dismiss target for showing via {@link #showDismissTarget()}.
- */
- public void createDismissTarget() {
- if (mDismissView == null) {
- // Determine sizes for the view
- final Rect stableInsets = new Rect();
- WindowManagerWrapper.getInstance().getStableInsets(stableInsets);
- mWindowSize = new Point();
- mWindowManager.getDefaultDisplay().getRealSize(mWindowSize);
- final int gradientHeight = mContext.getResources().getDimensionPixelSize(
- R.dimen.pip_dismiss_gradient_height);
- final int bottomMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.pip_dismiss_text_bottom_margin);
- mTargetSlop = mContext.getResources().getDimensionPixelSize(
- R.dimen.bubble_dismiss_slop);
-
- // Create a new view for the dismiss target
- LayoutInflater inflater = LayoutInflater.from(mContext);
- mDismissView = inflater.inflate(R.layout.pip_dismiss_view, null);
- mDismissView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
- mDismissView.forceHasOverlappingRendering(false);
-
- // Set the gradient background
- Drawable gradient = mContext.getResources().getDrawable(R.drawable.pip_dismiss_scrim);
- gradient.setAlpha((int) (255 * 0.85f));
- mDismissView.setBackground(gradient);
-
- // Adjust bottom margins of the text
- mTargetView = mDismissView.findViewById(R.id.pip_dismiss_text);
- FrameLayout.LayoutParams tlp = (FrameLayout.LayoutParams) mTargetView.getLayoutParams();
- tlp.bottomMargin = stableInsets.bottom + bottomMargin;
- mTargetView.setLayoutParams(tlp);
-
- // Add the target to the window
- LayoutParams lp = new LayoutParams(
- LayoutParams.MATCH_PARENT, gradientHeight,
- 0, mWindowSize.y - gradientHeight,
- LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | LayoutParams.FLAG_NOT_TOUCHABLE
- | LayoutParams.FLAG_NOT_FOCUSABLE,
- PixelFormat.TRANSLUCENT);
- lp.setTitle("pip-dismiss-overlay");
- lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
- lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- lp.setFitInsetsTypes(0 /* types */);
- mWindowManager.addView(mDismissView, lp);
- }
- mDismissView.animate().cancel();
- }
-
-
- /**
- * Updates the dismiss target based on location of the view, only used for bubbles not for PIP.
- *
- * @return whether the view is within the dismiss target.
- */
- public boolean updateTarget(View view) {
- if (mDismissView == null) {
- return false;
- }
- if (mDismissView.getAlpha() > 0) {
- view.getLocationOnScreen(mLoc);
- Rect viewRect = new Rect(mLoc[0], mLoc[1], mLoc[0] + view.getWidth(),
- mLoc[1] + view.getHeight());
- mTargetView.getLocationOnScreen(mLoc);
- Rect targetRect = new Rect(mLoc[0], mLoc[1], mLoc[0] + mTargetView.getWidth(),
- mLoc[1] + mTargetView.getHeight());
- expandRect(targetRect, mTargetSlop);
- boolean intersecting = targetRect.intersect(viewRect);
- if (intersecting != mIntersecting) {
- // TODO: is this the right effect?
- mVibe.vibrate(VibrationEffect.get(intersecting
- ? VibrationEffect.EFFECT_CLICK
- : VibrationEffect.EFFECT_TICK));
- }
- mIntersecting = intersecting;
- return intersecting;
- }
- return false;
- }
-
- /**
- * Shows the dismiss target.
- */
- public void showDismissTarget() {
- mDismissView.animate()
- .alpha(1f)
- .setInterpolator(Interpolators.LINEAR)
- .setStartDelay(SHOW_TARGET_DELAY)
- .setDuration(SHOW_TARGET_DURATION)
- .start();
- }
-
- /**
- * Hides and destroys the dismiss target.
- */
- public void destroyDismissTarget() {
- if (mDismissView != null) {
- mDismissView.animate()
- .alpha(0f)
- .setInterpolator(Interpolators.LINEAR)
- .setStartDelay(0)
- .setDuration(HIDE_TARGET_DURATION)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- mWindowManager.removeViewImmediate(mDismissView);
- mDismissView = null;
- }
- })
- .start();
- }
- }
-
- private void expandRect(Rect outRect, int expandAmount) {
- outRect.left = Math.max(0, outRect.left - expandAmount);
- outRect.top = Math.max(0, outRect.top - expandAmount);
- outRect.right = Math.min(mWindowSize.x, outRect.right + expandAmount);
- outRect.bottom = Math.min(mWindowSize.y, outRect.bottom + expandAmount);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 8397c65dbdb0..a192afceddb9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -24,8 +24,6 @@ import android.annotation.Nullable;
import android.app.ActivityManager.StackInfo;
import android.app.IActivityTaskManager;
import android.content.Context;
-import android.graphics.Point;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Debug;
import android.os.RemoteException;
@@ -40,6 +38,7 @@ import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.animation.FloatProperties;
import com.android.systemui.util.animation.PhysicsAnimator;
+import com.android.systemui.util.magnetictarget.MagnetizedObject;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -61,9 +60,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
/** Friction to use for PIP when it moves via physics fling animations. */
private static final float DEFAULT_FRICTION = 2f;
- // The fraction of the stack height that the user has to drag offscreen to dismiss the PiP
- private static final float DISMISS_OFFSCREEN_FRACTION = 0.3f;
-
private final Context mContext;
private final IActivityTaskManager mActivityTaskManager;
private final PipTaskOrganizer mPipTaskOrganizer;
@@ -103,7 +99,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
/**
* Update listener that resizes the PIP to {@link #mAnimatedBounds}.
*/
- private final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener =
+ final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener =
(target, values) -> resizePipUnchecked(mAnimatedBounds);
/** FlingConfig instances provided to PhysicsAnimator for fling gestures. */
@@ -122,6 +118,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
private final Consumer<Rect> mUpdateBoundsCallback = mBounds::set;
+ /**
+ * Whether we're springing to the touch event location (vs. moving it to that position
+ * instantly). We spring-to-touch after PIP is dragged out of the magnetic target, since it was
+ * 'stuck' in the target and needs to catch up to the touch location.
+ */
+ private boolean mSpringingToTouch = false;
+
public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager,
PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils,
@@ -211,9 +214,35 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
mFloatingContentCoordinator.onContentMoved(this);
}
- cancelAnimations();
- resizePipUnchecked(toBounds);
- mBounds.set(toBounds);
+ if (!mSpringingToTouch) {
+ // If we are moving PIP directly to the touch event locations, cancel any animations and
+ // move PIP to the given bounds.
+ cancelAnimations();
+ resizePipUnchecked(toBounds);
+ mBounds.set(toBounds);
+ } else {
+ // If PIP is 'catching up' after being stuck in the dismiss target, update the animation
+ // to spring towards the new touch location.
+ mAnimatedBoundsPhysicsAnimator
+ .spring(FloatProperties.RECT_X, toBounds.left, mSpringConfig)
+ .spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig)
+ .withEndActions(() -> mSpringingToTouch = false);
+
+ startBoundsAnimator(toBounds.left /* toX */, toBounds.top /* toY */);
+ }
+ }
+
+ /** Set whether we're springing-to-touch to catch up after being stuck in the dismiss target. */
+ void setSpringingToTouch(boolean springingToTouch) {
+ if (springingToTouch) {
+ mAnimatedBounds.set(mBounds);
+ }
+
+ mSpringingToTouch = springingToTouch;
+ }
+
+ void prepareForAnimation() {
+ mAnimatedBounds.set(mBounds);
}
/**
@@ -278,24 +307,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
}
/**
- * @return whether the PiP at the current bounds should be dismissed.
- */
- boolean shouldDismissPip() {
- Point displaySize = new Point();
- mContext.getDisplay().getRealSize(displaySize);
- final int y = displaySize.y - mStableInsets.bottom;
- if (mBounds.bottom > y) {
- float offscreenFraction = (float) (mBounds.bottom - y) / mBounds.height();
- return offscreenFraction >= DISMISS_OFFSCREEN_FRACTION;
- }
- return false;
- }
-
- /**
* Flings the PiP to the closest snap target.
*/
void flingToSnapTarget(
- float velocityX, float velocityY, Runnable updateAction, @Nullable Runnable endAction) {
+ float velocityX, float velocityY,
+ @Nullable Runnable updateAction, @Nullable Runnable endAction) {
mAnimatedBounds.set(mBounds);
mAnimatedBoundsPhysicsAnimator
.flingThenSpring(
@@ -303,9 +319,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
true /* flingMustReachMinOrMax */)
.flingThenSpring(
FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig)
- .addUpdateListener((target, values) -> updateAction.run())
.withEndActions(endAction);
+ if (updateAction != null) {
+ mAnimatedBoundsPhysicsAnimator.addUpdateListener(
+ (target, values) -> updateAction.run());
+ }
+
final float xEndValue = velocityX < 0 ? mMovementBounds.left : mMovementBounds.right;
final float estimatedFlingYEndValue =
PhysicsAnimator.estimateFlingEndValue(mBounds.top, velocityY, mFlingConfigY);
@@ -338,16 +358,14 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
* Animates the dismissal of the PiP off the edge of the screen.
*/
void animateDismiss(float velocityX, float velocityY, @Nullable Runnable updateAction) {
- final float velocity = PointF.length(velocityX, velocityY);
- final boolean isFling = velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond();
- final Point dismissEndPoint = getDismissEndPoint(mBounds, velocityX, velocityY, isFling);
-
mAnimatedBounds.set(mBounds);
- // Animate to the dismiss end point, and then dismiss PIP.
+ // Animate off the bottom of the screen, then dismiss PIP.
mAnimatedBoundsPhysicsAnimator
- .spring(FloatProperties.RECT_X, dismissEndPoint.x, velocityX, mSpringConfig)
- .spring(FloatProperties.RECT_Y, dismissEndPoint.y, velocityY, mSpringConfig)
+ .spring(FloatProperties.RECT_Y,
+ mBounds.bottom + mBounds.height(),
+ velocityY,
+ mSpringConfig)
.withEndActions(this::dismissPip);
// If we were provided with an update action, run it whenever there's an update.
@@ -356,7 +374,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
(target, values) -> updateAction.run());
}
- startBoundsAnimator(dismissEndPoint.x /* toX */, dismissEndPoint.y /* toY */);
+ startBoundsAnimator(mBounds.left /* toX */, mBounds.bottom + mBounds.height() /* toY */);
}
/**
@@ -408,6 +426,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
private void cancelAnimations() {
mAnimatedBoundsPhysicsAnimator.cancel();
mAnimatingToBounds.setEmpty();
+ mSpringingToTouch = false;
}
/** Set new fling configs whose min/max values respect the given movement bounds. */
@@ -426,7 +445,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
* the 'real' bounds to equal the final animated bounds.
*/
private void startBoundsAnimator(float toX, float toY) {
- cancelAnimations();
+ if (!mSpringingToTouch) {
+ cancelAnimations();
+ }
// Set animatingToBounds directly to avoid allocating a new Rect, but then call
// setAnimatingToBounds to run the normal logic for changing animatingToBounds.
@@ -484,47 +505,29 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
}
/**
- * @return the coordinates the PIP should animate to based on the direction of velocity when
- * dismissing.
+ * Returns a MagnetizedObject wrapper for PIP's animated bounds. This is provided to the
+ * magnetic dismiss target so it can calculate PIP's size and position.
*/
- private Point getDismissEndPoint(Rect pipBounds, float velX, float velY, boolean isFling) {
- Point displaySize = new Point();
- mContext.getDisplay().getRealSize(displaySize);
- final float bottomBound = displaySize.y + pipBounds.height() * .1f;
- if (isFling && velX != 0 && velY != 0) {
- // Line is defined by: y = mx + b, m = slope, b = y-intercept
- // Find the slope
- final float slope = velY / velX;
- // Sub in slope and PiP position to solve for y-intercept: b = y - mx
- final float yIntercept = pipBounds.top - slope * pipBounds.left;
- // Now find the point on this line when y = bottom bound: x = (y - b) / m
- final float x = (bottomBound - yIntercept) / slope;
- return new Point((int) x, (int) bottomBound);
- } else {
- // If it wasn't a fling the velocity on 'up' is not reliable for direction of movement,
- // just animate downwards.
- return new Point(pipBounds.left, (int) bottomBound);
- }
- }
+ MagnetizedObject<Rect> getMagnetizedPip() {
+ return new MagnetizedObject<Rect>(
+ mContext, mAnimatedBounds, FloatProperties.RECT_X, FloatProperties.RECT_Y) {
+ @Override
+ public float getWidth(@NonNull Rect animatedPipBounds) {
+ return animatedPipBounds.width();
+ }
- /**
- * @return whether the gesture it towards the dismiss area based on the velocity when
- * dismissing.
- */
- public boolean isGestureToDismissArea(Rect pipBounds, float velX, float velY,
- boolean isFling) {
- Point endpoint = getDismissEndPoint(pipBounds, velX, velY, isFling);
- // Center the point
- endpoint.x += pipBounds.width() / 2;
- endpoint.y += pipBounds.height() / 2;
-
- // The dismiss area is the middle third of the screen, half the PIP's height from the bottom
- Point size = new Point();
- mContext.getDisplay().getRealSize(size);
- final int left = size.x / 3;
- Rect dismissArea = new Rect(left, size.y - (pipBounds.height() / 2), left * 2,
- size.y + pipBounds.height());
- return dismissArea.contains(endpoint.x, endpoint.y);
+ @Override
+ public float getHeight(@NonNull Rect animatedPipBounds) {
+ return animatedPipBounds.height();
+ }
+
+ @Override
+ public void getLocationOnScreen(
+ @NonNull Rect animatedPipBounds, @NonNull int[] loc) {
+ loc[0] = animatedPipBounds.left;
+ loc[1] = animatedPipBounds.top;
+ }
+ };
}
public void dump(PrintWriter pw, String prefix) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 7cc2759ad59a..bbb493966533 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -20,11 +20,13 @@ import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STAT
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
+import android.annotation.SuppressLint;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -33,14 +35,23 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;
import android.util.Size;
+import android.view.Gravity;
import android.view.IPinnedStackController;
import android.view.InputEvent;
import android.view.MotionEvent;
+import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.logging.MetricsLoggerWrapper;
@@ -51,7 +62,10 @@ import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.DismissCircleView;
import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.systemui.util.animation.PhysicsAnimator;
+import com.android.systemui.util.magnetictarget.MagnetizedObject;
import java.io.PrintWriter;
@@ -62,9 +76,6 @@ import java.io.PrintWriter;
public class PipTouchHandler {
private static final String TAG = "PipTouchHandler";
- // Allow the PIP to be flung from anywhere on the screen to the bottom to be dismissed.
- private static final boolean ENABLE_FLING_DISMISS = false;
-
private static final int SHOW_DISMISS_AFFORDANCE_DELAY = 225;
private static final int BOTTOM_OFFSET_BUFFER_DP = 1;
@@ -73,17 +84,45 @@ public class PipTouchHandler {
// Allow PIP to resize to a slightly bigger state upon touch
private final boolean mEnableResize;
private final Context mContext;
+ private final WindowManager mWindowManager;
private final IActivityManager mActivityManager;
private final PipBoundsHandler mPipBoundsHandler;
private PipResizeGestureHandler mPipResizeGestureHandler;
private IPinnedStackController mPinnedStackController;
private final PipMenuActivityController mMenuController;
- private final PipDismissViewController mDismissViewController;
private final PipSnapAlgorithm mSnapAlgorithm;
private final AccessibilityManager mAccessibilityManager;
private boolean mShowPipMenuOnAnimationEnd = false;
+ /**
+ * MagnetizedObject wrapper for PIP. This allows the magnetic target library to locate and move
+ * PIP.
+ */
+ private MagnetizedObject<Rect> mMagnetizedPip;
+
+ /**
+ * Container for the dismiss circle, so that it can be animated within the container via
+ * translation rather than within the WindowManager via slow layout animations.
+ */
+ private ViewGroup mTargetViewContainer;
+
+ /** Circle view used to render the dismiss target. */
+ private DismissCircleView mTargetView;
+
+ /**
+ * MagneticTarget instance wrapping the target view and allowing us to set its magnetic radius.
+ */
+ private MagnetizedObject.MagneticTarget mMagneticTarget;
+
+ /** PhysicsAnimator instance for animating the dismiss target in/out. */
+ private PhysicsAnimator<View> mMagneticTargetAnimator;
+
+ /** Default configuration to use for springing the dismiss target in/out. */
+ private final PhysicsAnimator.SpringConfig mTargetSpringConfig =
+ new PhysicsAnimator.SpringConfig(
+ SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_NO_BOUNCY);
+
// The current movement bounds
private Rect mMovementBounds = new Rect();
// The current resized bounds, changed by user resize.
@@ -104,21 +143,20 @@ public class PipTouchHandler {
private int mDeferResizeToNormalBoundsUntilRotation = -1;
private int mDisplayRotation;
+ /**
+ * Runnable that can be posted delayed to show the target. This needs to be saved as a member
+ * variable so we can pass it to removeCallbacks.
+ */
+ private Runnable mShowTargetAction = this::showDismissTargetMaybe;
+
private Handler mHandler = new Handler();
- private Runnable mShowDismissAffordance = new Runnable() {
- @Override
- public void run() {
- if (mEnableDismissDragToEdge) {
- mDismissViewController.showDismissTarget();
- }
- }
- };
// Behaviour states
private int mMenuState = MENU_STATE_NONE;
private boolean mIsImeShowing;
private int mImeHeight;
private int mImeOffset;
+ private int mDismissAreaHeight;
private boolean mIsShelfShowing;
private int mShelfHeight;
private int mMovementBoundsExtraOffsets;
@@ -168,6 +206,7 @@ public class PipTouchHandler {
}
}
+ @SuppressLint("InflateParams")
public PipTouchHandler(Context context, IActivityManager activityManager,
IActivityTaskManager activityTaskManager, PipMenuActivityController menuController,
InputConsumerController inputConsumerController,
@@ -180,9 +219,9 @@ public class PipTouchHandler {
mContext = context;
mActivityManager = activityManager;
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mMenuController = menuController;
mMenuController.addListener(new PipMenuListener());
- mDismissViewController = new PipDismissViewController(context);
mSnapAlgorithm = pipSnapAlgorithm;
mFlingAnimationUtils = new FlingAnimationUtils(context.getResources().getDisplayMetrics(),
2.5f);
@@ -200,6 +239,7 @@ public class PipTouchHandler {
mExpandedShortestEdgeSize = res.getDimensionPixelSize(
R.dimen.pip_expanded_shortest_edge_size);
mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
+ mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height);
mEnableDismissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge);
mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu);
@@ -212,6 +252,56 @@ public class PipTouchHandler {
mFloatingContentCoordinator = floatingContentCoordinator;
mConnection = new PipAccessibilityInteractionConnection(mMotionHelper,
this::onAccessibilityShowMenu, mHandler);
+
+ final int targetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size);
+ mTargetView = new DismissCircleView(context);
+ final FrameLayout.LayoutParams newParams =
+ new FrameLayout.LayoutParams(targetSize, targetSize);
+ newParams.gravity = Gravity.CENTER;
+ mTargetView.setLayoutParams(newParams);
+
+ mTargetViewContainer = new FrameLayout(context);
+ mTargetViewContainer.setClipChildren(false);
+ mTargetViewContainer.addView(mTargetView);
+
+ mMagnetizedPip = mMotionHelper.getMagnetizedPip();
+ mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0);
+ mMagnetizedPip.setPhysicsAnimatorUpdateListener(mMotionHelper.mResizePipUpdateListener);
+ mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() {
+ @Override
+ public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+ mMotionHelper.prepareForAnimation();
+
+ // Show the dismiss target, in case the initial touch event occurred within the
+ // magnetic field radius.
+ showDismissTargetMaybe();
+ }
+
+ @Override
+ public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
+ float velX, float velY, boolean wasFlungOut) {
+ if (wasFlungOut) {
+ mMotionHelper.flingToSnapTarget(velX, velY, null, null);
+ hideDismissTarget();
+ } else {
+ mMotionHelper.setSpringingToTouch(true);
+ }
+ }
+
+ @Override
+ public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+ mHandler.post(() -> {
+ mMotionHelper.animateDismiss(0, 0, null);
+ hideDismissTarget();
+ });
+
+
+ MetricsLoggerWrapper.logPictureInPictureDismissByDrag(mContext,
+ PipUtils.getTopPipActivity(mContext, mActivityManager));
+ }
+ });
+
+ mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
}
public void setTouchGesture(PipTouchGesture gesture) {
@@ -231,7 +321,8 @@ public class PipTouchHandler {
}
public void onActivityPinned() {
- cleanUpDismissTarget();
+ createDismissTargetMaybe();
+
mShowPipMenuOnAnimationEnd = true;
mPipResizeGestureHandler.onActivityPinned();
mFloatingContentCoordinator.onContentAdded(mMotionHelper);
@@ -264,6 +355,10 @@ public class PipTouchHandler {
public void onConfigurationChanged() {
mMotionHelper.onConfigurationChanged();
mMotionHelper.synchronizePinnedStackBounds();
+
+ // Recreate the dismiss target for the new orientation.
+ cleanUpDismissTarget();
+ createDismissTargetMaybe();
}
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
@@ -351,6 +446,74 @@ public class PipTouchHandler {
}
}
+ /** Adds the magnetic target view to the WindowManager so it's ready to be animated in. */
+ private void createDismissTargetMaybe() {
+ if (!mTargetViewContainer.isAttachedToWindow()) {
+ mHandler.removeCallbacks(mShowTargetAction);
+ mMagneticTargetAnimator.cancel();
+
+ final Point windowSize = new Point();
+ mWindowManager.getDefaultDisplay().getRealSize(windowSize);
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ WindowManager.LayoutParams.MATCH_PARENT,
+ mDismissAreaHeight,
+ 0, windowSize.y - mDismissAreaHeight,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ PixelFormat.TRANSLUCENT);
+ lp.setTitle("pip-dismiss-overlay");
+ lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ lp.setFitInsetsTypes(0 /* types */);
+
+ mTargetViewContainer.setVisibility(View.INVISIBLE);
+ mWindowManager.addView(mTargetViewContainer, lp);
+ }
+ }
+
+ /** Makes the dismiss target visible and animates it in, if it isn't already visible. */
+ private void showDismissTargetMaybe() {
+ createDismissTargetMaybe();
+
+ if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
+
+ mTargetView.setTranslationY(mTargetViewContainer.getHeight());
+ mTargetViewContainer.setVisibility(View.VISIBLE);
+
+ // Set the magnetic field radius to half of PIP's width.
+ mMagneticTarget.setMagneticFieldRadiusPx(mMotionHelper.getBounds().width());
+
+ // Cancel in case we were in the middle of animating it out.
+ mMagneticTargetAnimator.cancel();
+ mMagneticTargetAnimator
+ .spring(DynamicAnimation.TRANSLATION_Y, 0f, mTargetSpringConfig)
+ .start();
+ }
+ }
+
+ /** Animates the magnetic dismiss target out and then sets it to GONE. */
+ private void hideDismissTarget() {
+ mHandler.removeCallbacks(mShowTargetAction);
+ mMagneticTargetAnimator
+ .spring(DynamicAnimation.TRANSLATION_Y,
+ mTargetViewContainer.getHeight(),
+ mTargetSpringConfig)
+ .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE))
+ .start();
+ }
+
+ /**
+ * Removes the dismiss target and cancels any pending callbacks to show it.
+ */
+ private void cleanUpDismissTarget() {
+ mHandler.removeCallbacks(mShowTargetAction);
+
+ if (mTargetViewContainer.isAttachedToWindow()) {
+ mWindowManager.removeView(mTargetViewContainer);
+ }
+ }
+
private void onRegistrationChanged(boolean isRegistered) {
mAccessibilityManager.setPictureInPictureActionReplacingConnection(isRegistered
? mConnection : null);
@@ -375,8 +538,24 @@ public class PipTouchHandler {
if (mPinnedStackController == null) {
return true;
}
+
MotionEvent ev = (MotionEvent) inputEvent;
+ if (mMagnetizedPip.maybeConsumeMotionEvent(ev)) {
+ // If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event
+ // to the touch state. Touch state needs a DOWN event in order to later process MOVE
+ // events it'll receive if the object is dragged out of the magnetic field.
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mTouchState.onTouchEvent(ev);
+ }
+
+ // Continue tracking velocity when the object is in the magnetic field, since we want to
+ // respect touch input velocity if the object is dragged out and then flung.
+ mTouchState.addMovementToVelocityTracker(ev);
+
+ return true;
+ }
+
// Update the touch state
mTouchState.onTouchEvent(ev);
@@ -600,17 +779,13 @@ public class PipTouchHandler {
mDelta.set(0f, 0f);
mStartPosition.set(bounds.left, bounds.top);
mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mMovementBounds.bottom;
+ mMotionHelper.setSpringingToTouch(false);
// If the menu is still visible then just poke the menu
// so that it will timeout after the user stops touching it
if (mMenuState != MENU_STATE_NONE) {
mMenuController.pokeMenu();
}
-
- if (mEnableDismissDragToEdge) {
- mDismissViewController.createDismissTarget();
- mHandler.postDelayed(mShowDismissAffordance, SHOW_DISMISS_AFFORDANCE_DELAY);
- }
}
@Override
@@ -623,8 +798,10 @@ public class PipTouchHandler {
mSavedSnapFraction = -1f;
if (mEnableDismissDragToEdge) {
- mHandler.removeCallbacks(mShowDismissAffordance);
- mDismissViewController.showDismissTarget();
+ if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
+ mHandler.removeCallbacks(mShowTargetAction);
+ showDismissTargetMaybe();
+ }
}
}
@@ -644,10 +821,6 @@ public class PipTouchHandler {
mTmpBounds.offsetTo((int) left, (int) top);
mMotionHelper.movePip(mTmpBounds, true /* isDragging */);
- if (mEnableDismissDragToEdge) {
- updateDismissFraction();
- }
-
final PointF curPos = touchState.getLastTouchPosition();
if (mMovementWithinDismiss) {
// Track if movement remains near the bottom edge to identify swipe to dismiss
@@ -661,9 +834,7 @@ public class PipTouchHandler {
@Override
public boolean onUp(PipTouchState touchState) {
if (mEnableDismissDragToEdge) {
- // Clean up the dismiss target regardless of the touch state in case the touch
- // enabled state changes while the user is interacting
- cleanUpDismissTarget();
+ hideDismissTarget();
}
if (!touchState.isUserInteracting()) {
@@ -671,26 +842,8 @@ public class PipTouchHandler {
}
final PointF vel = touchState.getVelocity();
- final boolean isHorizontal = Math.abs(vel.x) > Math.abs(vel.y);
final float velocity = PointF.length(vel.x, vel.y);
final boolean isFling = velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond();
- final boolean isUpWithinDimiss = ENABLE_FLING_DISMISS
- && touchState.getLastTouchPosition().y >= mMovementBounds.bottom
- && mMotionHelper.isGestureToDismissArea(mMotionHelper.getBounds(), vel.x,
- vel.y, isFling);
- final boolean isFlingToBot = isFling && vel.y > 0 && !isHorizontal
- && (mMovementWithinDismiss || isUpWithinDimiss);
- if (mEnableDismissDragToEdge) {
- // Check if the user dragged or flung the PiP offscreen to dismiss it
- if (mMotionHelper.shouldDismissPip() || isFlingToBot) {
- MetricsLoggerWrapper.logPictureInPictureDismissByDrag(mContext,
- PipUtils.getTopPipActivity(mContext, mActivityManager));
- mMotionHelper.animateDismiss(
- vel.x, vel.y,
- PipTouchHandler.this::updateDismissFraction /* updateAction */);
- return true;
- }
- }
if (touchState.isDragging()) {
Runnable endAction = null;
@@ -749,14 +902,6 @@ public class PipTouchHandler {
}
/**
- * Removes the dismiss target and cancels any pending callbacks to show it.
- */
- private void cleanUpDismissTarget() {
- mHandler.removeCallbacks(mShowDismissAffordance);
- mDismissViewController.destroyDismissTarget();
- }
-
- /**
* @return whether the menu will resize as a part of showing the full menu.
*/
private boolean willResizeMenu() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
index e3f65ef812fb..dc286c1c2de5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
@@ -92,7 +92,7 @@ public class PipTouchState {
// Initialize the velocity tracker
initOrResetVelocityTracker();
- addMovement(ev);
+ addMovementToVelocityTracker(ev);
mActivePointerId = ev.getPointerId(0);
if (DEBUG) {
@@ -120,7 +120,7 @@ public class PipTouchState {
}
// Update the velocity tracker
- addMovement(ev);
+ addMovementToVelocityTracker(ev);
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
Log.e(TAG, "Invalid active pointer id on MOVE: " + mActivePointerId);
@@ -151,7 +151,7 @@ public class PipTouchState {
}
// Update the velocity tracker
- addMovement(ev);
+ addMovementToVelocityTracker(ev);
int pointerIndex = ev.getActionIndex();
int pointerId = ev.getPointerId(pointerIndex);
@@ -174,7 +174,7 @@ public class PipTouchState {
}
// Update the velocity tracker
- addMovement(ev);
+ addMovementToVelocityTracker(ev);
mVelocityTracker.computeCurrentVelocity(1000,
mViewConfig.getScaledMaximumFlingVelocity());
mVelocity.set(mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
@@ -318,6 +318,20 @@ public class PipTouchState {
return -1;
}
+ void addMovementToVelocityTracker(MotionEvent event) {
+ if (mVelocityTracker == null) {
+ return;
+ }
+
+ // Add movement to velocity tracker using raw screen X and Y coordinates instead
+ // of window coordinates because the window frame may be moving at the same time.
+ float deltaX = event.getRawX() - event.getX();
+ float deltaY = event.getRawY() - event.getY();
+ event.offsetLocation(deltaX, deltaY);
+ mVelocityTracker.addMovement(event);
+ event.offsetLocation(-deltaX, -deltaY);
+ }
+
private void initOrResetVelocityTracker() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
@@ -333,16 +347,6 @@ public class PipTouchState {
}
}
- private void addMovement(MotionEvent event) {
- // Add movement to velocity tracker using raw screen X and Y coordinates instead
- // of window coordinates because the window frame may be moving at the same time.
- float deltaX = event.getRawX() - event.getX();
- float deltaY = event.getRawY() - event.getY();
- event.offsetLocation(deltaX, deltaY);
- mVelocityTracker.addMovement(event);
- event.offsetLocation(-deltaX, -deltaY);
- }
-
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 8fa64d3aaf0c..e6876bd98d21 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -66,7 +66,10 @@ public class QuickQSPanel extends QSPanel {
private int mMaxTiles;
protected QSPanel mFullPanel;
private QuickQSMediaPlayer mMediaPlayer;
+ /** Whether or not the QS media player feature is enabled. */
private boolean mUsingMediaPlayer;
+ /** Whether or not the QuickQSPanel currently contains a media player. */
+ private boolean mHasMediaPlayer;
private LinearLayout mHorizontalLinearLayout;
// Only used with media
@@ -185,8 +188,8 @@ public class QuickQSPanel extends QSPanel {
boolean switchTileLayout() {
if (!mUsingMediaPlayer) return false;
- if (mMediaPlayer.hasMediaSession()
- && mHorizontalLinearLayout.getVisibility() == View.GONE) {
+ mHasMediaPlayer = mMediaPlayer.hasMediaSession();
+ if (mHasMediaPlayer && mHorizontalLinearLayout.getVisibility() == View.GONE) {
mHorizontalLinearLayout.setVisibility(View.VISIBLE);
((View) mRegularTileLayout).setVisibility(View.GONE);
mTileLayout.setListening(false);
@@ -198,8 +201,7 @@ public class QuickQSPanel extends QSPanel {
if (mHost != null) setTiles(mHost.getTiles());
mTileLayout.setListening(mListening);
return true;
- } else if (!mMediaPlayer.hasMediaSession()
- && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) {
+ } else if (!mHasMediaPlayer && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) {
mHorizontalLinearLayout.setVisibility(View.GONE);
((View) mRegularTileLayout).setVisibility(View.VISIBLE);
mTileLayout.setListening(false);
@@ -215,8 +217,9 @@ public class QuickQSPanel extends QSPanel {
return false;
}
- public boolean hasMediaPlayerSession() {
- return mMediaPlayer.hasMediaSession();
+ /** Returns true if this panel currently contains a media player. */
+ public boolean hasMediaPlayer() {
+ return mHasMediaPlayer;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 11b625f41737..e1ffad4df2c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -344,7 +344,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
if (mQsDisabled) {
lp.height = resources.getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
- } else if (useQsMediaPlayer(mContext) && mHeaderQsPanel.hasMediaPlayerSession()) {
+ } else if (useQsMediaPlayer(mContext) && mHeaderQsPanel.hasMediaPlayer()) {
lp.height = Math.max(getMinimumHeight(),
resources.getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_total_height_with_media));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index fd44f04a0d80..d2da2628276a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -74,6 +74,7 @@ class NotificationShadeDepthController @Inject constructor(
var shadeSpring = DepthAnimation()
@VisibleForTesting
var globalActionsSpring = DepthAnimation()
+ var showingHomeControls: Boolean = false
@VisibleForTesting
var brightnessMirrorSpring = DepthAnimation()
@@ -133,7 +134,14 @@ class NotificationShadeDepthController @Inject constructor(
shadeRadius = 0f
}
}
- val blur = max(shadeRadius.toInt(), globalActionsSpring.radius)
+
+ // Home controls have black background, this means that we should not have blur when they
+ // are fully visible, otherwise we'll enter Client Composition unnecessarily.
+ var globalActionsRadius = globalActionsSpring.radius
+ if (showingHomeControls) {
+ globalActionsRadius = 0
+ }
+ val blur = max(shadeRadius.toInt(), globalActionsRadius)
blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur)
try {
wallpaperManager.setWallpaperZoomOut(root.windowToken,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index 1696f0715865..53ec57090321 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -103,12 +103,20 @@ class ConversationNotificationManager @Inject constructor(
override fun onEntryInflated(entry: NotificationEntry) {
if (!entry.ranking.isConversation) return
fun updateCount(isExpanded: Boolean) {
- if (isExpanded && !notifPanelCollapsed) {
+ if (isExpanded && (!notifPanelCollapsed || entry.isPinnedAndExpanded())) {
resetCount(entry.key)
entry.row?.let(::resetBadgeUi)
}
}
- entry.row?.setOnExpansionChangedListener(::updateCount)
+ entry.row?.setOnExpansionChangedListener { isExpanded ->
+ if (entry.row?.isShown == true && isExpanded) {
+ entry.row.performOnIntrinsicHeightReached {
+ updateCount(isExpanded)
+ }
+ } else {
+ updateCount(isExpanded)
+ }
+ }
updateCount(entry.row?.isExpanded == true)
}
@@ -169,7 +177,8 @@ class ConversationNotificationManager @Inject constructor(
private fun resetBadgeUi(row: ExpandableNotificationRow): Unit =
(row.layouts?.asSequence() ?: emptySequence())
- .mapNotNull { layout -> layout.contractedChild as? ConversationLayout }
+ .flatMap { layout -> layout.allViews.asSequence()}
+ .mapNotNull { view -> view as? ConversationLayout }
.forEach { convoLayout -> convoLayout.setUnreadCount(0) }
private data class ConversationState(val unreadCount: Int, val notification: Notification)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index dd7be2775209..c1ba26d034ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -601,6 +601,13 @@ public final class NotificationEntry extends ListEntry {
return row != null && row.isPinned();
}
+ /**
+ * Is this entry pinned and was expanded while doing so
+ */
+ public boolean isPinnedAndExpanded() {
+ return row != null && row.isPinnedAndExpanded();
+ }
+
public void setRowPinned(boolean pinned) {
if (row != null) row.setPinned(pinned);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 2917346153d2..5c578dfc5744 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -284,6 +284,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
if (isPinned()) {
nowExpanded = !mExpandedWhenPinned;
mExpandedWhenPinned = nowExpanded;
+ // Also notify any expansion changed listeners. This is necessary since the
+ // expansion doesn't actually change (it's already system expanded) but it
+ // changes visually
+ if (mExpansionChangedListener != null) {
+ mExpansionChangedListener.onExpansionChanged(nowExpanded);
+ }
} else {
nowExpanded = !isExpanded();
setUserExpanded(nowExpanded);
@@ -326,6 +332,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private NotificationInlineImageResolver mImageResolver;
private NotificationMediaManager mMediaManager;
@Nullable private OnExpansionChangedListener mExpansionChangedListener;
+ @Nullable private Runnable mOnIntrinsicHeightReachedRunnable;
private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
new SystemNotificationAsyncTask();
@@ -358,6 +365,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return Arrays.copyOf(mLayouts, mLayouts.length);
}
+ /**
+ * Is this entry pinned and was expanded while doing so
+ */
+ public boolean isPinnedAndExpanded() {
+ if (!isPinned()) {
+ return false;
+ }
+ return mExpandedWhenPinned;
+ }
+
@Override
public boolean isGroupExpansionChanging() {
if (isChildInGroup()) {
@@ -2690,6 +2707,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
if (mMenuRow != null && mMenuRow.getMenuView() != null) {
mMenuRow.onParentHeightUpdate();
}
+ handleIntrinsicHeightReached();
}
@Override
@@ -2907,6 +2925,24 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mExpansionChangedListener = listener;
}
+ /**
+ * Perform an action when the notification height has reached its intrinsic height.
+ *
+ * @param runnable the runnable to run
+ */
+ public void performOnIntrinsicHeightReached(@Nullable Runnable runnable) {
+ mOnIntrinsicHeightReachedRunnable = runnable;
+ handleIntrinsicHeightReached();
+ }
+
+ private void handleIntrinsicHeightReached() {
+ if (mOnIntrinsicHeightReachedRunnable != null
+ && getActualHeight() == getIntrinsicHeight()) {
+ mOnIntrinsicHeightReachedRunnable.run();
+ mOnIntrinsicHeightReachedRunnable = null;
+ }
+ }
+
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
index 893e8490eb90..e4e3ebcf7671 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java
@@ -151,9 +151,12 @@ public final class NotifBindPipeline {
* the real work once rather than repeatedly start and cancel it.
*/
private void requestPipelineRun(NotificationEntry entry) {
- mLogger.logRequestPipelineRun(entry.getKey());
-
final BindEntry bindEntry = getBindEntry(entry);
+ if (bindEntry.row == null) {
+ // Row is not managed yet but may be soon. Stop for now.
+ return;
+ }
+ mLogger.logRequestPipelineRun(entry.getKey());
// Abort any existing pipeline run
mStage.abortStage(entry, bindEntry.row);
@@ -177,10 +180,6 @@ public final class NotifBindPipeline {
final BindEntry bindEntry = mBindEntries.get(entry);
final ExpandableNotificationRow row = bindEntry.row;
- if (row == null) {
- // Row is not managed yet but may be soon. Stop for now.
- return;
- }
mStage.executeStage(entry, row, (en) -> onPipelineComplete(en));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index b18bf01ea91f..3c3f1b21fb3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
import android.app.PendingIntent;
@@ -988,6 +989,14 @@ public class NotificationContentView extends FrameLayout {
}
}
+ public @NonNull View[] getAllViews() {
+ return new View[] {
+ mContractedChild,
+ mHeadsUpChild,
+ mExpandedChild,
+ mSingleLineView };
+ }
+
public NotificationViewWrapper getVisibleWrapper(int visibleType) {
switch (visibleType) {
case VISIBLE_TYPE_EXPANDED:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index f06cfec9480a..82e02b47974c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -203,7 +203,9 @@ public class KeyguardBouncer {
Log.wtf(TAG, "onFullyShown when view was null");
} else {
mKeyguardView.onResume();
- mRoot.announceForAccessibility(mKeyguardView.getAccessibilityTitleForCurrentMode());
+ if (mRoot != null) {
+ mRoot.announceForAccessibility(mKeyguardView.getAccessibilityTitleForCurrentMode());
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index d70484e9cf41..a19d35ac4e81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -50,19 +50,22 @@ public class LockIcon extends KeyguardAffordanceView {
static final int STATE_BIOMETRICS_ERROR = 3;
private float mDozeAmount;
private int mIconColor;
- private StateProvider mStateProvider;
private int mOldState;
+ private int mState;
private boolean mPulsing;
private boolean mDozing;
private boolean mKeyguardJustShown;
+ private boolean mPredrawRegistered;
private final SparseArray<Drawable> mDrawableCache = new SparseArray<>();
private final OnPreDrawListener mOnPreDrawListener = new OnPreDrawListener() {
@Override
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);
+ mPredrawRegistered = false;
- int newState = mStateProvider.getState();
+ int newState = mState;
+ mOldState = mState;
Drawable icon = getIcon(newState);
setImageDrawable(icon, false);
@@ -80,7 +83,7 @@ public class LockIcon extends KeyguardAffordanceView {
@Override
public void onAnimationEnd(Drawable drawable) {
if (getDrawable() == animation
- && newState == mStateProvider.getState()
+ && newState == mState
&& newState == STATE_SCANNING_FACE) {
animation.start();
} else {
@@ -100,10 +103,6 @@ public class LockIcon extends KeyguardAffordanceView {
super(context, attrs);
}
- void setStateProvider(StateProvider stateProvider) {
- mStateProvider = stateProvider;
- }
-
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -135,13 +134,16 @@ public class LockIcon extends KeyguardAffordanceView {
return false;
}
- void update(int oldState, boolean pulsing, boolean dozing, boolean keyguardJustShown) {
- mOldState = oldState;
+ void update(int newState, boolean pulsing, boolean dozing, boolean keyguardJustShown) {
+ mState = newState;
mPulsing = pulsing;
mDozing = dozing;
mKeyguardJustShown = keyguardJustShown;
- getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener);
+ if (!mPredrawRegistered) {
+ mPredrawRegistered = true;
+ getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener);
+ }
}
void setDozeAmount(float dozeAmount) {
@@ -175,7 +177,7 @@ public class LockIcon extends KeyguardAffordanceView {
return mDrawableCache.get(iconRes);
}
- static int getIconForState(int state) {
+ private static int getIconForState(int state) {
int iconRes;
switch (state) {
case STATE_LOCKED:
@@ -196,7 +198,7 @@ public class LockIcon extends KeyguardAffordanceView {
return iconRes;
}
- static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
+ private static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
boolean dozing, boolean keyguardJustShown) {
// Never animate when screen is off
@@ -260,9 +262,4 @@ public class LockIcon extends KeyguardAffordanceView {
}
return LOCK_ANIM_RES_IDS[0][lockAnimIndex];
}
-
- interface StateProvider {
- int getState();
- }
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index f7c861b84a68..a633e1979bad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -352,7 +352,6 @@ public class LockscreenLockIconController {
mLockIcon.setOnClickListener(this::handleClick);
mLockIcon.setOnLongClickListener(this::handleLongClick);
mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate);
- mLockIcon.setStateProvider(this::getState);
if (mLockIcon.isAttachedToWindow()) {
mOnAttachStateChangeListener.onViewAttachedToWindow(mLockIcon);
@@ -462,7 +461,7 @@ public class LockscreenLockIconController {
shouldUpdate = false;
}
if (shouldUpdate && mLockIcon != null) {
- mLockIcon.update(mLastState, mPulsing, mDozing, mKeyguardJustShown);
+ mLockIcon.update(state, mPulsing, mDozing, mKeyguardJustShown);
}
mLastState = state;
mKeyguardJustShown = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index bf5900ff24bb..95b41a141244 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -71,7 +71,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
protected boolean mPluggedIn;
protected boolean mCharging;
private boolean mCharged;
- private boolean mPowerSave;
+ protected boolean mPowerSave;
private boolean mAodPowerSave;
private boolean mTestmode = false;
private boolean mHasReceivedBattery = false;
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
index 812a1e4bc121..f27bdbfbeda0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -160,6 +160,18 @@ abstract class MagnetizedObject<T : Any>(
lateinit var magnetListener: MagnetizedObject.MagnetListener
/**
+ * Optional update listener to provide to the PhysicsAnimator that is used to spring the object
+ * into the target.
+ */
+ var physicsAnimatorUpdateListener: PhysicsAnimator.UpdateListener<T>? = null
+
+ /**
+ * Optional end listener to provide to the PhysicsAnimator that is used to spring the object
+ * into the target.
+ */
+ var physicsAnimatorEndListener: PhysicsAnimator.EndListener<T>? = null
+
+ /**
* Sets whether forcefully flinging the object vertically towards a target causes it to be
* attracted to the target and then released immediately, despite never being dragged within the
* magnetic field.
@@ -479,6 +491,14 @@ abstract class MagnetizedObject<T : Any>(
.spring(yProperty, yProperty.getValue(underlyingObject) + yDiff, velY,
springConfig)
+ if (physicsAnimatorUpdateListener != null) {
+ animator.addUpdateListener(physicsAnimatorUpdateListener!!)
+ }
+
+ if (physicsAnimatorEndListener != null) {
+ animator.addEndListener(physicsAnimatorEndListener!!)
+ }
+
if (after != null) {
animator.withEndActions(after)
}
@@ -560,13 +580,15 @@ abstract class MagnetizedObject<T : Any>(
private val tempLoc = IntArray(2)
fun updateLocationOnScreen() {
- targetView.getLocationOnScreen(tempLoc)
-
- // Add half of the target size to get the center, and subtract translation since the
- // target could be animating in while we're doing this calculation.
- centerOnScreen.set(
- tempLoc[0] + targetView.width / 2f - targetView.translationX,
- tempLoc[1] + targetView.height / 2f - targetView.translationY)
+ targetView.post {
+ targetView.getLocationOnScreen(tempLoc)
+
+ // Add half of the target size to get the center, and subtract translation since the
+ // target could be animating in while we're doing this calculation.
+ centerOnScreen.set(
+ tempLoc[0] + targetView.width / 2f - targetView.translationX,
+ tempLoc[1] + targetView.height / 2f - targetView.translationY)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index bae5bb41aa5a..c22b718fa50f 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -272,13 +272,18 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
mAnimation.cancel();
}
- mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
final float defaultY = mImeSourceControl.getSurfacePosition().y;
final float x = mImeSourceControl.getSurfacePosition().x;
final float hiddenY = defaultY + imeSource.getFrame().height();
final float shownY = defaultY;
final float startY = show ? hiddenY : shownY;
final float endY = show ? shownY : hiddenY;
+ if (mAnimationDirection == DIRECTION_NONE && mImeShowing && show) {
+ // IME is already showing, so set seek to end
+ seekValue = shownY;
+ seek = true;
+ }
+ mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
mImeShowing = show;
mAnimation = ValueAnimator.ofFloat(startY, endY);
mAnimation.setDuration(
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
index 1140b9aa3abb..e5da603321cd 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -258,12 +258,13 @@ public class SystemWindows {
Rect outVisibleInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
+ SurfaceControl outBLASTSurfaceControl) {
int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight,
viewVisibility, flags, frameNumber, outFrame, outOverscanInsets,
outContentInsets, outVisibleInsets, outStableInsets,
cutout, mergedConfiguration, outSurfaceControl, outInsetsState,
- outSurfaceSize, outBLASTSurfaceControl);
+ outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
if (res != 0) {
return res;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 6b7a3bfce5ad..c874915e9124 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -117,12 +117,27 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
}
@Test
- fun updateGlobalDialogVisibility_appliesBlur() {
+ fun updateGlobalDialogVisibility_animatesBlur() {
notificationShadeDepthController.updateGlobalDialogVisibility(0.5f, root)
verify(globalActionsSpring).animateTo(eq(maxBlur / 2), safeEq(root))
}
@Test
+ fun updateGlobalDialogVisibility_appliesBlur_withoutHomeControls() {
+ `when`(globalActionsSpring.radius).thenReturn(maxBlur)
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(blurUtils).applyBlur(any(), eq(maxBlur))
+ }
+
+ @Test
+ fun updateGlobalDialogVisibility_appliesBlur_unlessHomeControls() {
+ notificationShadeDepthController.showingHomeControls = true
+ `when`(globalActionsSpring.radius).thenReturn(maxBlur)
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(blurUtils).applyBlur(any(), eq(0))
+ }
+
+ @Test
fun updateBlurCallback_setsBlurAndZoom() {
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperManager).setWallpaperZoomOut(any(), anyFloat())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
index f1672b1c644d..f6b7b74d4bfc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
@@ -106,6 +106,10 @@ class MagnetizedObjectTest : SysuiTestCase() {
location[1] = targetCenterY - targetSize / 2 // y = 800
}
}.`when`(targetView).getLocationOnScreen(ArgumentMatchers.any())
+ doAnswer { invocation ->
+ (invocation.arguments[0] as Runnable).run()
+ true
+ }.`when`(targetView).post(ArgumentMatchers.any())
`when`(targetView.context).thenReturn(context)
magneticTarget = MagnetizedObject.MagneticTarget(targetView, magneticFieldRadius)
@@ -408,6 +412,10 @@ class MagnetizedObjectTest : SysuiTestCase() {
`when`(secondTargetView.width).thenReturn(targetSize) // width = 200
`when`(secondTargetView.height).thenReturn(targetSize) // height = 200
doAnswer { invocation ->
+ (invocation.arguments[0] as Runnable).run()
+ true
+ }.`when`(secondTargetView).post(ArgumentMatchers.any())
+ doAnswer { invocation ->
(invocation.arguments[0] as IntArray).also { location ->
// Return the top left of the target.
location[0] = secondTargetCenterX - targetSize / 2 // x = 0
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 061ff42de60b..58972a5346c7 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -123,6 +123,8 @@ public class Watchdog extends Thread {
"android.hardware.neuralnetworks@1.0::IDevice",
"android.hardware.power.stats@1.0::IPowerStats",
"android.hardware.sensors@1.0::ISensors",
+ "android.hardware.sensors@2.0::ISensors",
+ "android.hardware.sensors@2.1::ISensors",
"android.hardware.vr@1.0::IVr",
"android.system.suspend@1.0::ISystemSuspend"
);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1248ec01e020..f07fa501d3a8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1830,7 +1830,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throws PackageManagerException {
final List<File> addedFiles = getAddedApksLocked();
if (addedFiles.isEmpty()) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ String.format("Session: %d. No packages staged in %s", sessionId,
+ stageDir.getAbsolutePath()));
}
if (ArrayUtils.size(addedFiles) > 1) {
@@ -1921,7 +1923,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final List<File> addedFiles = getAddedApksLocked();
if (addedFiles.isEmpty() && removeSplitList.size() == 0) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ String.format("Session: %d. No packages staged in %s", sessionId,
+ stageDir.getAbsolutePath()));
}
// Verify that all staged packages are internally consistent
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bc3a0352484b..f693555d9761 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9684,6 +9684,20 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
String loaderIsa) {
+ if (PLATFORM_PACKAGE_NAME.equals(loadingPackageName)
+ && Binder.getCallingUid() != Process.SYSTEM_UID) {
+ Slog.w(TAG, "Non System Server process reporting dex loads as system server. uid="
+ + Binder.getCallingUid());
+ // Do not record dex loads from processes pretending to be system server.
+ // Only the system server should be assigned the package "android", so reject calls
+ // that don't satisfy the constraint.
+ //
+ // notifyDexLoad is a PM API callable from the app process. So in theory, apps could
+ // craft calls to this API and pretend to be system server. Doing so poses no particular
+ // danger for dex load reporting or later dexopt, however it is a sensible check to do
+ // in order to verify the expectations.
+ return;
+ }
int userId = UserHandle.getCallingUserId();
ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
if (ai == null) {
@@ -11310,7 +11324,7 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
parsedPackage.getPackageName() + " " +
AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage)
- + ", "
+ + ", "
+ AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage));
}
}
@@ -17572,11 +17586,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (needToVerify) {
+ final boolean needsVerification = needsNetworkVerificationLPr(packageName);
final int verificationId = mIntentFilterVerificationToken++;
for (ParsedActivity a : activities) {
for (ParsedIntentInfo filter : a.getIntents()) {
- if (filter.handlesWebUris(true)
- && needsNetworkVerificationLPr(a.getPackageName())) {
+ // Run verification against hosts mentioned in any web-nav intent filter,
+ // even if the filter matches non-web schemes as well
+ if (needsVerification && filter.handlesWebUris(false)) {
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
"Verification needed for IntentFilter:" + filter.toString());
mIntentFilterVerifier.addOneIntentFilterVerification(
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index e8765ad973f3..ebdf85691e58 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -17,13 +17,17 @@
package com.android.server.pm.dex;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
+import static java.util.function.Function.identity;
+
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
+import android.content.pm.PackagePartitions;
import android.os.FileUtils;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -67,13 +71,12 @@ import java.util.zip.ZipEntry;
*/
public class DexManager {
private static final String TAG = "DexManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
"pm.dexopt.priv-apps-oob-list";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
private final Context mContext;
// Maps package name to code locations.
@@ -178,12 +181,14 @@ public class DexManager {
boolean primaryOrSplit = searchResult.mOutcome == DEX_SEARCH_FOUND_PRIMARY ||
searchResult.mOutcome == DEX_SEARCH_FOUND_SPLIT;
- if (primaryOrSplit && !isUsedByOtherApps) {
+ if (primaryOrSplit && !isUsedByOtherApps
+ && !PLATFORM_PACKAGE_NAME.equals(searchResult.mOwningPackageName)) {
// If the dex file is the primary apk (or a split) and not isUsedByOtherApps
// do not record it. This case does not bring any new usable information
// and can be safely skipped.
// Note this is just an optimization that makes things easier to read in the
// package-dex-use file since we don't need to pollute it with redundant info.
+ // However, we always record system server packages.
continue;
}
@@ -217,6 +222,23 @@ public class DexManager {
}
/**
+ * Check if the dexPath belongs to system server.
+ * System server can load code from different location, so we cast a wide-net here, and
+ * assume that if the paths is on any of the registered system partitions then it can be loaded
+ * by system server.
+ */
+ private boolean isSystemServerDexPathSupportedForOdex(String dexPath) {
+ ArrayList<PackagePartitions.SystemPartition> partitions =
+ PackagePartitions.getOrderedPartitions(identity());
+ for (int i = 0; i < partitions.size(); i++) {
+ if (partitions.get(i).containsPath(dexPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Read the dex usage from disk and populate the code cache locations.
* @param existingPackages a map containing information about what packages
* are available to what users. Only packages in this list will be
@@ -607,12 +629,6 @@ public class DexManager {
*/
private DexSearchResult getDexPackage(
ApplicationInfo loadingAppInfo, String dexPath, int userId) {
- // Ignore framework code.
- // TODO(calin): is there a better way to detect it?
- if (dexPath.startsWith("/system/framework/")) {
- return new DexSearchResult("framework", DEX_SEARCH_NOT_FOUND);
- }
-
// First, check if the package which loads the dex file actually owns it.
// Most of the time this will be true and we can return early.
PackageCodeLocations loadingPackageCodeLocations =
@@ -635,6 +651,28 @@ public class DexManager {
}
}
+ // We could not find the owning package amongst regular apps.
+ // If the loading package is system server, see if the dex file resides
+ // on any of the potentially system server owning location and if so,
+ // assuming system server ownership.
+ //
+ // Note: We don't have any way to detect which code paths are actually
+ // owned by system server. We can only assume that such paths are on
+ // system partitions.
+ if (PLATFORM_PACKAGE_NAME.equals(loadingAppInfo.packageName)) {
+ if (isSystemServerDexPathSupportedForOdex(dexPath)) {
+ // We record system server dex files as secondary dex files.
+ // The reason is that we only record the class loader context for secondary dex
+ // files and we expect that all primary apks are loaded with an empty class loader.
+ // System server dex files may be loaded in non-empty class loader so we need to
+ // keep track of their context.
+ return new DexSearchResult(PLATFORM_PACKAGE_NAME, DEX_SEARCH_FOUND_SECONDARY);
+ } else {
+ Slog.wtf(TAG, "System server loads dex files outside paths supported for odex: "
+ + dexPath);
+ }
+ }
+
if (DEBUG) {
// TODO(calin): Consider checking for /data/data symlink.
// /data/data/ symlinks /data/user/0/ and there's nothing stopping apps
diff --git a/services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java b/services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java
new file mode 100644
index 000000000000..807c82d887e3
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.dex;
+
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
+import android.content.pm.IPackageManager;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+import dalvik.system.BaseDexClassLoader;
+import dalvik.system.VMRuntime;
+
+import java.util.Map;
+
+/**
+ * Reports dex file use to the package manager on behalf of system server.
+ */
+public class SystemServerDexLoadReporter implements BaseDexClassLoader.Reporter {
+ private static final String TAG = "SystemServerDexLoadReporter";
+
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final IPackageManager mPackageManager;
+
+ private SystemServerDexLoadReporter(IPackageManager pm) {
+ mPackageManager = pm;
+ }
+
+ @Override
+ public void report(Map<String, String> classLoaderContextMap) {
+ if (DEBUG) {
+ Slog.i(TAG, "Reporting " + classLoaderContextMap);
+ }
+ if (classLoaderContextMap.isEmpty()) {
+ Slog.wtf(TAG, "Bad call to DexLoadReporter: empty classLoaderContextMap");
+ return;
+ }
+
+ try {
+ mPackageManager.notifyDexLoad(
+ PLATFORM_PACKAGE_NAME,
+ classLoaderContextMap,
+ VMRuntime.getRuntime().vmInstructionSet());
+ } catch (RemoteException ignored) {
+ // We're in system server, it can't happen.
+ }
+ }
+
+ /**
+ * Configures system server dex file reporting.
+ * <p>The method will install a reporter in the BaseDexClassLoader and also
+ * force the reporting of any dex files already loaded by the system server.
+ */
+ public static void configureSystemServerDexReporter(IPackageManager pm) {
+ Slog.i(TAG, "Configuring system server dex reporter");
+
+ SystemServerDexLoadReporter reporter = new SystemServerDexLoadReporter(pm);
+ BaseDexClassLoader.setReporter(reporter);
+ ClassLoader currrentClassLoader = reporter.getClass().getClassLoader();
+ if (currrentClassLoader instanceof BaseDexClassLoader) {
+ ((BaseDexClassLoader) currrentClassLoader).reportClassLoaderChain();
+ } else {
+ Slog.wtf(TAG, "System server class loader is not a BaseDexClassLoader. type="
+ + currrentClassLoader.getClass().getName());
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 161f30449a52..27288d852fb2 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -30,6 +30,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.AppOpsManagerInternal;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -47,6 +48,7 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.permission.PermissionControllerManager;
+import android.provider.Settings;
import android.provider.Telephony;
import android.telecom.TelecomManager;
import android.util.ArrayMap;
@@ -70,7 +72,9 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ExecutionException;
/**
@@ -180,8 +184,6 @@ public final class PermissionPolicyService extends SystemService {
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
intentFilter.addDataScheme("package");
-
- /* TODO ntmyren: enable receiver when test flakes are fixed
getContext().registerReceiverAsUser(new BroadcastReceiver() {
final List<Integer> mUserSetupUids = new ArrayList<>(200);
final Map<UserHandle, PermissionControllerManager> mPermControllerManagers =
@@ -232,7 +234,6 @@ public final class PermissionPolicyService extends SystemService {
manager.updateUserSensitiveForApp(uid);
}
}, UserHandle.ALL, intentFilter, null, null);
- */
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5ce63de87ee9..c47d2151a958 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -42,7 +42,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.activityTypeToString;
import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_HOME;
@@ -109,7 +108,6 @@ import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_UNSET;
-import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -5812,18 +5810,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
@VisibleForTesting
- boolean shouldAnimate(int transit) {
- if (task != null && !task.shouldAnimate()) {
- return false;
- }
- final boolean isSplitScreenPrimary =
- getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
- final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
-
- // We animate always if it's not split screen primary, and only some special cases in split
- // screen primary because it causes issues with stack clipping when we run an un-minimize
- // animation at the same time.
- return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
+ boolean shouldAnimate() {
+ return task == null || task.shouldAnimate();
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index f5eba96a96d1..78d2afc64f96 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -20,7 +20,6 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
@@ -685,9 +684,7 @@ class ActivityStack extends Task {
return;
}
- setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
- false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
- false /* creating */);
+ setWindowingMode(windowingMode, false /* creating */);
}
/**
@@ -709,27 +706,22 @@ class ActivityStack extends Task {
* @param preferredWindowingMode the preferred windowing mode. This may not be honored depending
* on the state of things. For example, WINDOWING_MODE_UNDEFINED will resolve to the
* previous non-transient mode if this stack is currently in a transient mode.
- * @param animate Can be used to prevent animation.
- * @param showRecents Controls whether recents is shown on the other side of a split while
- * entering split mode.
- * @param enteringSplitScreenMode {@code true} if entering split mode.
- * @param deferEnsuringVisibility Whether visibility updates are deferred. This is set when
- * many operations (which can effect visibility) are being performed in bulk.
* @param creating {@code true} if this is being run during ActivityStack construction.
*/
- void setWindowingMode(int preferredWindowingMode, boolean animate, boolean showRecents,
- boolean enteringSplitScreenMode, boolean deferEnsuringVisibility, boolean creating) {
+ void setWindowingMode(int preferredWindowingMode, boolean creating) {
mWmService.inSurfaceTransaction(() -> setWindowingModeInSurfaceTransaction(
- preferredWindowingMode, animate, showRecents, enteringSplitScreenMode,
- deferEnsuringVisibility, creating));
+ preferredWindowingMode, creating));
}
- private void setWindowingModeInSurfaceTransaction(int preferredWindowingMode, boolean animate,
- boolean showRecents, boolean enteringSplitScreenMode, boolean deferEnsuringVisibility,
+ private void setWindowingModeInSurfaceTransaction(int preferredWindowingMode,
boolean creating) {
+ final TaskDisplayArea taskDisplayArea = getDisplayArea();
+ if (taskDisplayArea == null) {
+ Slog.d(TAG, "taskDisplayArea is null, bail early");
+ return;
+ }
final int currentMode = getWindowingMode();
final int currentOverrideMode = getRequestedOverrideWindowingMode();
- final TaskDisplayArea taskDisplayArea = getDisplayArea();
final Task topTask = getTopMostTask();
int windowingMode = preferredWindowingMode;
if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED
@@ -753,12 +745,9 @@ class ActivityStack extends Task {
final boolean alreadyInSplitScreenMode = taskDisplayArea.isSplitScreenModeActivated();
- // Don't send non-resizeable notifications if the windowing mode changed was a side effect
- // of us entering split-screen mode.
- final boolean sendNonResizeableNotification = !enteringSplitScreenMode;
// Take any required action due to us not supporting the preferred windowing mode.
if (alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
- && sendNonResizeableNotification && isActivityTypeStandardOrUndefined()) {
+ && isActivityTypeStandardOrUndefined()) {
final boolean preferredSplitScreen =
preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -794,7 +783,7 @@ class ActivityStack extends Task {
if (currentMode == WINDOWING_MODE_PINNED) {
mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
}
- if (sendNonResizeableNotification && likelyResolvedMode != WINDOWING_MODE_FULLSCREEN
+ if (likelyResolvedMode != WINDOWING_MODE_FULLSCREEN
&& topActivity != null && !topActivity.noDisplay
&& topActivity.isNonResizableOrForcedResizable(likelyResolvedMode)) {
// Inform the user that they are starting an app that may not work correctly in
@@ -806,7 +795,7 @@ class ActivityStack extends Task {
mAtmService.deferWindowLayout();
try {
- if (!animate && topActivity != null) {
+ if (topActivity != null) {
mStackSupervisor.mNoAnimActivities.add(topActivity);
}
super.setWindowingMode(windowingMode);
@@ -845,36 +834,11 @@ class ActivityStack extends Task {
false /*preserveWindows*/, true /*deferResume*/);
}
} finally {
- if (showRecents && !alreadyInSplitScreenMode && isOnHomeDisplay()
- && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- // Make sure recents stack exist when creating a dock stack as it normally needs to
- // be on the other side of the docked stack and we make visibility decisions based
- // on that.
- // TODO: This is only here to help out with the case where recents stack doesn't
- // exist yet. For that case the initial size of the split-screen stack will be the
- // the one where the home stack is visible since recents isn't visible yet, but the
- // divider will be off. I think we should just make the initial bounds that of home
- // so that the divider matches and remove this logic.
- // TODO: This is currently only called when entering split-screen while in another
- // task, and from the tests
- // TODO (b/78247419): Fix the rotation animation from fullscreen to minimized mode
- final boolean isRecentsComponentHome =
- mAtmService.getRecentTasks().isRecentsComponentHomeActivity(mCurrentUser);
- final ActivityStack recentStack = taskDisplayArea.getOrCreateStack(
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
- isRecentsComponentHome ? ACTIVITY_TYPE_HOME : ACTIVITY_TYPE_RECENTS,
- true /* onTop */);
- recentStack.moveToFront("setWindowingMode");
- // If task moved to docked stack - show recents if needed.
- mWmService.showRecentApps();
- }
mAtmService.continueWindowLayout();
}
- if (!deferEnsuringVisibility) {
- mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- mRootWindowContainer.resumeFocusedStacksTopActivities();
- }
+ mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ mRootWindowContainer.resumeFocusedStacksTopActivities();
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 02601ff4b6e3..1e5a924e1d4d 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -80,8 +80,6 @@ import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
-import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
-import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -140,7 +138,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.TransferPipe;
-import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -382,71 +379,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
private boolean mInitialized;
- private final MoveTaskToFullscreenHelper mMoveTaskToFullscreenHelper =
- new MoveTaskToFullscreenHelper();
- private class MoveTaskToFullscreenHelper {
- private TaskDisplayArea mToDisplayArea;
- private boolean mOnTop;
- private Task mTopTask;
- private boolean mSchedulePictureInPictureModeChange;
-
- void process(ActivityStack fromStack, TaskDisplayArea toDisplayArea, boolean onTop,
- boolean schedulePictureInPictureModeChange) {
- mSchedulePictureInPictureModeChange = schedulePictureInPictureModeChange;
- mToDisplayArea = toDisplayArea;
- mOnTop = onTop;
- mTopTask = fromStack.getTopMostTask();
-
- final PooledConsumer c = PooledLambda.obtainConsumer(
- MoveTaskToFullscreenHelper::processLeafTask, this, PooledLambda.__(Task.class));
- fromStack.forAllLeafTasks(c, false /* traverseTopToBottom */);
- c.recycle();
- mToDisplayArea = null;
- mTopTask = null;
- }
-
- private void processLeafTask(Task task) {
- // This is a one level task that we don't need to create stack for reparenting to.
- if (task.isRootTask() && DisplayContent.alwaysCreateStack(WINDOWING_MODE_FULLSCREEN,
- task.getActivityType())) {
- final ActivityStack stack = (ActivityStack) task;
- stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- if (mToDisplayArea.getDisplayId() != stack.getDisplayId()) {
- stack.reparent(mToDisplayArea, mOnTop);
- } else if (mOnTop) {
- mToDisplayArea.positionStackAtTop(stack, false /* includingParents */);
- } else {
- mToDisplayArea.positionStackAtBottom(stack);
- }
- return;
- }
-
- final ActivityStack toStack = mToDisplayArea.getOrCreateStack(null, mTmpOptions, task,
- task.getActivityType(), mOnTop);
- if (task == toStack) {
- // The task was reused as the root task.
- return;
- }
-
- if (mOnTop) {
- final boolean isTopTask = task == mTopTask;
- // Defer resume until all the tasks have been moved to the fullscreen stack
- task.reparent(toStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, isTopTask /*animate*/,
- DEFER_RESUME, mSchedulePictureInPictureModeChange,
- "moveTasksToFullscreenStack - onTop");
- MetricsLoggerWrapper.logPictureInPictureFullScreen(mService.mContext,
- task.effectiveUid, task.realActivity.flattenToString());
- } else {
- // Position the tasks in the fullscreen stack in order at the bottom of the
- // stack. Also defer resume until all the tasks have been moved to the
- // fullscreen stack.
- task.reparent(toStack, ON_TOP, REPARENT_LEAVE_STACK_IN_PLACE,
- !ANIMATE, DEFER_RESUME, mSchedulePictureInPictureModeChange,
- "moveTasksToFullscreenStack - NOT_onTop");
- }
- }
- }
-
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -1501,41 +1433,43 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
mResizingTasksDuringAnimation.clear();
}
- /**
- * TODO: This should just change the windowing mode and resize vs. actually moving task around.
- * Can do that once we are no longer using static stack ids.
- */
- private void moveTasksToFullscreenStackInSurfaceTransaction(ActivityStack fromStack,
- int toDisplayId, boolean onTop) {
+ void setSplitScreenResizing(boolean resizing) {
+ if (resizing == mDockedStackResizing) {
+ return;
+ }
- mService.deferWindowLayout();
- try {
- final int windowingMode = fromStack.getWindowingMode();
- final TaskDisplayArea toDisplayArea = mRootWindowContainer
- .getDisplayContent(toDisplayId).getDefaultTaskDisplayArea();
+ mDockedStackResizing = resizing;
+ mWindowManager.setDockedStackResizing(resizing);
+ }
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- // We are moving all tasks from the docked stack to the fullscreen stack,
- // which is dismissing the docked stack, so resize all other stacks to
- // fullscreen here already so we don't end up with resize trashing.
- for (int i = toDisplayArea.getStackCount() - 1; i >= 0; --i) {
- final ActivityStack otherStack = toDisplayArea.getStackAt(i);
- if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
- continue;
- }
- otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
- }
- }
+ private void removePinnedStackInSurfaceTransaction(ActivityStack stack) {
+ /**
+ * Workaround: Force-stop all the activities in the pinned stack before we reparent them
+ * to the fullscreen stack. This is to guarantee that when we are removing a stack,
+ * that the client receives onStop() before it is reparented. We do this by detaching
+ * the stack from the display so that it will be considered invisible when
+ * ensureActivitiesVisible() is called, and all of its activities will be marked
+ * invisible as well and added to the stopping list. After which we process the
+ * stopping list by handling the idle.
+ */
+ stack.cancelAnimation();
+ stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
+ stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */);
+ activityIdleInternal(null /* idleActivity */, false /* fromTimeout */,
+ true /* processPausingActivities */, null /* configuration */);
- // If we are moving from the pinned stack, then the animation takes care of updating
- // the picture-in-picture mode.
- final boolean schedulePictureInPictureModeChange =
- windowingMode == WINDOWING_MODE_PINNED;
+ // Reparent all the tasks to the bottom of the display
+ final DisplayContent toDisplay =
+ mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY);
- if (fromStack.hasChild()) {
- mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
- mMoveTaskToFullscreenHelper.process(
- fromStack, toDisplayArea, onTop, schedulePictureInPictureModeChange);
+ mService.deferWindowLayout();
+ try {
+ stack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ if (toDisplay.getDisplayId() != stack.getDisplayId()) {
+ stack.reparent(toDisplay.getDefaultTaskDisplayArea(), false /* onTop */);
+ } else {
+ toDisplay.mTaskContainers.positionStackAtBottom(stack);
}
mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
@@ -1545,41 +1479,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
}
- void moveTasksToFullscreenStackLocked(ActivityStack fromStack, boolean onTop) {
- // TODO(b/153089193): Support moving within the same task display area
- mWindowManager.inSurfaceTransaction(() ->
- moveTasksToFullscreenStackInSurfaceTransaction(fromStack, DEFAULT_DISPLAY, onTop));
- }
-
- void setSplitScreenResizing(boolean resizing) {
- if (resizing == mDockedStackResizing) {
- return;
- }
-
- mDockedStackResizing = resizing;
- mWindowManager.setDockedStackResizing(resizing);
- }
-
private void removeStackInSurfaceTransaction(ActivityStack stack) {
if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) {
- /**
- * Workaround: Force-stop all the activities in the pinned stack before we reparent them
- * to the fullscreen stack. This is to guarantee that when we are removing a stack,
- * that the client receives onStop() before it is reparented. We do this by detaching
- * the stack from the display so that it will be considered invisible when
- * ensureActivitiesVisible() is called, and all of its activities will be marked
- * invisible as well and added to the stopping list. After which we process the
- * stopping list by handling the idle.
- */
- stack.cancelAnimation();
- stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
- stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */);
- activityIdleInternal(null /* idleActivity */, false /* fromTimeout */,
- true /* processPausingActivities */, null /* configuration */);
-
- // Move all the tasks to the bottom of the fullscreen stack
- moveTasksToFullscreenStackLocked(stack, !ON_TOP);
+ removePinnedStackInSurfaceTransaction(stack);
} else {
final PooledConsumer c = PooledLambda.obtainConsumer(
ActivityStackSupervisor::processRemoveTask, this, PooledLambda.__(Task.class));
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0b1968765300..c253cd2c3297 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3324,33 +3324,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
return;
}
- // Place the task in the right stack if it isn't there already based on
- // the requested bounds.
- // The stack transition logic is:
- // - a null bounds on a freeform task moves that task to fullscreen
- // - a non-null bounds on a non-freeform (fullscreen OR docked) task moves
- // that task to freeform
- // - otherwise the task is not moved
- ActivityStack stack = task.getStack();
if (!task.getWindowConfiguration().canResizeTask()) {
throw new IllegalArgumentException("resizeTask not allowed on task=" + task);
}
- if (bounds == null && stack.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
- stack = stack.getDisplayArea().getOrCreateStack(
- WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP);
- } else if (bounds != null && stack.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
- stack = stack.getDisplayArea().getOrCreateStack(
- WINDOWING_MODE_FREEFORM, stack.getActivityType(), ON_TOP);
- }
// Reparent the task to the right stack if necessary
boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0;
- if (stack != task.getStack()) {
- // Defer resume until the task is resized below
- task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE,
- DEFER_RESUME, "resizeTask");
- preserveWindow = false;
- }
// After reparenting (which only resizes the task to the stack bounds), resize the
// task to the actual bounds provided
@@ -4022,28 +4001,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
- @Override
- // TODO: API should just be about changing windowing modes...
- public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
- "moveTasksToFullscreenStack()");
- synchronized (mGlobalLock) {
- final long origId = Binder.clearCallingIdentity();
- try {
- final ActivityStack stack = mRootWindowContainer.getStack(fromStackId);
- if (stack != null){
- if (!stack.isActivityTypeStandardOrUndefined()) {
- throw new IllegalArgumentException(
- "You can't move tasks from non-standard stacks.");
- }
- mStackSupervisor.moveTasksToFullscreenStackLocked(stack, onTop);
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
- }
-
/**
* Moves the top activity in the input stackId to the pinned stack.
*
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index f86aeb2244dc..78ee1de78079 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -76,7 +76,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
-import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
import android.annotation.DrawableRes;
@@ -1807,15 +1806,11 @@ public class AppTransition implements Dump {
}
int getAppStackClipMode() {
- // When dismiss keyguard animation occurs, clip before the animation to prevent docked
- // app from showing beyond the divider
- if (mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY
- || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
- return STACK_CLIP_BEFORE_ANIM;
- }
return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
|| mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
|| mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
+ || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY
+ || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER
? STACK_CLIP_NONE
: STACK_CLIP_AFTER_ANIM;
}
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 90fdf19d9781..edd14b7bebf3 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -253,6 +253,12 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
super.prepareSurfaces();
getBounds(mTmpDimBoundsRect);
+ // If SystemUI is dragging for recents, we want to reset the dim state so any dim layer
+ // on the display level fades out.
+ if (forAllTasks(task -> !task.canAffectSystemUiFlags())) {
+ mDimmer.resetDimStates();
+ }
+
if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
scheduleAnimation();
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a93b962c33b4..8111c0ef28c2 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -197,7 +197,6 @@ import android.view.ViewRootImpl;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
-import android.window.ITaskOrganizer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -3554,6 +3553,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
onWallpaper, goingToShade, subtle));
}
}, true /* traverseTopToBottom */);
+ for (int i = mShellRoots.size() - 1; i >= 0; --i) {
+ mShellRoots.valueAt(i).startAnimation(policy.createHiddenByKeyguardExit(
+ onWallpaper, goingToShade, subtle));
+ }
}
/** @return {@code true} if there is window to wait before enabling the screen. */
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index f088dbcb0174..e9d3d56ee283 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -696,6 +696,10 @@ public class DisplayPolicy {
mForceShowSystemBarsFromExternal = forceShowSystemBars;
}
+ boolean getForceShowSystemBars() {
+ return mForceShowSystemBarsFromExternal;
+ }
+
public boolean hasNavigationBar() {
return mHasNavigationBar;
}
@@ -1494,9 +1498,7 @@ public class DisplayPolicy {
final int behavior = mLastBehavior;
boolean navVisible = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
? (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- : mNavigationBar != null && mNavigationBar.getControllableInsetProvider() != null
- && mNavigationBar.getControllableInsetProvider().isClientVisible()
- && !mDisplayContent.getInsetsPolicy().isTransient(ITYPE_NAVIGATION_BAR);
+ : isNavigationBarRequestedVisible();
boolean navTranslucent = (sysui
& (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0
@@ -1533,6 +1535,14 @@ public class DisplayPolicy {
mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation;
}
+ boolean isNavigationBarRequestedVisible() {
+ final InsetsSourceProvider provider =
+ mDisplayContent.getInsetsStateController().peekSourceProvider(ITYPE_NAVIGATION_BAR);
+ return provider == null
+ ? InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR)
+ : provider.isClientVisible();
+ }
+
void updateHideNavInputEventReceiver(boolean navVisible, boolean navAllowedHidden) {
// When the navigation bar isn't visible, we put up a fake input window to catch all
// touch events. This way we can detect when the user presses anywhere to bring back the
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index e4e57168efe7..61a199a816df 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -99,7 +99,7 @@ class InsetsPolicy {
}
private void updateHideNavInputEventReceiver() {
- mPolicy.updateHideNavInputEventReceiver(!isHidden(ITYPE_NAVIGATION_BAR),
+ mPolicy.updateHideNavInputEventReceiver(mPolicy.isNavigationBarRequestedVisible(),
mFocusedWin != null
&& mFocusedWin.mAttrs.insetsFlags.behavior != BEHAVIOR_SHOW_BARS_BY_TOUCH);
}
@@ -304,7 +304,10 @@ class InsetsPolicy {
// We need to force system bars when the docked stack is visible, when the freeform stack
// is visible but also when we are resizing for the transitions when docked stack
// visibility changes.
- return isDockedStackVisible || isFreeformStackVisible || isResizing;
+ return isDockedStackVisible
+ || isFreeformStackVisible
+ || isResizing
+ || mPolicy.getForceShowSystemBars();
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 5f3732a58824..7d8a56e6c468 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -51,6 +51,7 @@ import android.view.IWindowId;
import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.InputChannel;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -158,10 +159,10 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
- InsetsState outInsetsState) {
+ InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
- outInsetsState);
+ outInsetsState, outActiveControls);
}
@Override
@@ -171,7 +172,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
new Rect() /* outFrame */, outContentInsets, outStableInsets,
new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */,
- outInsetsState);
+ outInsetsState, null);
}
@Override
@@ -191,7 +192,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
Rect outStableInsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
+ SurfaceControl outBLASTSurfaceControl) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
@@ -199,8 +201,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
outFrame, outContentInsets, outVisibleInsets,
outStableInsets, outBackdropFrame, cutout,
- mergedConfiguration, outSurfaceControl, outInsetsState, outSurfaceSize,
- outBLASTSurfaceControl);
+ mergedConfiguration, outSurfaceControl, outInsetsState, outActiveControls,
+ outSurfaceSize, outBLASTSurfaceControl);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java
index 9732637fdd4d..701feff8c6be 100644
--- a/services/core/java/com/android/server/wm/ShellRoot.java
+++ b/services/core/java/com/android/server/wm/ShellRoot.java
@@ -16,12 +16,20 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
+import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
+
import android.annotation.NonNull;
+import android.graphics.Point;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import android.view.DisplayInfo;
import android.view.IWindow;
import android.view.SurfaceControl;
+import android.view.animation.Animation;
/**
* Represents a piece of the hierarchy under which a client Shell can manage sub-windows.
@@ -70,5 +78,29 @@ public class ShellRoot {
IWindow getClient() {
return mClient;
}
+
+ void startAnimation(Animation anim) {
+ // Only do this for the divider
+ if (mToken.windowType != TYPE_DOCK_DIVIDER) {
+ return;
+ }
+
+ DisplayInfo displayInfo = mToken.getFixedRotationTransformDisplayInfo();
+ if (displayInfo == null) {
+ displayInfo = mDisplayContent.getDisplayInfo();
+ }
+
+ // Mostly copied from WindowState to enable keyguard transition animation
+ anim.initialize(displayInfo.logicalWidth, displayInfo.logicalHeight,
+ displayInfo.appWidth, displayInfo.appHeight);
+ anim.restrictDuration(MAX_ANIMATION_DURATION);
+ anim.scaleCurrentDuration(mDisplayContent.mWmService.getWindowAnimationScaleLocked());
+ final AnimationAdapter adapter = new LocalAnimationAdapter(
+ new WindowAnimationSpec(anim, new Point(0, 0), false /* canSkipFirstFrame */,
+ 0 /* windowCornerRadius */),
+ mDisplayContent.mWmService.mSurfaceAnimationRunner);
+ mToken.startAnimation(mToken.getPendingTransaction(), adapter, false /* hidden */,
+ ANIMATION_TYPE_WINDOW_ANIMATION, null /* animationFinishedCallback */);
+ }
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index cb897db9a2d0..9adacb8c578d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3348,6 +3348,21 @@ class Task extends WindowContainer<WindowContainer> {
@Override
Dimmer getDimmer() {
+ // If the window is in multi-window mode, we want to dim at the Task level to ensure the dim
+ // bounds match the area the app lives in
+ if (inMultiWindowMode()) {
+ return mDimmer;
+ }
+
+ // If we're not at the root task level, we want to keep traversing through the parents to
+ // find the root.
+ // Once at the root task level, we want to check {@link #isTranslucent(ActivityRecord)}.
+ // If true, we want to get the Dimmer from the level above since we don't want to animate
+ // the dim with the Task.
+ if (!isRootTask() || isTranslucent(null)) {
+ return super.getDimmer();
+ }
+
return mDimmer;
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 1bc7244996ab..ec3c99bf0808 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -936,9 +936,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
}
} else {
addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
- stack.setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
- false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
- true /* creating */);
+ stack.setWindowingMode(windowingMode, true /* creating */);
}
return stack;
}
@@ -1148,7 +1146,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
for (int i = getStackCount() - 1; i >= 0; --i) {
final ActivityStack stack = getStackAt(i);
// Collect the root tasks that are currently being organized.
- if (stack.isOrganized()) {
+ if (stack.mCreatedByOrganizer) {
for (int k = stack.getChildCount() - 1; k >= 0; --k) {
final ActivityStack childStack = (ActivityStack) stack.getChildAt(k);
if (childStack.getActivityType() == activityType) {
@@ -1614,6 +1612,11 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
}
}
+ @Override
+ boolean canCreateRemoteAnimationTarget() {
+ return true;
+ }
+
/**
* Callback for when the order of the stacks in the display changes.
*/
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index eb005e0f7eda..14e5c6cbf28d 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -68,6 +68,7 @@ import android.util.MergedConfiguration;
import android.util.Slog;
import android.view.DisplayCutout;
import android.view.IWindowSession;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -164,6 +165,7 @@ class TaskSnapshotSurface implements StartingSurface {
final Rect tmpContentInsets = new Rect();
final Rect tmpStableInsets = new Rect();
final InsetsState mTmpInsetsState = new InsetsState();
+ final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
final TaskDescription taskDescription = new TaskDescription();
taskDescription.setBackgroundColor(WHITE);
@@ -231,8 +233,8 @@ class TaskSnapshotSurface implements StartingSurface {
}
try {
final int res = session.addToDisplay(window, window.mSeq, layoutParams,
- View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect, tmpRect,
- tmpCutout, null, mTmpInsetsState);
+ View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect,
+ tmpRect, tmpCutout, null, mTmpInsetsState, mTempControls);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
return null;
@@ -249,7 +251,7 @@ class TaskSnapshotSurface implements StartingSurface {
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
tmpFrame, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect,
tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
- sTmpSurfaceSize, sTmpSurfaceControl);
+ mTempControls, sTmpSurfaceSize, sTmpSurfaceControl);
} catch (RemoteException e) {
// Local call.
}
@@ -377,6 +379,7 @@ class TaskSnapshotSurface implements StartingSurface {
frame = null;
mTmpDstFrame.set(mFrame);
}
+ mTmpDstFrame.offsetTo(0, 0);
// Scale the mismatch dimensions to fill the task bounds
mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 569b8f61c4f4..f9955fa89bff 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2295,6 +2295,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
mLastLayer = -1;
reassignLayer(t);
+
+ // Leash is now responsible for position, so set our position to 0.
+ t.setPosition(mSurfaceControl, 0, 0);
+ mLastSurfacePosition.set(0, 0);
}
@Override
@@ -2302,6 +2306,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
mLastLayer = -1;
mSurfaceFreezer.unfreeze(t);
reassignLayer(t);
+ updateSurfacePosition(t);
}
/**
@@ -2365,11 +2370,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
}
- void updateSurfacePosition() {
+ final void updateSurfacePosition() {
+ updateSurfacePosition(getPendingTransaction());
+ }
+
+ void updateSurfacePosition(Transaction t) {
// Avoid fighting with the organizer over Surface position.
if (isOrganized()) return;
- if (mSurfaceControl == null) {
+ if (mSurfaceControl == null || mSurfaceAnimator.hasLeash()) {
return;
}
@@ -2378,7 +2387,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return;
}
- getPendingTransaction().setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y);
+ t.setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y);
mLastSurfacePosition.set(mTmpPos.x, mTmpPos.y);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a1e0eb730ff7..8d3a4f27a257 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -227,6 +227,7 @@ import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.InputWindowHandle;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.KeyEvent;
import android.view.MagnificationSpec;
@@ -1356,7 +1357,7 @@ public class WindowManagerService extends IWindowManager.Stub
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
- InsetsState outInsetsState) {
+ InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
int[] appOp = new int[1];
final boolean isRoundedCornerOverlay = (attrs.privateFlags
& PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
@@ -1643,8 +1644,7 @@ public class WindowManagerService extends IWindowManager.Stub
outStableInsets, outDisplayCutout)) {
res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
}
- outInsetsState.set(win.getInsetsState(),
- win.mClient instanceof IWindow.Stub /* copySource */);
+ outInsetsState.set(win.getInsetsState(), win.isClientLocal());
if (mInTouchMode) {
res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
@@ -1678,6 +1678,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
+ getInsetsSourceControls(win, outActiveControls);
+
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
+ ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
@@ -2080,7 +2082,8 @@ public class WindowManagerService extends IWindowManager.Stub
Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
+ SurfaceControl outBLASTSurfaceControl) {
int result = 0;
boolean configChanged;
final int pid = Binder.getCallingPid();
@@ -2375,8 +2378,8 @@ public class WindowManagerService extends IWindowManager.Stub
outStableInsets);
outCutout.set(win.getWmDisplayCutout().getDisplayCutout());
outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw()));
- outInsetsState.set(win.getInsetsState(),
- win.mClient instanceof IWindow.Stub /* copySource */);
+ outInsetsState.set(win.getInsetsState(), win.isClientLocal());
+ getInsetsSourceControls(win, outActiveControls);
if (DEBUG) {
Slog.v(TAG_WM, "Relayout given client " + client.asBinder()
+ ", requestedWidth=" + requestedWidth
@@ -2413,6 +2416,21 @@ public class WindowManagerService extends IWindowManager.Stub
return result;
}
+ private void getInsetsSourceControls(WindowState win, InsetsSourceControl[] outControls) {
+ if (outControls != null) {
+ final InsetsSourceControl[] controls =
+ win.getDisplayContent().getInsetsStateController().getControlsForDispatch(win);
+ Arrays.fill(outControls, null);
+ if (controls != null) {
+ final int length = Math.min(controls.length, outControls.length);
+ for (int i = 0; i < length; i++) {
+ outControls[i] = win.isClientLocal()
+ ? new InsetsSourceControl(controls[i]) : controls[i];
+ }
+ }
+ }
+ }
+
private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator,
boolean focusMayChange) {
// Try starting an animation; if there isn't one, we
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3ebc0f410fd7..5a76bac67d64 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3479,6 +3479,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
+ boolean isClientLocal() {
+ return mClient instanceof IWindow.Stub;
+ }
+
void updateLocationInParentDisplayIfNeeded() {
final int embeddedDisplayContentsSize = mEmbeddedDisplayContents.size();
// If there is any embedded display which is re-parented to this window, we need to
@@ -5233,23 +5237,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
super.onAnimationLeashCreated(t, leash);
-
- // Leash is now responsible for position, so set our position to 0.
- t.setPosition(mSurfaceControl, 0, 0);
- mLastSurfacePosition.set(0, 0);
}
@Override
public void onAnimationLeashLost(Transaction t) {
super.onAnimationLeashLost(t);
- updateSurfacePosition(t);
}
@Override
- void updateSurfacePosition() {
- updateSurfacePosition(getPendingTransaction());
- }
-
@VisibleForTesting
void updateSurfacePosition(Transaction t) {
if (mSurfaceControl == null) {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 7457a1d05335..23091a00a80b 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -535,8 +535,8 @@ class WindowToken extends WindowContainer<WindowState> {
}
@Override
- void updateSurfacePosition() {
- super.updateSurfacePosition();
+ void updateSurfacePosition(SurfaceControl.Transaction t) {
+ super.updateSurfacePosition(t);
if (isFixedRotationTransforming()) {
// The window is layouted in a simulated rotated display but the real display hasn't
// rotated, so here transforms its surface to fit in the real display.
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index d36eae89c1ff..de24bcf02a7e 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -73,7 +73,7 @@ struct Constants {
};
static const Constants& constants() {
- static Constants c;
+ static constexpr Constants c;
return c;
}
@@ -159,6 +159,9 @@ std::string makeBindMdName() {
}
} // namespace
+const bool IncrementalService::sEnablePerfLogging =
+ android::base::GetBoolProperty("incremental.perflogging", false);
+
IncrementalService::IncFsMount::~IncFsMount() {
incrementalService.mDataLoaderManager->destroyDataLoader(mountId);
LOG(INFO) << "Unmounting and cleaning up mount " << mountId << " with root '" << root << '\'';
@@ -719,7 +722,10 @@ int IncrementalService::bind(StorageId storage, std::string_view source, std::st
if (storageInfo == ifs->storages.end()) {
return -EINVAL;
}
- std::string normSource = normalizePathToStorage(ifs, storage, source);
+ std::string normSource = normalizePathToStorageLocked(storageInfo, source);
+ if (normSource.empty()) {
+ return -EINVAL;
+ }
l.unlock();
std::unique_lock l2(mLock, std::defer_lock);
return addBindMount(*ifs, storage, storageInfo->second.name, std::move(normSource),
@@ -768,22 +774,28 @@ int IncrementalService::unbind(StorageId storage, std::string_view target) {
return 0;
}
-std::string IncrementalService::normalizePathToStorage(const IncrementalService::IfsMountPtr ifs,
- StorageId storage, std::string_view path) {
- const auto storageInfo = ifs->storages.find(storage);
- if (storageInfo == ifs->storages.end()) {
- return {};
- }
+std::string IncrementalService::normalizePathToStorageLocked(
+ IncFsMount::StorageMap::iterator storageIt, std::string_view path) {
std::string normPath;
if (path::isAbsolute(path)) {
normPath = path::normalize(path);
+ if (!path::startsWith(normPath, storageIt->second.name)) {
+ return {};
+ }
} else {
- normPath = path::normalize(path::join(storageInfo->second.name, path));
+ normPath = path::normalize(path::join(storageIt->second.name, path));
}
- if (!path::startsWith(normPath, storageInfo->second.name)) {
+ return normPath;
+}
+
+std::string IncrementalService::normalizePathToStorage(const IncrementalService::IfsMountPtr& ifs,
+ StorageId storage, std::string_view path) {
+ std::unique_lock l(ifs->lock);
+ const auto storageInfo = ifs->storages.find(storage);
+ if (storageInfo == ifs->storages.end()) {
return {};
}
- return normPath;
+ return normalizePathToStorageLocked(storageInfo, path);
}
int IncrementalService::makeFile(StorageId storage, std::string_view path, int mode, FileId id,
@@ -791,7 +803,8 @@ int IncrementalService::makeFile(StorageId storage, std::string_view path, int m
if (auto ifs = getIfs(storage)) {
std::string normPath = normalizePathToStorage(ifs, storage, path);
if (normPath.empty()) {
- LOG(ERROR) << "Internal error: storageId " << storage << " failed to normalize: " << path;
+ LOG(ERROR) << "Internal error: storageId " << storage
+ << " failed to normalize: " << path;
return -EINVAL;
}
auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params);
@@ -799,10 +812,6 @@ int IncrementalService::makeFile(StorageId storage, std::string_view path, int m
LOG(ERROR) << "Internal error: storageId " << storage << " failed to makeFile: " << err;
return err;
}
- std::vector<uint8_t> metadataBytes;
- if (params.metadata.data && params.metadata.size > 0) {
- metadataBytes.assign(params.metadata.data, params.metadata.data + params.metadata.size);
- }
return 0;
}
return -EINVAL;
@@ -842,8 +851,9 @@ int IncrementalService::makeDirs(StorageId storageId, std::string_view path, int
int IncrementalService::link(StorageId sourceStorageId, std::string_view oldPath,
StorageId destStorageId, std::string_view newPath) {
- if (auto ifsSrc = getIfs(sourceStorageId), ifsDest = getIfs(destStorageId);
- ifsSrc && ifsSrc == ifsDest) {
+ auto ifsSrc = getIfs(sourceStorageId);
+ auto ifsDest = sourceStorageId == destStorageId ? ifsSrc : getIfs(destStorageId);
+ if (ifsSrc && ifsSrc == ifsDest) {
std::string normOldPath = normalizePathToStorage(ifsSrc, sourceStorageId, oldPath);
std::string normNewPath = normalizePathToStorage(ifsDest, destStorageId, newPath);
if (normOldPath.empty() || normNewPath.empty()) {
@@ -1156,11 +1166,25 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs,
return true;
}
-// Extract lib filse from zip, create new files in incfs and write data to them
+template <class Duration>
+static long elapsedMcs(Duration start, Duration end) {
+ return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
+}
+
+// Extract lib files from zip, create new files in incfs and write data to them
bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
std::string_view libDirRelativePath,
std::string_view abi) {
+ namespace sc = std::chrono;
+ using Clock = sc::steady_clock;
+ auto start = Clock::now();
+
const auto ifs = getIfs(storage);
+ if (!ifs) {
+ LOG(ERROR) << "Invalid storage " << storage;
+ return false;
+ }
+
// First prepare target directories if they don't exist yet
if (auto res = makeDirs(storage, libDirRelativePath, 0755)) {
LOG(ERROR) << "Failed to prepare target lib directory " << libDirRelativePath
@@ -1168,112 +1192,145 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
return false;
}
- std::unique_ptr<ZipFileRO> zipFile(ZipFileRO::open(apkFullPath.data()));
+ auto mkDirsTs = Clock::now();
+
+ std::unique_ptr<ZipFileRO> zipFile(ZipFileRO::open(path::c_str(apkFullPath)));
if (!zipFile) {
LOG(ERROR) << "Failed to open zip file at " << apkFullPath;
return false;
}
void* cookie = nullptr;
const auto libFilePrefix = path::join(constants().libDir, abi);
- if (!zipFile.get()->startIteration(&cookie, libFilePrefix.c_str() /* prefix */,
- constants().libSuffix.data() /* suffix */)) {
+ if (!zipFile->startIteration(&cookie, libFilePrefix.c_str() /* prefix */,
+ constants().libSuffix.data() /* suffix */)) {
LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath;
return false;
}
+ auto endIteration = [&zipFile](void* cookie) { zipFile->endIteration(cookie); };
+ auto iterationCleaner = std::unique_ptr<void, decltype(endIteration)>(cookie, endIteration);
+
+ auto openZipTs = Clock::now();
+
+ std::vector<IncFsDataBlock> instructions;
ZipEntryRO entry = nullptr;
- bool success = true;
- while ((entry = zipFile.get()->nextEntry(cookie)) != nullptr) {
+ while ((entry = zipFile->nextEntry(cookie)) != nullptr) {
+ auto startFileTs = Clock::now();
+
char fileName[PATH_MAX];
- if (zipFile.get()->getEntryFileName(entry, fileName, sizeof(fileName))) {
+ if (zipFile->getEntryFileName(entry, fileName, sizeof(fileName))) {
continue;
}
const auto libName = path::basename(fileName);
const auto targetLibPath = path::join(libDirRelativePath, libName);
const auto targetLibPathAbsolute = normalizePathToStorage(ifs, storage, targetLibPath);
// If the extract file already exists, skip
- struct stat st;
- if (stat(targetLibPathAbsolute.c_str(), &st) == 0) {
- LOG(INFO) << "Native lib file already exists: " << targetLibPath
- << "; skipping extraction";
+ if (access(targetLibPathAbsolute.c_str(), F_OK) == 0) {
+ if (sEnablePerfLogging) {
+ LOG(INFO) << "incfs: Native lib file already exists: " << targetLibPath
+ << "; skipping extraction, spent "
+ << elapsedMcs(startFileTs, Clock::now()) << "mcs";
+ }
continue;
}
- uint32_t uncompressedLen;
- if (!zipFile.get()->getEntryInfo(entry, nullptr, &uncompressedLen, nullptr, nullptr,
- nullptr, nullptr)) {
+ uint32_t uncompressedLen, compressedLen;
+ if (!zipFile->getEntryInfo(entry, nullptr, &uncompressedLen, &compressedLen, nullptr,
+ nullptr, nullptr)) {
LOG(ERROR) << "Failed to read native lib entry: " << fileName;
- success = false;
- break;
+ return false;
}
// Create new lib file without signature info
- incfs::NewFileParams libFileParams{};
- libFileParams.size = uncompressedLen;
- libFileParams.signature = {};
- // Metadata of the new lib file is its relative path
- IncFsSpan libFileMetadata;
- libFileMetadata.data = targetLibPath.c_str();
- libFileMetadata.size = targetLibPath.size();
- libFileParams.metadata = libFileMetadata;
+ incfs::NewFileParams libFileParams = {
+ .size = uncompressedLen,
+ .signature = {},
+ // Metadata of the new lib file is its relative path
+ .metadata = {targetLibPath.c_str(), (IncFsSize)targetLibPath.size()},
+ };
incfs::FileId libFileId = idFromMetadata(targetLibPath);
- if (auto res = makeFile(storage, targetLibPath, 0777, libFileId, libFileParams)) {
+ if (auto res = mIncFs->makeFile(ifs->control, targetLibPathAbsolute, 0777, libFileId,
+ libFileParams)) {
LOG(ERROR) << "Failed to make file for: " << targetLibPath << " errno: " << res;
- success = false;
// If one lib file fails to be created, abort others as well
- break;
+ return false;
}
+
+ auto makeFileTs = Clock::now();
+
// If it is a zero-byte file, skip data writing
if (uncompressedLen == 0) {
+ if (sEnablePerfLogging) {
+ LOG(INFO) << "incfs: Extracted " << libName << "(" << compressedLen << " -> "
+ << uncompressedLen << " bytes): " << elapsedMcs(startFileTs, makeFileTs)
+ << "mcs, make: " << elapsedMcs(startFileTs, makeFileTs);
+ }
continue;
}
// Write extracted data to new file
- std::vector<uint8_t> libData(uncompressedLen);
- if (!zipFile.get()->uncompressEntry(entry, &libData[0], uncompressedLen)) {
+ // NOTE: don't zero-initialize memory, it may take a while
+ auto libData = std::unique_ptr<uint8_t[]>(new uint8_t[uncompressedLen]);
+ if (!zipFile->uncompressEntry(entry, libData.get(), uncompressedLen)) {
LOG(ERROR) << "Failed to extract native lib zip entry: " << fileName;
- success = false;
- break;
+ return false;
}
+
+ auto extractFileTs = Clock::now();
+
const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId);
if (!writeFd.ok()) {
LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd;
- success = false;
- break;
+ return false;
}
- const int numBlocks = uncompressedLen / constants().blockSize + 1;
- std::vector<IncFsDataBlock> instructions;
- auto remainingData = std::span(libData);
- for (int i = 0; i < numBlocks - 1; i++) {
+
+ auto openFileTs = Clock::now();
+
+ const int numBlocks = (uncompressedLen + constants().blockSize - 1) / constants().blockSize;
+ instructions.clear();
+ instructions.reserve(numBlocks);
+ auto remainingData = std::span(libData.get(), uncompressedLen);
+ for (int i = 0; i < numBlocks; i++) {
+ const auto blockSize = std::min<uint16_t>(constants().blockSize, remainingData.size());
auto inst = IncFsDataBlock{
- .fileFd = writeFd,
+ .fileFd = writeFd.get(),
.pageIndex = static_cast<IncFsBlockIndex>(i),
.compression = INCFS_COMPRESSION_KIND_NONE,
.kind = INCFS_BLOCK_KIND_DATA,
- .dataSize = static_cast<uint16_t>(constants().blockSize),
+ .dataSize = blockSize,
.data = reinterpret_cast<const char*>(remainingData.data()),
};
instructions.push_back(inst);
- remainingData = remainingData.subspan(constants().blockSize);
+ remainingData = remainingData.subspan(blockSize);
}
- // Last block
- auto inst = IncFsDataBlock{
- .fileFd = writeFd,
- .pageIndex = static_cast<IncFsBlockIndex>(numBlocks - 1),
- .compression = INCFS_COMPRESSION_KIND_NONE,
- .kind = INCFS_BLOCK_KIND_DATA,
- .dataSize = static_cast<uint16_t>(remainingData.size()),
- .data = reinterpret_cast<const char*>(remainingData.data()),
- };
- instructions.push_back(inst);
+ auto prepareInstsTs = Clock::now();
+
size_t res = mIncFs->writeBlocks(instructions);
if (res != instructions.size()) {
LOG(ERROR) << "Failed to write data into: " << targetLibPath;
- success = false;
+ return false;
+ }
+
+ if (sEnablePerfLogging) {
+ auto endFileTs = Clock::now();
+ LOG(INFO) << "incfs: Extracted " << libName << "(" << compressedLen << " -> "
+ << uncompressedLen << " bytes): " << elapsedMcs(startFileTs, endFileTs)
+ << "mcs, make: " << elapsedMcs(startFileTs, makeFileTs)
+ << " extract: " << elapsedMcs(makeFileTs, extractFileTs)
+ << " open: " << elapsedMcs(extractFileTs, openFileTs)
+ << " prepare: " << elapsedMcs(openFileTs, prepareInstsTs)
+ << " write:" << elapsedMcs(prepareInstsTs, endFileTs);
}
- instructions.clear();
}
- zipFile.get()->endIteration(cookie);
- return success;
+
+ if (sEnablePerfLogging) {
+ auto end = Clock::now();
+ LOG(INFO) << "incfs: configureNativeBinaries complete in " << elapsedMcs(start, end)
+ << "mcs, make dirs: " << elapsedMcs(start, mkDirsTs)
+ << " open zip: " << elapsedMcs(mkDirsTs, openZipTs)
+ << " extract all: " << elapsedMcs(openZipTs, end);
+ }
+
+ return true;
}
void IncrementalService::registerAppOpsCallback(const std::string& packageName) {
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 58002974e180..9b156464f480 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -157,6 +157,8 @@ public:
};
private:
+ static const bool sEnablePerfLogging;
+
struct IncFsMount {
struct Bind {
StorageId storage;
@@ -227,8 +229,10 @@ private:
void deleteStorage(IncFsMount& ifs);
void deleteStorageLocked(IncFsMount& ifs, std::unique_lock<std::mutex>&& ifsLock);
MountMap::iterator getStorageSlotLocked();
- std::string normalizePathToStorage(const IfsMountPtr incfs, StorageId storage,
+ std::string normalizePathToStorage(const IfsMountPtr& incfs, StorageId storage,
std::string_view path);
+ std::string normalizePathToStorageLocked(IncFsMount::StorageMap::iterator storageIt,
+ std::string_view path);
binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e5ffbacb357b..e2a247394a81 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -136,6 +136,7 @@ import com.android.server.pm.OtaDexoptService;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.ShortcutService;
import com.android.server.pm.UserManagerService;
+import com.android.server.pm.dex.SystemServerDexLoadReporter;
import com.android.server.policy.PermissionPolicyService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.policy.role.LegacyRoleResolutionPolicy;
@@ -837,6 +838,11 @@ public final class SystemServer {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
+ // Now that the package manager has started, register the dex load reporter to capture any
+ // dex files loaded by system server.
+ // These dex files will be optimized by the BackgroundDexOptService.
+ SystemServerDexLoadReporter.configureSystemServerDexReporter(mPackageManagerService);
+
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
t.traceEnd();
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index d69e1b8786b4..8398585ca74a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -85,6 +85,9 @@ public class DexManagerTests {
private TestData mBarUser0UnsupportedClassLoader;
private TestData mBarUser0DelegateLastClassLoader;
+ private TestData mSystemServerJar;
+ private TestData mSystemServerJarInvalid;
+
private int mUser0;
private int mUser1;
@@ -108,6 +111,9 @@ public class DexManagerTests {
mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0,
DELEGATE_LAST_CLASS_LOADER_NAME);
+ mSystemServerJar = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME);
+ mSystemServerJarInvalid = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME);
+
mDexManager = new DexManager(/*Context*/ null, mPM, /*PackageDexOptimizer*/ null,
mInstaller, mInstallLock);
@@ -587,6 +593,25 @@ public class DexManagerTests {
assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries);
}
+
+ @Test
+ public void testNotifySystemServerUse() {
+ List<String> dexFiles = new ArrayList<String>();
+ dexFiles.add("/system/framework/foo");
+ notifyDexLoad(mSystemServerJar, dexFiles, mUser0);
+ PackageUseInfo pui = getPackageUseInfo(mSystemServerJar);
+ assertIsUsedByOtherApps(mSystemServerJar, pui, false);
+ }
+
+ @Test
+ public void testNotifySystemServerInvalidUse() {
+ List<String> dexFiles = new ArrayList<String>();
+ dexFiles.add("/data/foo");
+ notifyDexLoad(mSystemServerJarInvalid, dexFiles, mUser0);
+ assertNoUseInfo(mSystemServerJarInvalid);
+ assertNoDclInfo(mSystemServerJarInvalid);
+ }
+
private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId,
String[] expectedContexts) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 89bc65b5a44d..b6eb9010ce90 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -30,7 +30,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -41,7 +40,6 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
import android.platform.test.annotations.Presubmit;
import android.util.IntArray;
@@ -49,7 +47,6 @@ import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.test.InsetsModeSession;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.AfterClass;
@@ -168,6 +165,18 @@ public class InsetsPolicyTest extends WindowTestsBase {
}
@Test
+ public void testControlsForDispatch_forceShowSystemBarsFromExternal_appHasNoControl() {
+ mDisplayContent.getDisplayPolicy().setForceShowSystemBars(true);
+ addWindow(TYPE_STATUS_BAR, "statusBar");
+ addWindow(TYPE_NAVIGATION_BAR, "navBar");
+
+ final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
+
+ // The focused app window cannot control system bars.
+ assertNull(controls);
+ }
+
+ @Test
public void testShowTransientBars_bothCanBeTransient_appGetsBothFakeControls() {
addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar")
.getControllableInsetProvider().getSource().setVisible(false);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index add4e9cf3948..ea933dfe42dc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1124,8 +1124,6 @@ public class RecentTasksTest extends ActivityTestsBase {
}
});
assertSecurityException(expectCallable,
- () -> mService.moveTasksToFullscreenStack(INVALID_STACK_ID, true));
- assertSecurityException(expectCallable,
() -> mService.startActivityFromRecents(0, new Bundle()));
assertSecurityException(expectCallable, () -> mService.getTaskSnapshot(0, true));
assertSecurityException(expectCallable, () -> mService.registerTaskStackListener(null));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 6d2b7b1e86fe..f19550ced0bf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -23,7 +23,6 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -318,7 +317,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
// Assume activity transition should animate when no
// IRecentsAnimationController#setDeferCancelUntilNextTransition called.
assertFalse(mController.shouldDeferCancelWithScreenshot());
- assertTrue(activity.shouldAnimate(TRANSIT_ACTIVITY_CLOSE));
+ assertTrue(activity.shouldAnimate());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 1ca2e318b0d7..397f73c3e67c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -134,6 +134,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
mChildAppWindowBelow = createCommonWindow(mAppWindow,
TYPE_APPLICATION_MEDIA_OVERLAY,
"mChildAppWindowBelow");
+ mDisplayContent.getDisplayPolicy().setForceShowSystemBars(false);
}
// Adding a display will cause freezing the display. Make sure to wait until it's
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index f3e9de0d2688..3048ad7c1fb0 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -311,7 +311,7 @@ public final class LocationAccessPolicy {
}
// If the user or profile is current, permission is granted.
// Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
- return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, uid, pid);
+ return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, pid, uid);
}
private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {