1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.camera2.params; 18 19 import android.annotation.LongDef; 20 import android.hardware.camera2.CameraCharacteristics; 21 import android.hardware.camera2.utils.HashCodeHelpers; 22 23 import java.lang.annotation.Retention; 24 import java.lang.annotation.RetentionPolicy; 25 import java.util.Arrays; 26 import java.util.HashMap; 27 import java.util.Objects; 28 29 /** 30 * Immutable class that maps the device fold state to sensor orientation. 31 * 32 * <p>Some {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA logical} 33 * cameras on foldables can include physical sensors with different sensor orientation 34 * values. As a result, the values of the logical camera device can potentially change depending 35 * on the device fold state.</p> 36 * 37 * <p>The device fold state to sensor orientation map will contain information about the 38 * respective logical camera sensor orientation given a device state. Clients 39 * can query the mapping for all possible supported folded states. 40 * 41 * @see CameraCharacteristics#SENSOR_ORIENTATION 42 */ 43 public final class DeviceStateSensorOrientationMap { 44 /** 45 * Needs to be kept in sync with the HIDL/AIDL DeviceState 46 */ 47 48 /** 49 * The device is in its normal physical configuration. This is the default if the 50 * device does not support multiple different states. 51 */ 52 public static final long NORMAL = 0; 53 54 /** 55 * The device is folded. If not set, the device is unfolded or does not 56 * support folding. 57 * 58 * The exact point when this status change happens during the folding 59 * operation is device-specific. 60 */ 61 public static final long FOLDED = 1 << 2; 62 63 /** @hide */ 64 @Retention(RetentionPolicy.SOURCE) 65 @LongDef(prefix = {"DEVICE_STATE"}, value = 66 {NORMAL, 67 FOLDED }) 68 public @interface DeviceState {}; 69 70 private final HashMap<Long, Integer> mDeviceStateOrientationMap = new HashMap<>(); 71 72 /** 73 * Create a new immutable DeviceStateOrientationMap instance. 74 * 75 * <p>This constructor takes over the array; do not write to the array afterwards.</p> 76 * 77 * @param elements 78 * An array of elements describing the map 79 * 80 * @throws IllegalArgumentException 81 * if the {@code elements} array length is invalid, not divisible by 2 or contains 82 * invalid element values 83 * @throws NullPointerException 84 * if {@code elements} is {@code null} 85 * 86 * @hide 87 */ DeviceStateSensorOrientationMap(final long[] elements)88 public DeviceStateSensorOrientationMap(final long[] elements) { 89 mElements = Objects.requireNonNull(elements, "elements must not be null"); 90 if ((elements.length % 2) != 0) { 91 throw new IllegalArgumentException("Device state sensor orientation map length " + 92 elements.length + " is not even!"); 93 } 94 95 for (int i = 0; i < elements.length; i += 2) { 96 if ((elements[i+1] % 90) != 0) { 97 throw new IllegalArgumentException("Sensor orientation not divisible by 90: " + 98 elements[i+1]); 99 } 100 101 mDeviceStateOrientationMap.put(elements[i], Math.toIntExact(elements[i + 1])); 102 } 103 } 104 105 /** 106 * Return the logical camera sensor orientation given a specific device fold state. 107 * 108 * @param deviceState Device fold state 109 * 110 * @return Valid {@link android.hardware.camera2.CameraCharacteristics#SENSOR_ORIENTATION} for 111 * any supported device fold state 112 * 113 * @throws IllegalArgumentException if the given device state is invalid 114 */ getSensorOrientation(@eviceState long deviceState)115 public int getSensorOrientation(@DeviceState long deviceState) { 116 if (!mDeviceStateOrientationMap.containsKey(deviceState)) { 117 throw new IllegalArgumentException("Invalid device state: " + deviceState); 118 } 119 120 return mDeviceStateOrientationMap.get(deviceState); 121 } 122 123 /** 124 * Check if this DeviceStateSensorOrientationMap is equal to another 125 * DeviceStateSensorOrientationMap. 126 * 127 * <p>Two device state orientation maps are equal if and only if all of their elements are 128 * {@link Object#equals equal}.</p> 129 * 130 * @return {@code true} if the objects were equal, {@code false} otherwise 131 */ 132 @Override equals(final Object obj)133 public boolean equals(final Object obj) { 134 if (obj == null) { 135 return false; 136 } 137 if (this == obj) { 138 return true; 139 } 140 if (obj instanceof DeviceStateSensorOrientationMap) { 141 final DeviceStateSensorOrientationMap other = (DeviceStateSensorOrientationMap) obj; 142 return Arrays.equals(mElements, other.mElements); 143 } 144 return false; 145 } 146 147 /** 148 * {@inheritDoc} 149 */ 150 @Override hashCode()151 public int hashCode() { 152 return HashCodeHelpers.hashCodeGeneric(mElements); 153 } 154 155 private final long[] mElements; 156 } 157