Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 46133ca9 authored by Mariia Sandrikova's avatar Mariia Sandrikova
Browse files

[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
parent 958993bf
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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" />
+53 −1
Original line number Diff line number Diff line
@@ -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);
        }
        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.
+4 −0
Original line number Diff line number Diff line
@@ -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();
                }
+68 −0
Original line number Diff line number Diff line
@@ -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(