Notify when task changes requested orientation.

This allows listener know task's orientation request change before
handling display rotation through IDisplayWindowRotationController if
they can register a local TaskStackListener.

Bug: 150409355
Test: atest WmTests:TaskStackChangedListenerTest#testNotifyTaskRequestedOrientationChanged
Change-Id: Id7bfc3e63329ce26d454b7e9c143e084e04dd365
This commit is contained in:
Garfield Tan
2020-03-03 16:07:07 -08:00
parent b8ad491e6d
commit afa0de8a91
7 changed files with 105 additions and 0 deletions

View File

@@ -205,4 +205,15 @@ oneway interface ITaskStackListener {
* @param {@code true} if the task got focus, {@code false} if it lost it.
*/
void onTaskFocusChanged(int taskId, boolean focused);
/**
* Called when a task changes its requested orientation. It is different from {@link
* #onActivityRequestedOrientationChanged(int, int)} in the sense that this method is called
* when a task changes requested orientation due to activity launch, dimiss or reparenting.
*
* @param taskId id of the task.
* @param requestedOrientation the new requested orientation of this task as screen orientations
* in {@link android.content.pm.ActivityInfo}.
*/
void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation);
}

View File

@@ -195,4 +195,8 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub {
@Override
public void onTaskFocusChanged(int taskId, boolean focused) {
}
@Override
public void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
}
}

View File

@@ -1392,6 +1392,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final WindowContainer orientationSource = getLastOrientationSource();
final ActivityRecord r =
orientationSource != null ? orientationSource.asActivityRecord() : null;
if (r != null && r.getTask() != null
&& orientation != r.getTask().mLastReportedRequestedOrientation) {
final Task task = r.getTask();
task.mLastReportedRequestedOrientation = orientation;
mAtmService.getTaskChangeNotificationController()
.notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
}
// Currently there is no use case from non-activity.
if (r != null && handleTopActivityLaunchingInDifferentOrientation(r)) {
// Display orientation should be deferred until the top fixed rotation is finished.

View File

@@ -368,6 +368,14 @@ class Task extends WindowContainer<WindowContainer> {
@Surface.Rotation
private int mRotation;
/**
* Last requested orientation reported to DisplayContent. This is different from {@link
* #mOrientation} in the sense that this takes activities' requested orientation into
* account. Start with {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} so that we don't need
* to notify for activities that don't specify any orientation.
*/
int mLastReportedRequestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
// For comparison with DisplayContent bounds.
private Rect mTmpRect = new Rect();
// For handling display rotations.

View File

@@ -60,6 +60,7 @@ class TaskChangeNotificationController {
private static final int NOTIFY_SINGLE_TASK_DISPLAY_EMPTY = 25;
private static final int NOTIFY_TASK_LIST_FROZEN_UNFROZEN_MSG = 26;
private static final int NOTIFY_TASK_FOCUS_CHANGED_MSG = 27;
private static final int NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG = 28;
// Delay in notifying task stack change listeners (in millis)
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -178,6 +179,10 @@ class TaskChangeNotificationController {
l.onTaskFocusChanged(m.arg1, m.arg2 != 0);
};
private final TaskStackConsumer mNotifyTaskRequestedOrientationChanged = (l, m) -> {
l.onTaskRequestedOrientationChanged(m.arg1, m.arg2);
};
@FunctionalInterface
public interface TaskStackConsumer {
void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -269,6 +274,9 @@ class TaskChangeNotificationController {
case NOTIFY_TASK_FOCUS_CHANGED_MSG:
forAllRemoteListeners(mNotifyTaskFocusChanged, msg);
break;
case NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG:
forAllRemoteListeners(mNotifyTaskRequestedOrientationChanged, msg);
break;
}
if (msg.obj instanceof SomeArgs) {
((SomeArgs) msg.obj).recycle();
@@ -558,4 +566,12 @@ class TaskChangeNotificationController {
forAllLocalListeners(mNotifyTaskFocusChanged, msg);
msg.sendToTarget();
}
/** @see android.app.ITaskStackListener#onTaskRequestedOrientationChanged(int, int) */
void notifyTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
final Message msg = mHandler.obtainMessage(NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG,
taskId, requestedOrientation);
forAllLocalListeners(mNotifyTaskRequestedOrientationChanged, msg);
msg.sendToTarget();
}
}

View File

@@ -54,6 +54,10 @@
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityViewTestActivity" />
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityInActivityView"
android:resizeableActivity="true" />
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$LandscapeActivity"
android:screenOrientation="sensorLandscape"
android:showWhenLocked="true"
android:turnScreenOn="true" />
<activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
android:showWhenLocked="true" />
</application>

View File

@@ -22,6 +22,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.app.Activity;
@@ -41,6 +42,7 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.support.test.uiautomator.UiDevice;
import android.text.TextUtils;
@@ -56,8 +58,10 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
/**
* Build/Install/Run:
@@ -391,6 +395,42 @@ public class TaskStackChangedListenerTest {
}
};
@Presubmit
@FlakyTest(bugId = 150409355)
@Test
public void testNotifyTaskRequestedOrientationChanged() throws Exception {
final ArrayBlockingQueue<int[]> taskIdAndOrientationQueue = new ArrayBlockingQueue<>(10);
registerTaskStackChangedListener(new TaskStackListener() {
@Override
public void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
int[] taskIdAndOrientation = new int[2];
taskIdAndOrientation[0] = taskId;
taskIdAndOrientation[1] = requestedOrientation;
taskIdAndOrientationQueue.offer(taskIdAndOrientation);
}
});
final LandscapeActivity activity =
(LandscapeActivity) startTestActivity(LandscapeActivity.class);
int[] taskIdAndOrientation = waitForResult(taskIdAndOrientationQueue,
candidate -> candidate[0] == activity.getTaskId());
assertNotNull(taskIdAndOrientation);
assertEquals(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, taskIdAndOrientation[1]);
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
taskIdAndOrientation = waitForResult(taskIdAndOrientationQueue,
candidate -> candidate[0] == activity.getTaskId());
assertNotNull(taskIdAndOrientation);
assertEquals(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, taskIdAndOrientation[1]);
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
taskIdAndOrientation = waitForResult(taskIdAndOrientationQueue,
candidate -> candidate[0] == activity.getTaskId());
assertNotNull(taskIdAndOrientation);
assertEquals(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, taskIdAndOrientation[1]);
}
/**
* Starts the provided activity and returns the started instance.
*/
@@ -432,6 +472,19 @@ public class TaskStackChangedListenerTest {
}
}
private <T> T waitForResult(ArrayBlockingQueue<T> queue, Predicate<T> predicate) {
try {
final long timeout = SystemClock.uptimeMillis() + TimeUnit.SECONDS.toMillis(15);
T result;
do {
result = queue.poll(timeout - SystemClock.uptimeMillis(), TimeUnit.MILLISECONDS);
} while (result != null && !predicate.test(result));
return result;
} catch (InterruptedException e) {
return null;
}
}
public static class TestActivity extends Activity {
boolean mIsResumed = false;
@@ -563,4 +616,6 @@ public class TaskStackChangedListenerTest {
// Activity that has {@link android.R.attr#resizeableActivity} attribute set to {@code true}
public static class ActivityInActivityView extends TestActivity {}
public static class LandscapeActivity extends TestActivity {}
}