[5/n] Camera Compat: Toasts explaining compat treatment

Add two toasts explaining compat treatment:
- after the system rotates the screen for camera compatibility
- when a camera view is started within the app that may not be able to display the camera preview correctly while in split screen.

Fix: 255939392
Test: atest WmTests:DisplayRotationCompatPolicyTests
Change-Id: I50d91601ac6e6fb90a626c5496aca60d454ff960
This commit is contained in:
Mariia Sandrikova
2023-01-28 04:14:34 +00:00
parent 958993bfe0
commit 46133ca915
4 changed files with 127 additions and 1 deletions

View File

@@ -2562,6 +2562,8 @@
<java-symbol type="string" name="zen_mode_default_weekends_name" />
<java-symbol type="string" name="zen_mode_default_events_name" />
<java-symbol type="string" name="zen_mode_default_every_night_name" />
<java-symbol type="string" name="display_rotation_camera_compat_toast_after_rotation" />
<java-symbol type="string" name="display_rotation_camera_compat_toast_in_split_screen" />
<java-symbol type="array" name="config_system_condition_providers" />
<java-symbol type="string" name="muted_by" />
<java-symbol type="string" name="zen_mode_alarm" />

View File

@@ -16,6 +16,8 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
@@ -34,6 +36,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.RefreshCallbackItem;
import android.app.servertransaction.ResumeActivityItem;
@@ -44,10 +47,13 @@ import android.os.Handler;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.UiThread;
import java.util.Map;
import java.util.Set;
@@ -232,6 +238,27 @@ final class DisplayRotationCompatPolicy {
activity.mLetterboxUiController.setIsRefreshAfterRotationRequested(false);
}
/**
* Notifies that animation in {@link ScreenAnimationRotation} has finished.
*
* <p>This class uses this signal as a trigger for notifying the user about forced rotation
* reason with the {@link Toast}.
*/
void onScreenRotationAnimationFinished() {
if (!isTreatmentEnabledForDisplay() || mCameraIdPackageBiMap.isEmpty()) {
return;
}
ActivityRecord topActivity = mDisplayContent.topRunningActivity(
/* considerKeyguardState= */ true);
if (topActivity == null
// Checking windowing mode on activity level because we don't want to
// show toast in case of activity embedding.
|| topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
return;
}
showToast(R.string.display_rotation_camera_compat_toast_after_rotation);
}
String getSummaryForDisplayRotationHistoryRecord() {
String summaryIfEnabled = "";
if (isTreatmentEnabledForDisplay()) {
@@ -334,7 +361,28 @@ final class DisplayRotationCompatPolicy {
}
mCameraIdPackageBiMap.put(packageName, cameraId);
}
updateOrientationWithWmLock();
ActivityRecord topActivity = mDisplayContent.topRunningActivity(
/* considerKeyguardState= */ true);
if (topActivity == null || topActivity.getTask() == null) {
return;
}
// Checking whether an activity in fullscreen rather than the task as this camera compat
// treatment doesn't cover activity embedding.
if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
updateOrientationWithWmLock();
return;
}
// Checking that the whole app is in multi-window mode as we shouldn't show toast
// for the activity embedding case.
if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
showToast(R.string.display_rotation_camera_compat_toast_in_split_screen);
}
}
@VisibleForTesting
void showToast(@StringRes int stringRes) {
UiThread.getHandler().post(
() -> Toast.makeText(mWmService.mContext, stringRes, Toast.LENGTH_LONG).show());
}
private synchronized void notifyCameraClosed(@NonNull String cameraId) {
@@ -396,6 +444,10 @@ final class DisplayRotationCompatPolicy {
private final Map<String, String> mPackageToCameraIdMap = new ArrayMap<>();
private final Map<String, String> mCameraIdToPackageMap = new ArrayMap<>();
boolean isEmpty() {
return mCameraIdToPackageMap.isEmpty();
}
void put(String packageName, String cameraId) {
// Always using the last connected camera ID for the package even for the concurrent
// camera use case since we can't guess which camera is more important anyway.

View File

@@ -800,6 +800,10 @@ class ScreenRotationAnimation {
if (mDisplayContent.getRotationAnimation() == ScreenRotationAnimation.this) {
// It also invokes kill().
mDisplayContent.setRotationAnimation(null);
if (mDisplayContent.mDisplayRotationCompatPolicy != null) {
mDisplayContent.mDisplayRotationCompatPolicy
.onScreenRotationAnimationFinished();
}
} else {
kill();
}

View File

@@ -16,6 +16,7 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
@@ -30,7 +31,9 @@ import static android.view.Surface.ROTATION_90;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertEquals;
@@ -58,6 +61,8 @@ import android.view.Surface.Rotation;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -127,6 +132,69 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase {
mDisplayContent, mMockHandler);
}
@Test
public void testOpenedCameraInSplitScreen_showToast() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
spyOn(mTask);
spyOn(mDisplayRotationCompatPolicy);
doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mActivity).getWindowingMode();
doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mTask).getWindowingMode();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
verify(mDisplayRotationCompatPolicy).showToast(
R.string.display_rotation_camera_compat_toast_in_split_screen);
}
@Test
public void testOnScreenRotationAnimationFinished_treatmentNotEnabled_doNotShowToast() {
when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled(
/* checkDeviceConfig */ anyBoolean()))
.thenReturn(false);
spyOn(mDisplayRotationCompatPolicy);
mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
verify(mDisplayRotationCompatPolicy, never()).showToast(
R.string.display_rotation_camera_compat_toast_after_rotation);
}
@Test
public void testOnScreenRotationAnimationFinished_noOpenCamera_doNotShowToast() {
spyOn(mDisplayRotationCompatPolicy);
mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
verify(mDisplayRotationCompatPolicy, never()).showToast(
R.string.display_rotation_camera_compat_toast_after_rotation);
}
@Test
public void testOnScreenRotationAnimationFinished_notFullscreen_doNotShowToast() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mActivity).getWindowingMode();
spyOn(mDisplayRotationCompatPolicy);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
verify(mDisplayRotationCompatPolicy, never()).showToast(
R.string.display_rotation_camera_compat_toast_after_rotation);
}
@Test
public void testOnScreenRotationAnimationFinished_showToast() {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
spyOn(mDisplayRotationCompatPolicy);
mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
verify(mDisplayRotationCompatPolicy).showToast(
R.string.display_rotation_camera_compat_toast_after_rotation);
}
@Test
public void testTreatmentNotEnabled_noForceRotationOrRefresh() throws Exception {
when(mLetterboxConfiguration.isCameraCompatTreatmentEnabled(