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

Commit 147989ff authored by Mina Granic's avatar Mina Granic
Browse files

Extract `CameraIdPackageNameBiMapping` in a separate class.

This allows the mapping to be reused in other camera compat classes.

Bug: 314960895
Test: atest WmTests:DisplayRotationCompatPolicyTests
Test: atest WmTests:CameraIdPackageNameBiMappingTests
Change-Id: I2f7c007b53d697eb1b49b5e428297d3420faafbc
parent a3971d66
Loading
Loading
Loading
Loading
+78 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArrayMap;

import java.util.Map;

/**
 * Bidirectional mapping (1:1) for the currently active cameraId and the app package that opened it.
 *
 * <p>This class is not thread-safe.
 */
final class CameraIdPackageNameBiMapping {
    private final Map<String, String> mPackageToCameraIdMap = new ArrayMap<>();
    private final Map<String, String> mCameraIdToPackageMap = new ArrayMap<>();

    boolean isEmpty() {
        return mCameraIdToPackageMap.isEmpty();
    }

    void put(@NonNull String packageName, @NonNull 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.
        removePackageName(packageName);
        removeCameraId(cameraId);
        mPackageToCameraIdMap.put(packageName, cameraId);
        mCameraIdToPackageMap.put(cameraId, packageName);
    }

    boolean containsPackageName(@NonNull String packageName) {
        return mPackageToCameraIdMap.containsKey(packageName);
    }

    @Nullable
    String getCameraId(@NonNull String packageName) {
        return mPackageToCameraIdMap.get(packageName);
    }

    void removeCameraId(@NonNull String cameraId) {
        final String packageName = mCameraIdToPackageMap.get(cameraId);
        if (packageName == null) {
            return;
        }
        mPackageToCameraIdMap.remove(packageName, cameraId);
        mCameraIdToPackageMap.remove(cameraId, packageName);
    }

    @NonNull
    String getSummaryForDisplayRotationHistoryRecord() {
        return "{ mPackageToCameraIdMap=" + mPackageToCameraIdMap + " }";
    }

    private void removePackageName(@NonNull String packageName) {
        String cameraId = mPackageToCameraIdMap.get(packageName);
        if (cameraId == null) {
            return;
        }
        mPackageToCameraIdMap.remove(packageName, cameraId);
        mCameraIdToPackageMap.remove(cameraId, packageName);
    }
}
+2 −53
Original line number Original line Diff line number Diff line
@@ -46,7 +46,6 @@ import android.content.res.Configuration;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraManager;
import android.os.Handler;
import android.os.Handler;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ArraySet;
import android.widget.Toast;
import android.widget.Toast;


@@ -56,7 +55,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.UiThread;
import com.android.server.UiThread;


import java.util.Map;
import java.util.Set;
import java.util.Set;


/**
/**
@@ -100,7 +98,8 @@ final class DisplayRotationCompatPolicy {
    // camera id by a package name when determining rotation; 2) get a package name by a camera id
    // camera id by a package name when determining rotation; 2) get a package name by a camera id
    // when camera connection is closed and we need to clean up our records.
    // when camera connection is closed and we need to clean up our records.
    @GuardedBy("this")
    @GuardedBy("this")
    private final CameraIdPackageNameBiMap mCameraIdPackageBiMap = new CameraIdPackageNameBiMap();
    private final CameraIdPackageNameBiMapping mCameraIdPackageBiMap =
            new CameraIdPackageNameBiMapping();
    @GuardedBy("this")
    @GuardedBy("this")
    private final Set<String> mScheduledToBeRemovedCameraIdSet = new ArraySet<>();
    private final Set<String> mScheduledToBeRemovedCameraIdSet = new ArraySet<>();
    @GuardedBy("this")
    @GuardedBy("this")
@@ -516,54 +515,4 @@ final class DisplayRotationCompatPolicy {
        }
        }
        return topActivity.mLetterboxUiController.isRefreshAfterRotationRequested();
        return topActivity.mLetterboxUiController.isRefreshAfterRotationRequested();
    }
    }

    private static class CameraIdPackageNameBiMap {

        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.
            removePackageName(packageName);
            removeCameraId(cameraId);
            mPackageToCameraIdMap.put(packageName, cameraId);
            mCameraIdToPackageMap.put(cameraId, packageName);
        }

        boolean containsPackageName(String packageName) {
            return mPackageToCameraIdMap.containsKey(packageName);
        }

        @Nullable
        String getCameraId(String packageName) {
            return mPackageToCameraIdMap.get(packageName);
        }

        void removeCameraId(String cameraId) {
            String packageName = mCameraIdToPackageMap.get(cameraId);
            if (packageName == null) {
                return;
            }
            mPackageToCameraIdMap.remove(packageName, cameraId);
            mCameraIdToPackageMap.remove(cameraId, packageName);
        }

        String getSummaryForDisplayRotationHistoryRecord() {
            return "{ mPackageToCameraIdMap=" + mPackageToCameraIdMap + " }";
        }

        private void removePackageName(String packageName) {
            String cameraId = mPackageToCameraIdMap.get(packageName);
            if (cameraId == null) {
                return;
            }
            mPackageToCameraIdMap.remove(packageName, cameraId);
            mCameraIdToPackageMap.remove(cameraId, packageName);
        }
    }
}
}
+107 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import android.platform.test.annotations.Presubmit;

import androidx.test.filters.SmallTest;

import org.junit.Before;
import org.junit.Test;

/**
 * Tests for {@link CameraIdPackageNameBiMapping}.
 *
 * Build/Install/Run:
 * atest WmTests:CameraIdPackageNameBiMapTests
 */
@SmallTest
@Presubmit
public class CameraIdPackageNameBiMappingTests {
    private CameraIdPackageNameBiMapping mMapping;

    private static final String PACKAGE_1 = "PACKAGE_1";
    private static final String PACKAGE_2 = "PACKAGE_2";
    private static final String CAMERA_ID_1 = "1234";
    private static final String CAMERA_ID_2 = "5678";

    @Before
    public void setUp() {
        mMapping = new CameraIdPackageNameBiMapping();
    }

    @Test
    public void mappingEmptyAtStart() {
        assertTrue(mMapping.isEmpty());
    }

    @Test
    public void addPackageAndId_containsPackage() {
        mMapping.put(PACKAGE_1, CAMERA_ID_1);
        assertTrue(mMapping.containsPackageName(PACKAGE_1));
    }

    @Test
    public void addTwoPackagesAndId_containsPackages() {
        mMapping.put(PACKAGE_1, CAMERA_ID_1);
        mMapping.put(PACKAGE_2, CAMERA_ID_2);
        assertTrue(mMapping.containsPackageName(PACKAGE_1));
        assertTrue(mMapping.containsPackageName(PACKAGE_2));
    }

    @Test
    public void addPackageAndId_mapContainsPackageAndId() {
        mMapping.put(PACKAGE_1, CAMERA_ID_1);
        assertEquals(CAMERA_ID_1, mMapping.getCameraId(PACKAGE_1));
    }

    @Test
    public void changeCameraId_newestCameraId() {
        mMapping.put(PACKAGE_1, CAMERA_ID_1);
        mMapping.put(PACKAGE_1, CAMERA_ID_2);
        assertEquals(CAMERA_ID_2, mMapping.getCameraId(PACKAGE_1));
    }

    @Test
    public void changePackage_newestPackage() {
        mMapping.put(PACKAGE_1, CAMERA_ID_1);
        mMapping.put(PACKAGE_2, CAMERA_ID_1);
        assertFalse(mMapping.containsPackageName(PACKAGE_1));
        assertTrue(mMapping.containsPackageName(PACKAGE_2));
        assertEquals(CAMERA_ID_1, mMapping.getCameraId(PACKAGE_2));
    }

    @Test
    public void addAndRemoveCameraId_containsOtherPackage() {
        mMapping.put(PACKAGE_1, CAMERA_ID_1);
        mMapping.put(PACKAGE_2, CAMERA_ID_2);
        mMapping.removeCameraId(CAMERA_ID_1);
        assertFalse(mMapping.containsPackageName(PACKAGE_1));
        assertTrue(mMapping.containsPackageName(PACKAGE_2));
    }

    @Test
    public void addAndRemoveOnlyCameraId_empty() {
        mMapping.put(PACKAGE_1, CAMERA_ID_1);
        mMapping.removeCameraId(CAMERA_ID_1);
        assertTrue(mMapping.isEmpty());
    }
}