Snap for 8084085 from 785ee1a55c to sc-v2-release
Change-Id: If9982c1586e37bf5863c0777d2cbba45a0437b43
This commit is contained in:
@@ -311,6 +311,14 @@ class ContextImpl extends Context {
|
||||
@ContextType
|
||||
private int mContextType;
|
||||
|
||||
/**
|
||||
* {@code true} to indicate that the {@link Context} owns the {@link #getWindowContextToken()}
|
||||
* and is responsible for detaching the token when the Context is released.
|
||||
*
|
||||
* @see #finalize()
|
||||
*/
|
||||
private boolean mOwnsToken = false;
|
||||
|
||||
@GuardedBy("mSync")
|
||||
private File mDatabasesDir;
|
||||
@GuardedBy("mSync")
|
||||
@@ -2979,7 +2987,7 @@ class ContextImpl extends Context {
|
||||
// WindowContainer. We should detach from WindowContainer when the Context is finalized
|
||||
// if this Context is not a WindowContext. WindowContext finalization is handled in
|
||||
// WindowContext class.
|
||||
if (mToken instanceof WindowTokenClient && mContextType != CONTEXT_TYPE_WINDOW_CONTEXT) {
|
||||
if (mToken instanceof WindowTokenClient && mOwnsToken) {
|
||||
((WindowTokenClient) mToken).detachFromWindowContainerIfNeeded();
|
||||
}
|
||||
super.finalize();
|
||||
@@ -3010,6 +3018,7 @@ class ContextImpl extends Context {
|
||||
token.attachContext(context);
|
||||
token.attachToDisplayContent(displayId);
|
||||
context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI;
|
||||
context.mOwnsToken = true;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,10 @@ import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
|
||||
import static android.window.ConfigurationHelper.isDifferentDisplay;
|
||||
import static android.window.ConfigurationHelper.shouldUpdateResources;
|
||||
|
||||
import android.annotation.BinderThread;
|
||||
import android.annotation.MainThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.IWindowToken;
|
||||
import android.app.ResourcesManager;
|
||||
import android.content.Context;
|
||||
@@ -30,7 +31,9 @@ import android.inputmethodservice.AbstractInputMethodService;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Debug;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.IWindowManager;
|
||||
@@ -71,6 +74,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
|
||||
private boolean mAttachToWindowContainer;
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
/**
|
||||
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
|
||||
* can only attach one {@link Context}.
|
||||
@@ -132,7 +137,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
if (configuration == null) {
|
||||
return false;
|
||||
}
|
||||
onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */);
|
||||
mHandler.post(() -> onConfigurationChanged(configuration, displayId,
|
||||
false /* shouldReportConfigChange */));
|
||||
mAttachToWindowContainer = true;
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
@@ -179,9 +185,11 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
* @param newConfig the updated {@link Configuration}
|
||||
* @param newDisplayId the updated {@link android.view.Display} ID
|
||||
*/
|
||||
@BinderThread
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
|
||||
onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */);
|
||||
mHandler.post(() -> onConfigurationChanged(newConfig, newDisplayId,
|
||||
true /* shouldReportConfigChange */));
|
||||
}
|
||||
|
||||
// TODO(b/192048581): rewrite this method based on WindowContext and WindowProviderService
|
||||
@@ -192,6 +200,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
* Similar to {@link #onConfigurationChanged(Configuration, int)}, but adds a flag to control
|
||||
* whether to dispatch configuration update or not.
|
||||
*/
|
||||
@MainThread
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
|
||||
public void onConfigurationChanged(Configuration newConfig, int newDisplayId,
|
||||
boolean shouldReportConfigChange) {
|
||||
@@ -217,16 +226,14 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
|
||||
if (shouldReportConfigChange && context instanceof WindowContext) {
|
||||
final WindowContext windowContext = (WindowContext) context;
|
||||
ActivityThread.currentActivityThread().getHandler().post(
|
||||
() -> windowContext.dispatchConfigurationChanged(newConfig));
|
||||
windowContext.dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
final int diff = mConfiguration.diffPublicOnly(newConfig);
|
||||
if (shouldReportConfigChange && diff != 0
|
||||
&& context instanceof WindowProviderService) {
|
||||
final WindowProviderService windowProviderService = (WindowProviderService) context;
|
||||
ActivityThread.currentActivityThread().getHandler().post(
|
||||
() -> windowProviderService.onConfigurationChanged(newConfig));
|
||||
windowProviderService.onConfigurationChanged(newConfig);
|
||||
}
|
||||
freeTextLayoutCachesIfNeeded(diff);
|
||||
if (mShouldDumpConfigForIme) {
|
||||
@@ -248,12 +255,15 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void onWindowTokenRemoved() {
|
||||
final Context context = mContextRef.get();
|
||||
if (context != null) {
|
||||
context.destroy();
|
||||
mContextRef.clear();
|
||||
}
|
||||
mHandler.post(() -> {
|
||||
final Context context = mContextRef.get();
|
||||
if (context != null) {
|
||||
context.destroy();
|
||||
mContextRef.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,7 +783,7 @@ public class ZygoteInit {
|
||||
"--setuid=1000",
|
||||
"--setgid=1000",
|
||||
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
|
||||
+ "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011",
|
||||
+ "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011,3012",
|
||||
"--capabilities=" + capabilities + "," + capabilities,
|
||||
"--nice-name=system_server",
|
||||
"--runtime-args",
|
||||
|
||||
@@ -22,6 +22,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANI
|
||||
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
@@ -497,6 +498,23 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean shouldSendEventWhenTaskInvisible(@NonNull Task task,
|
||||
@NonNull PendingTaskFragmentEvent event) {
|
||||
final TaskFragmentOrganizerState state =
|
||||
mTaskFragmentOrganizerState.get(event.mTaskFragmentOrg.asBinder());
|
||||
final TaskFragmentInfo lastInfo = state.mLastSentTaskFragmentInfos.get(event.mTaskFragment);
|
||||
final TaskFragmentInfo info = event.mTaskFragment.getTaskFragmentInfo();
|
||||
// Send an info changed callback if this event is for the last activities to finish in a
|
||||
// Task so that the {@link TaskFragmentOrganizer} can delete this TaskFragment. Otherwise,
|
||||
// the Task may be removed before it becomes visible again to send this event because it no
|
||||
// longer has activities. As a result, the organizer will never get this info changed event
|
||||
// and will not delete the TaskFragment because the organizer thinks the TaskFragment still
|
||||
// has running activities.
|
||||
return event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED
|
||||
&& task.topRunningActivity() == null && lastInfo != null
|
||||
&& lastInfo.getRunningActivityCount() > 0 && info.getRunningActivityCount() == 0;
|
||||
}
|
||||
|
||||
void dispatchPendingEvents() {
|
||||
if (mAtmService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()
|
||||
|| mPendingTaskFragmentEvents.isEmpty()) {
|
||||
@@ -510,7 +528,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
final PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i);
|
||||
final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
|
||||
if (task != null && (task.lastActiveTime <= event.mDeferTime
|
||||
|| !isTaskVisible(task, visibleTasks, invisibleTasks))) {
|
||||
|| !(isTaskVisible(task, visibleTasks, invisibleTasks)
|
||||
|| shouldSendEventWhenTaskInvisible(task, event)))) {
|
||||
// Defer sending events to the TaskFragment until the host task is active again.
|
||||
event.mDeferTime = task.lastActiveTime;
|
||||
continue;
|
||||
|
||||
@@ -21,14 +21,17 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.server.wm.testing.Assert.assertThrows;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Intent;
|
||||
@@ -471,6 +474,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
|
||||
.setParentTask(task)
|
||||
.setOrganizer(mOrganizer)
|
||||
.setFragmentToken(mFragmentToken)
|
||||
.build();
|
||||
|
||||
// Mock the task to invisible
|
||||
@@ -485,4 +489,38 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
// Verifies that event was not sent
|
||||
verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a task fragment info changed event is still sent if the task is invisible only
|
||||
* when the info changed event is because of the last activity in a task finishing.
|
||||
*/
|
||||
@Test
|
||||
public void testLastPendingTaskFragmentInfoChangedEventOfInvisibleTaskSent() {
|
||||
// Create a TaskFragment with an activity, all within a parent task
|
||||
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
|
||||
.setOrganizer(mOrganizer)
|
||||
.setFragmentToken(mFragmentToken)
|
||||
.setCreateParentTask()
|
||||
.createActivityCount(1)
|
||||
.build();
|
||||
final Task parentTask = taskFragment.getTask();
|
||||
final ActivityRecord activity = taskFragment.getTopNonFinishingActivity();
|
||||
assertTrue(parentTask.shouldBeVisible(null));
|
||||
|
||||
// Dispatch pending info changed event from creating the activity
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
taskFragment.mTaskFragmentAppearedSent = true;
|
||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
|
||||
// Finish the activity and verify that the task is invisible
|
||||
activity.finishing = true;
|
||||
assertFalse(parentTask.shouldBeVisible(null));
|
||||
|
||||
// Verify the info changed callback still occurred despite the task being invisible
|
||||
reset(mOrganizer);
|
||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
verify(mOrganizer).onTaskFragmentInfoChanged(any());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user