diff options
20 files changed, 149 insertions, 27 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2beb64d98c99..b26504dd1c49 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4164,7 +4164,8 @@ public final class ActivityThread extends ClientTransactionHandler private void scheduleResume(ActivityClientRecord r) { final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token); - transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(/* isForward */ false)); + transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(/* isForward */ false, + /* shouldSendCompatFakeFocus */ false)); executeTransaction(transaction); } @@ -4791,7 +4792,7 @@ public final class ActivityThread extends ClientTransactionHandler @Override public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest, - boolean isForward, String reason) { + boolean isForward, boolean shouldSendCompatFakeFocus, String reason) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); @@ -4898,6 +4899,16 @@ public final class ActivityThread extends ClientTransactionHandler if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); } + + if (shouldSendCompatFakeFocus) { + // Attaching to a window is asynchronous with the activity being resumed, + // so it's possible we will need to send a fake focus event after attaching + if (impl != null) { + impl.dispatchCompatFakeFocus(); + } else { + r.window.getDecorView().fakeFocusAfterAttachingToWindow(); + } + } } r.nextIdle = mNewActivities; diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 2c70c4e90157..d7fa732cfb3d 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -109,7 +109,8 @@ public abstract class ClientTransactionHandler { * @param reason Reason for performing this operation. */ public abstract void handleResumeActivity(@NonNull ActivityClientRecord r, - boolean finalStateRequest, boolean isForward, String reason); + boolean finalStateRequest, boolean isForward, boolean shouldSendCompatFakeFocus, + String reason); /** * Notify the activity about top resumed state change. diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java index e6fdc006615a..222f8ca61e09 100644 --- a/core/java/android/app/servertransaction/ResumeActivityItem.java +++ b/core/java/android/app/servertransaction/ResumeActivityItem.java @@ -39,6 +39,9 @@ public class ResumeActivityItem extends ActivityLifecycleItem { private int mProcState; private boolean mUpdateProcState; private boolean mIsForward; + // Whether we should send compat fake focus when the activity is resumed. This is needed + // because some game engines wait to get focus before drawing the content of the app. + private boolean mShouldSendCompatFakeFocus; @Override public void preExecute(ClientTransactionHandler client, IBinder token) { @@ -52,7 +55,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem { PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward, - "RESUME_ACTIVITY"); + mShouldSendCompatFakeFocus, "RESUME_ACTIVITY"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -74,7 +77,8 @@ public class ResumeActivityItem extends ActivityLifecycleItem { private ResumeActivityItem() {} /** Obtain an instance initialized with provided params. */ - public static ResumeActivityItem obtain(int procState, boolean isForward) { + public static ResumeActivityItem obtain(int procState, boolean isForward, + boolean shouldSendCompatFakeFocus) { ResumeActivityItem instance = ObjectPool.obtain(ResumeActivityItem.class); if (instance == null) { instance = new ResumeActivityItem(); @@ -82,12 +86,13 @@ public class ResumeActivityItem extends ActivityLifecycleItem { instance.mProcState = procState; instance.mUpdateProcState = true; instance.mIsForward = isForward; + instance.mShouldSendCompatFakeFocus = shouldSendCompatFakeFocus; return instance; } /** Obtain an instance initialized with provided params. */ - public static ResumeActivityItem obtain(boolean isForward) { + public static ResumeActivityItem obtain(boolean isForward, boolean shouldSendCompatFakeFocus) { ResumeActivityItem instance = ObjectPool.obtain(ResumeActivityItem.class); if (instance == null) { instance = new ResumeActivityItem(); @@ -95,6 +100,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem { instance.mProcState = ActivityManager.PROCESS_STATE_UNKNOWN; instance.mUpdateProcState = false; instance.mIsForward = isForward; + instance.mShouldSendCompatFakeFocus = shouldSendCompatFakeFocus; return instance; } @@ -105,6 +111,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem { mProcState = ActivityManager.PROCESS_STATE_UNKNOWN; mUpdateProcState = false; mIsForward = false; + mShouldSendCompatFakeFocus = false; ObjectPool.recycle(this); } @@ -117,6 +124,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem { dest.writeInt(mProcState); dest.writeBoolean(mUpdateProcState); dest.writeBoolean(mIsForward); + dest.writeBoolean(mShouldSendCompatFakeFocus); } /** Read from Parcel. */ @@ -124,6 +132,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem { mProcState = in.readInt(); mUpdateProcState = in.readBoolean(); mIsForward = in.readBoolean(); + mShouldSendCompatFakeFocus = in.readBoolean(); } public static final @NonNull Creator<ResumeActivityItem> CREATOR = @@ -147,7 +156,8 @@ public class ResumeActivityItem extends ActivityLifecycleItem { } final ResumeActivityItem other = (ResumeActivityItem) o; return mProcState == other.mProcState && mUpdateProcState == other.mUpdateProcState - && mIsForward == other.mIsForward; + && mIsForward == other.mIsForward + && mShouldSendCompatFakeFocus == other.mShouldSendCompatFakeFocus; } @Override @@ -156,12 +166,14 @@ public class ResumeActivityItem extends ActivityLifecycleItem { result = 31 * result + mProcState; result = 31 * result + (mUpdateProcState ? 1 : 0); result = 31 * result + (mIsForward ? 1 : 0); + result = 31 * result + (mShouldSendCompatFakeFocus ? 1 : 0); return result; } @Override public String toString() { return "ResumeActivityItem{procState=" + mProcState - + ",updateProcState=" + mUpdateProcState + ",isForward=" + mIsForward + "}"; + + ",updateProcState=" + mUpdateProcState + ",isForward=" + mIsForward + + ",shouldSendCompatFakeFocus=" + mShouldSendCompatFakeFocus + "}"; } } diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index 1ff0b796fb1e..c8f7d100a398 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -226,7 +226,8 @@ public class TransactionExecutor { break; case ON_RESUME: mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */, - r.isForward, "LIFECYCLER_RESUME_ACTIVITY"); + r.isForward, false /* shouldSendCompatFakeFocus */, + "LIFECYCLER_RESUME_ACTIVITY"); break; case ON_PAUSE: mTransactionHandler.handlePauseActivity(r, false /* finished */, diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java index 92f7dee0b0ad..6c188795e028 100644 --- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java +++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java @@ -195,7 +195,8 @@ public class TransactionExecutorHelper { lifecycleItem = StopActivityItem.obtain(0 /* configChanges */); break; default: - lifecycleItem = ResumeActivityItem.obtain(false /* isForward */); + lifecycleItem = ResumeActivityItem.obtain(false /* isForward */, + false /* shouldSendCompatFakeFocus */); break; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index a78af04995d3..333efad2c4c8 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -21264,6 +21264,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return Math.max(vis1, vis2); } + private boolean mShouldFakeFocus = false; + + /** + * Fake send a focus event after attaching to window. + * See {@link android.view.ViewRootImpl#dispatchCompatFakeFocus()} for details. + * @hide + */ + public void fakeFocusAfterAttachingToWindow() { + mShouldFakeFocus = true; + } + /** * @param info the {@link android.view.View.AttachInfo} to associated with * this view @@ -21332,6 +21343,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyEnterOrExitForAutoFillIfNeeded(true); notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); + + if (mShouldFakeFocus) { + getViewRootImpl().dispatchCompatFakeFocus(); + mShouldFakeFocus = false; + } } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index af070238787f..6f4a63ca0fd7 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -258,6 +258,7 @@ public final class ViewRootImpl implements ViewParent, private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV; private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV; private static final boolean DEBUG_BLAST = false || LOCAL_LOGV; + private static final int LOGTAG_INPUT_FOCUS = 62001; /** * Set to false if we do not want to use the multi threaded renderer even though @@ -3808,8 +3809,7 @@ public final class ViewRootImpl implements ViewParent, } if (mAdded) { - dispatchFocusEvent(hasWindowFocus); - + dispatchFocusEvent(hasWindowFocus, false /* fakeFocus */); // Note: must be done after the focus change callbacks, // so all of the view state is set up correctly. mImeFocusController.onPostWindowFocus( @@ -3844,7 +3844,33 @@ public final class ViewRootImpl implements ViewParent, } } - private void dispatchFocusEvent(boolean hasWindowFocus) { + /** + * Send a fake focus event for unfocused apps in split screen as some game engines wait to + * get focus before drawing the content of the app. This will be used so that apps do not get + * blacked out when they are resumed and do not have focus yet. + * + * {@hide} + */ + // TODO(b/263094829): Investigate dispatching this for onPause as well + public void dispatchCompatFakeFocus() { + boolean aboutToHaveFocus = false; + synchronized (this) { + aboutToHaveFocus = mWindowFocusChanged && mUpcomingWindowFocus; + } + final boolean alreadyHaveFocus = mAttachInfo.mHasWindowFocus; + if (aboutToHaveFocus || alreadyHaveFocus) { + // Do not need to toggle focus if app doesn't need it, or has focus. + return; + } + EventLog.writeEvent(LOGTAG_INPUT_FOCUS, + "Giving fake focus to " + mBasePackageName, "reason=unity bug workaround"); + dispatchFocusEvent(true /* hasWindowFocus */, true /* fakeFocus */); + EventLog.writeEvent(LOGTAG_INPUT_FOCUS, + "Removing fake focus from " + mBasePackageName, "reason=timeout callback"); + dispatchFocusEvent(false /* hasWindowFocus */, true /* fakeFocus */); + } + + private void dispatchFocusEvent(boolean hasWindowFocus, boolean fakeFocus) { profileRendering(hasWindowFocus); if (hasWindowFocus && mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) { mFullRedrawNeeded = true; @@ -3870,8 +3896,10 @@ public final class ViewRootImpl implements ViewParent, } mAttachInfo.mHasWindowFocus = hasWindowFocus; - mImeFocusController.updateImeFocusable(mWindowAttributes, true /* force */); - mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes); + if (!fakeFocus) { + mImeFocusController.updateImeFocusable(mWindowAttributes, true /* force */); + mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes); + } if (mView != null) { mAttachInfo.mKeyDispatchState.reset(); diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a0d6e470041a..a8c2246ef966 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5344,6 +5344,11 @@ TODO(b/255532890) Enable when ignoreOrientationRequest is set --> <bool name="config_letterboxIsEnabledForTranslucentActivities">false</bool> + <!-- Whether sending compat fake focus for split screen resumed activities is enabled. + Needed because some game engines wait to get focus before drawing the content of + the app which isn't guaranteed by default in multi-window modes. --> + <bool name="config_isCompatFakeFocusEnabled">false</bool> + <!-- Whether camera compat treatment is enabled for issues caused by orientation mismatch between camera buffers and an app window. This includes force rotation of fixed orientation activities connected to the camera in fullscreen and showing a tooltip in diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 371dbfb21587..5c3e1d69c6b5 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4460,6 +4460,7 @@ <java-symbol type="bool" name="config_letterboxIsEducationEnabled" /> <java-symbol type="dimen" name="config_letterboxDefaultMinAspectRatioForUnresizableApps" /> <java-symbol type="bool" name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled" /> + <java-symbol type="bool" name="config_isCompatFakeFocusEnabled" /> <java-symbol type="bool" name="config_isWindowManagerCameraCompatTreatmentEnabled" /> <java-symbol type="bool" name="config_isCameraCompatControlForStretchedIssuesEnabled" /> diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index a2d4bafef41c..984ba584953a 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -692,7 +692,8 @@ public class ActivityThreadTest { final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null, null, 0, new MergedConfiguration(), false /* preserveWindow */); final ResumeActivityItem resumeStateRequest = - ResumeActivityItem.obtain(true /* isForward */); + ResumeActivityItem.obtain(true /* isForward */, + false /* shouldSendCompatFakeFocus*/); final ClientTransaction transaction = newTransaction(activity); transaction.addCallback(callbackItem); @@ -703,7 +704,8 @@ public class ActivityThreadTest { private static ClientTransaction newResumeTransaction(Activity activity) { final ResumeActivityItem resumeStateRequest = - ResumeActivityItem.obtain(true /* isForward */); + ResumeActivityItem.obtain(true /* isForward */, + false /* shouldSendCompatFakeFocus */); final ClientTransaction transaction = newTransaction(activity); transaction.setLifecycleStateRequest(resumeStateRequest); diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index 942e1cf3eed5..0056bddc4cce 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -238,15 +238,15 @@ public class ObjectPoolTests { @Test public void testRecycleResumeActivityItem() { - ResumeActivityItem emptyItem = ResumeActivityItem.obtain(false); - ResumeActivityItem item = ResumeActivityItem.obtain(3, true); + ResumeActivityItem emptyItem = ResumeActivityItem.obtain(false, false); + ResumeActivityItem item = ResumeActivityItem.obtain(3, true, false); assertNotSame(item, emptyItem); assertFalse(item.equals(emptyItem)); item.recycle(); assertEquals(item, emptyItem); - ResumeActivityItem item2 = ResumeActivityItem.obtain(2, true); + ResumeActivityItem item2 = ResumeActivityItem.obtain(2, true, false); assertSame(item, item2); assertFalse(item2.equals(emptyItem)); } diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index c868963c4d02..8cab40a501ab 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -250,7 +250,7 @@ public class TransactionParcelTests { public void testResume() { // Write to parcel ResumeActivityItem item = ResumeActivityItem.obtain(27 /* procState */, - true /* isForward */); + true /* isForward */, false /* shouldSendCompatFakeFocus */); writeAndPrepareForReading(item); // Read from parcel and assert diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index 1d0644897fc2..2afbb476bc16 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -297,6 +297,20 @@ public class ViewRootImplTest { } } + @Test + public void whenDispatchFakeFocus_focusDoesNotPersist() throws Exception { + View view = new View(sContext); + attachViewToWindow(view); + view.clearFocus(); + + assertThat(view.hasWindowFocus()).isFalse(); + + mViewRootImpl = view.getViewRootImpl(); + + mViewRootImpl.dispatchCompatFakeFocus(); + assertThat(view.hasWindowFocus()).isFalse(); + } + /** * When window doesn't have focus, keys should be dropped. */ diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index ad72d49d2d6d..5acfc15ac7dc 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -294,7 +294,7 @@ public class ActivityThreadClientTest { private void resumeActivity(ActivityClientRecord r) { mThread.handleResumeActivity(r, true /* finalStateRequest */, - true /* isForward */, "test"); + true /* isForward */, false /* shouldSendCompatFakeFocus */, "test"); } private void pauseActivity(ActivityClientRecord r) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 50169b4ba667..f38633fb0e6c 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -9351,7 +9351,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A preserveWindow); final ActivityLifecycleItem lifecycleItem; if (andResume) { - lifecycleItem = ResumeActivityItem.obtain(isTransitionForward()); + lifecycleItem = ResumeActivityItem.obtain(isTransitionForward(), + shouldSendCompatFakeFocus()); } else { lifecycleItem = PauseActivityItem.obtain(); } @@ -10118,6 +10119,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + /** + * Whether we should send fake focus when the activity is resumed. This is done because some + * game engines wait to get focus before drawing the content of the app. + */ + // TODO(b/263593361): Explore enabling compat fake focus for freeform. + // TODO(b/263592337): Explore enabling compat fake focus for fullscreen, e.g. for when + // covered with bubbles. + boolean shouldSendCompatFakeFocus() { + return mWmService.mLetterboxConfiguration.isCompatFakeFocusEnabled() && inMultiWindowMode() + && !inPinnedWindowingMode() && !inFreeformWindowingMode(); + } + static class Builder { private final ActivityTaskManagerService mAtmService; private WindowProcessController mCallerApp; diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 565b8f8d117c..9b9337e24f53 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -918,7 +918,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // Set desired final state. final ActivityLifecycleItem lifecycleItem; if (andResume) { - lifecycleItem = ResumeActivityItem.obtain(isTransitionForward); + lifecycleItem = ResumeActivityItem.obtain(isTransitionForward, + r.shouldSendCompatFakeFocus()); } else { lifecycleItem = PauseActivityItem.obtain(); } diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java index 18c5c3b82b19..7266d2194779 100644 --- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java @@ -214,7 +214,8 @@ final class DisplayRotationCompatPolicy { activity.app.getThread(), activity.token); transaction.addCallback( RefreshCallbackItem.obtain(cycleThroughStop ? ON_STOP : ON_PAUSE)); - transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(/* isForward */ false)); + transaction.setLifecycleStateRequest(ResumeActivityItem.obtain( + /* isForward */ false, /* shouldSendCompatFakeFocus */ false)); activity.mAtmService.getLifecycleManager().scheduleTransaction(transaction); mHandler.postDelayed( () -> onActivityRefreshed(activity), diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index a7bf595fa673..03c558924430 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -191,6 +191,11 @@ final class LetterboxConfiguration { // Allows to enable letterboxing strategy for translucent activities ignoring flags. private boolean mTranslucentLetterboxingOverrideEnabled; + // Whether sending compat fake focus is enabled for unfocused apps in splitscreen. Some game + // engines wait to get focus before drawing the content of the app so this needs to be used + // otherwise the apps get blacked out when they are resumed and do not have focus yet. + private boolean mIsCompatFakeFocusEnabled; + // Whether camera compatibility treatment is enabled. // See DisplayRotationCompatPolicy for context. private final boolean mIsCameraCompatTreatmentEnabled; @@ -259,6 +264,8 @@ final class LetterboxConfiguration { R.bool.config_isWindowManagerCameraCompatTreatmentEnabled); mLetterboxConfigurationPersister = letterboxConfigurationPersister; mLetterboxConfigurationPersister.start(); + mIsCompatFakeFocusEnabled = mContext.getResources() + .getBoolean(R.bool.config_isCompatFakeFocusEnabled); } /** @@ -970,6 +977,13 @@ final class LetterboxConfiguration { "enable_translucent_activity_letterbox", false); } + // TODO(b/262866240): Add listener to check for device config property + /** Whether fake sending focus is enabled for unfocused apps in splitscreen */ + boolean isCompatFakeFocusEnabled() { + return mIsCompatFakeFocusEnabled && DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_WINDOW_MANAGER, "enable_compat_fake_focus", true); + } + /** Whether camera compatibility treatment is enabled. */ boolean isCameraCompatTreatmentEnabled(boolean checkDeviceConfig) { return mIsCameraCompatTreatmentEnabled diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index f6db3f7cbb36..be541ae0ba20 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -1472,7 +1472,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { next.abortAndClearOptionsAnimation(); transaction.setLifecycleStateRequest( ResumeActivityItem.obtain(next.app.getReportedProcState(), - dc.isNextTransitionForward())); + dc.isNextTransitionForward(), next.shouldSendCompatFakeFocus())); mAtmService.getLifecycleManager().scheduleTransaction(transaction); ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java index d1234e3de81a..8bb79e3f7ddc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java @@ -398,7 +398,8 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { final ClientTransaction transaction = ClientTransaction.obtain( mActivity.app.getThread(), mActivity.token); transaction.addCallback(RefreshCallbackItem.obtain(cycleThroughStop ? ON_STOP : ON_PAUSE)); - transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(/* isForward */ false)); + transaction.setLifecycleStateRequest(ResumeActivityItem.obtain( + /* isForward */ false, /* shouldSendCompatFakeFocus */ false)); verify(mActivity.mAtmService.getLifecycleManager(), times(refreshRequested ? 1 : 0)) .scheduleTransaction(eq(transaction)); |