/*
* Copyright 2021 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 androidx.camera.camera2.internal.compat.quirk;
import android.os.Build;
import android.util.Range;
import android.util.Size;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.camera.core.impl.Quirk;
import androidx.camera.core.impl.SurfaceConfig;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* Quirk that requires specific resolutions as the workaround.
*
* <p>QuirkSummary
* Bug Id: 190203334
* Description: The symptom of these devices is that the output of one or many streams,
* including PRIV, JPEG and/or YUV, can have an unintended 25% crop, and the
* cropped image is stretched to fill the Surface, which results in a distorted
* output. The streams can also have an unintended 25% double crop, in which
* case the stretched image will not be distorted, but the FOV is smaller than
* it should be. The behavior is inconsistent in a way that the extra cropping
* depends on the resolution of the streams. The existence of the issue also
* depends on API level and/or build number. See discussion in
* go/samsung-camera-distortion.
* Device(s): Samsung Galaxy Tab A (2016) SM-T580, Samsung Galaxy J7 (2016) SM-J710MN,
* Samsung Galaxy A3 (2017) SM-A320FL, Samsung Galaxy J5 Prime SM-G570M,
* Samsung Galaxy J7 Prime SM-G610F, Samsung Galaxy J7 Prime SM-G610M
*/
@RequiresApi(21)
public class ExtraCroppingQuirk implements Quirk {
private static final Map<String, Range<Integer>> SAMSUNG_DISTORTION_MODELS_TO_API_LEVEL_MAP =
new HashMap<>();
static {
SAMSUNG_DISTORTION_MODELS_TO_API_LEVEL_MAP.put("SM-T580", null);
SAMSUNG_DISTORTION_MODELS_TO_API_LEVEL_MAP.put("SM-J710MN", new Range<>(21, 26));
SAMSUNG_DISTORTION_MODELS_TO_API_LEVEL_MAP.put("SM-A320FL", null);
SAMSUNG_DISTORTION_MODELS_TO_API_LEVEL_MAP.put("SM-G570M", null);
SAMSUNG_DISTORTION_MODELS_TO_API_LEVEL_MAP.put("SM-G610F", null);
SAMSUNG_DISTORTION_MODELS_TO_API_LEVEL_MAP.put("SM-G610M", new Range<>(21, 26));
}
static boolean load() {
return isSamsungDistortion();
}
/**
* Get a verified resolution that is guaranteed to work.
*
* <p> The selected resolution have been manually tested by CameraX team. It is known to
* work for the given device/stream.
*
* @return null if no resolution provided, in which case the calling code should fallback to
* user provided target resolution.
*/
@Nullable
public Size getVerifiedResolution(@NonNull SurfaceConfig.ConfigType configType) {
if (isSamsungDistortion()) {
// The following resolutions are needed for both the front and the back camera.
switch (configType) {
case PRIV:
return new Size(1920, 1080);
case YUV:
return new Size(1280, 720);
case JPEG:
return new Size(3264, 1836);
default:
return null;
}
}
return null;
}
/**
* Checks for device model with Samsung output distortion bug (b/190203334).
*/
private static boolean isSamsungDistortion() {
boolean isDeviceModelContained = "samsung".equalsIgnoreCase(Build.BRAND)
&& SAMSUNG_DISTORTION_MODELS_TO_API_LEVEL_MAP.containsKey(
Build.MODEL.toUpperCase(Locale.US));
if (!isDeviceModelContained) {
return false;
}
Range<Integer> apiLevelRange =
SAMSUNG_DISTORTION_MODELS_TO_API_LEVEL_MAP.get(Build.MODEL.toUpperCase(Locale.US));
return apiLevelRange == null ? true : apiLevelRange.contains(Build.VERSION.SDK_INT);
}
}