Fix foldable camera cutout overrides
This commit is contained in:
+85
@@ -0,0 +1,85 @@
|
||||
package se.ajpanton.statusbartweak.runtime.render;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import se.ajpanton.statusbartweak.shell.settings.ClockCameraTypeSupport;
|
||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||
|
||||
final class EffectiveCutoutSupport {
|
||||
private static final WeakHashMap<View, CameraTypeCache> CAMERA_TYPE_BY_ROOT = new WeakHashMap<>();
|
||||
|
||||
private EffectiveCutoutSupport() {
|
||||
}
|
||||
|
||||
static Rect middleCutout(View root, SbtSettings settings, boolean ignoreUnderDisplayCamera) {
|
||||
Rect cutout = ViewGeometry.middleCutout(root);
|
||||
if (cutout == null || !ignoreUnderDisplayCamera) {
|
||||
return cutout;
|
||||
}
|
||||
String effectiveType = effectiveCameraType(root, cutout, settings);
|
||||
return ClockCameraTypeSupport.TYPE_UDC.equals(effectiveType) ? null : cutout;
|
||||
}
|
||||
|
||||
static Rect layoutMiddleCutout(View root, SbtSettings settings) {
|
||||
return middleCutout(
|
||||
root,
|
||||
settings,
|
||||
settings != null && settings.layoutIgnoreUnderDisplayCameras);
|
||||
}
|
||||
|
||||
static Rect clockMiddleCutout(View root, SbtSettings settings) {
|
||||
return middleCutout(
|
||||
root,
|
||||
settings,
|
||||
settings != null && settings.clockIgnoreUnderDisplayCameras);
|
||||
}
|
||||
|
||||
private static String effectiveCameraType(View root, Rect cutout, SbtSettings settings) {
|
||||
int signature = cameraTypeSignature(root, cutout, settings);
|
||||
CameraTypeCache cached = CAMERA_TYPE_BY_ROOT.get(root);
|
||||
if (cached != null && cached.signature == signature) {
|
||||
return cached.effectiveType;
|
||||
}
|
||||
WindowInsets insets = root != null ? root.getRootWindowInsets() : null;
|
||||
DisplayCutout displayCutout = insets != null ? insets.getDisplayCutout() : null;
|
||||
ClockCameraTypeSupport.CameraInfo cameraInfo =
|
||||
ClockCameraTypeSupport.resolveCameraInfo(root, displayCutout, settings);
|
||||
String effectiveType = cameraInfo.effectiveType;
|
||||
if (root != null) {
|
||||
SbtSettings.setClockCameraDebugState(
|
||||
root.getContext(),
|
||||
cameraInfo.cameraId,
|
||||
cameraInfo.automaticType,
|
||||
cameraInfo.effectiveType);
|
||||
}
|
||||
CAMERA_TYPE_BY_ROOT.put(root, new CameraTypeCache(signature, effectiveType));
|
||||
return effectiveType;
|
||||
}
|
||||
|
||||
private static int cameraTypeSignature(View root, Rect cutout, SbtSettings settings) {
|
||||
return Objects.hash(
|
||||
root != null ? root.getWidth() : 0,
|
||||
root != null ? root.getHeight() : 0,
|
||||
cutout != null ? cutout.left : 0,
|
||||
cutout != null ? cutout.top : 0,
|
||||
cutout != null ? cutout.right : 0,
|
||||
cutout != null ? cutout.bottom : 0,
|
||||
settings != null ? settings.clockCameraTypeOverrides : null);
|
||||
}
|
||||
|
||||
private static final class CameraTypeCache {
|
||||
final int signature;
|
||||
final String effectiveType;
|
||||
|
||||
CameraTypeCache(int signature, String effectiveType) {
|
||||
this.signature = signature;
|
||||
this.effectiveType = effectiveType;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-5
@@ -96,7 +96,7 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
root,
|
||||
settings,
|
||||
scene,
|
||||
ViewGeometry.middleCutout(root),
|
||||
EffectiveCutoutSupport.layoutMiddleCutout(root, settings),
|
||||
anchors,
|
||||
previousIcons);
|
||||
LayoutInputSignature previousSignature = lastLayoutSignatureByRoot.get(root);
|
||||
@@ -154,12 +154,12 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
root,
|
||||
currentClockLayout,
|
||||
settings,
|
||||
UnlockedLayoutPlanner.cutoutBounds(ViewGeometry.middleCutout(root), settings.clockMiddleCutoutGapPx));
|
||||
clockCutoutBounds(root, settings));
|
||||
ClockPlacement textPlacement = clockTextPlacementForPrevious(
|
||||
root,
|
||||
currentClockLayout,
|
||||
settings,
|
||||
UnlockedLayoutPlanner.cutoutBounds(ViewGeometry.middleCutout(root), settings.clockMiddleCutoutGapPx),
|
||||
clockCutoutBounds(root, settings),
|
||||
previousPlan != null ? previousPlan.clockPlacement : null);
|
||||
ClockPlacement updatedClock = clockPlacementWithUpdatedText(
|
||||
previousPlan != null ? previousPlan.clockPlacement : null,
|
||||
@@ -193,7 +193,7 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
root,
|
||||
currentClockLayout,
|
||||
settings,
|
||||
UnlockedLayoutPlanner.cutoutBounds(ViewGeometry.middleCutout(root), settings.clockMiddleCutoutGapPx));
|
||||
clockCutoutBounds(root, settings));
|
||||
}
|
||||
if (scene.isLockscreen() && clockEnabledForScene(settings, scene) && currentClockLayout == null) {
|
||||
clearLockscreenHosts(clockHost, carrierHost, chipHost, statusHost, notificationHost);
|
||||
@@ -724,7 +724,13 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
anchors,
|
||||
settings,
|
||||
scene,
|
||||
UnlockedLayoutPlanner.cutoutBounds(ViewGeometry.middleCutout(root), settings != null ? settings.clockMiddleCutoutGapPx : 0));
|
||||
clockCutoutBounds(root, settings));
|
||||
}
|
||||
|
||||
private Bounds clockCutoutBounds(View root, SbtSettings settings) {
|
||||
return UnlockedLayoutPlanner.cutoutBounds(
|
||||
EffectiveCutoutSupport.clockMiddleCutout(root, settings),
|
||||
settings != null ? settings.clockMiddleCutoutGapPx : 0);
|
||||
}
|
||||
|
||||
private ClockLayout buildClockLayout(
|
||||
|
||||
+6
-5
@@ -68,13 +68,14 @@ final class UnlockedLayoutPlanner {
|
||||
aodInitialStatusbarHeightByRoot.remove(root);
|
||||
}
|
||||
ArrayList<UnlockedLayoutBand> bands = new ArrayList<>();
|
||||
Rect cutout = ViewGeometry.middleCutout(root);
|
||||
Rect layoutCutout = EffectiveCutoutSupport.layoutMiddleCutout(root, settings);
|
||||
Rect clockCutout = EffectiveCutoutSupport.clockMiddleCutout(root, settings);
|
||||
Bounds layoutCutoutBounds = scene != null && scene.isAod()
|
||||
? aodCutoutBounds(root, cutout, settings.layoutPaddingCutoutPx)
|
||||
: cutoutBounds(cutout, settings.layoutPaddingCutoutPx);
|
||||
? aodCutoutBounds(root, layoutCutout, settings.layoutPaddingCutoutPx)
|
||||
: cutoutBounds(layoutCutout, settings.layoutPaddingCutoutPx);
|
||||
Bounds clockCutoutBounds = scene != null && scene.isAod()
|
||||
? aodCutoutBounds(root, cutout, settings.clockMiddleCutoutGapPx)
|
||||
: cutoutBounds(cutout, settings.clockMiddleCutoutGapPx);
|
||||
? aodCutoutBounds(root, clockCutout, settings.clockMiddleCutoutGapPx)
|
||||
: cutoutBounds(clockCutout, settings.clockMiddleCutoutGapPx);
|
||||
Bounds aodStatusAnchorBounds = scene != null && scene.isAod()
|
||||
? aodStatusAnchorBounds(root, anchors, scene)
|
||||
: null;
|
||||
|
||||
+1
@@ -1626,6 +1626,7 @@ final class UnlockedStockSourceCollector {
|
||||
settings.clockCustomFormatEnabled,
|
||||
settings.clockCustomFormat,
|
||||
settings.clockIgnoreUnderDisplayCameras,
|
||||
settings.clockCameraTypeOverrides,
|
||||
settings.layoutPaddingCutoutPx,
|
||||
settings.layoutPaddingLeftPx,
|
||||
settings.layoutPaddingRightPx,
|
||||
|
||||
+29
-8
@@ -29,6 +29,9 @@ public final class ClockCameraTypeSupport {
|
||||
public static final class CameraInfo {
|
||||
public int semDisplayDeviceType = Integer.MIN_VALUE;
|
||||
public int fillUdcDisplayCutout = Integer.MIN_VALUE;
|
||||
public int rootWidth = Integer.MIN_VALUE;
|
||||
public int rootHeight = Integer.MIN_VALUE;
|
||||
public int rotation = Integer.MIN_VALUE;
|
||||
public boolean isUdcMainDisplay;
|
||||
public String cutoutType;
|
||||
public String cutoutString;
|
||||
@@ -59,8 +62,15 @@ public final class ClockCameraTypeSupport {
|
||||
: "blocking cutout";
|
||||
}
|
||||
|
||||
public static String buildCameraId(int semDisplayDeviceType, String cutoutType, String cutoutString) {
|
||||
private static String buildCameraId(int semDisplayDeviceType,
|
||||
int rootWidth,
|
||||
int rootHeight,
|
||||
int rotation,
|
||||
String cutoutType,
|
||||
String cutoutString) {
|
||||
String descriptor = semDisplayDeviceType + "|"
|
||||
+ rootWidth + "x" + rootHeight + "|"
|
||||
+ rotation + "|"
|
||||
+ safe(cutoutType) + "|"
|
||||
+ safe(cutoutString);
|
||||
return "cam_" + shortSha1(descriptor);
|
||||
@@ -78,6 +88,20 @@ public final class ClockCameraTypeSupport {
|
||||
finalizeCameraInfo(info, settings);
|
||||
return info;
|
||||
}
|
||||
Display display = root.getDisplay();
|
||||
if (display != null) {
|
||||
info.rotation = display.getRotation();
|
||||
}
|
||||
int width = root.getWidth();
|
||||
if (width <= 0 && root.getRootView() != null) {
|
||||
width = root.getRootView().getWidth();
|
||||
}
|
||||
info.rootWidth = width;
|
||||
int height = root.getHeight();
|
||||
if (height <= 0 && root.getRootView() != null) {
|
||||
height = root.getRootView().getHeight();
|
||||
}
|
||||
info.rootHeight = height;
|
||||
info.semDisplayDeviceType = readSemDisplayDeviceType(context);
|
||||
info.fillUdcDisplayCutout = readGlobalInt(context, "fill_udc_display_cutout");
|
||||
Object displayLifecycle = resolveDisplayLifecycle(context);
|
||||
@@ -93,15 +117,9 @@ public final class ClockCameraTypeSupport {
|
||||
finalizeCameraInfo(info, settings);
|
||||
return info;
|
||||
}
|
||||
|
||||
Object input = newInstance(inputClass, context);
|
||||
Display display = root.getDisplay();
|
||||
if (display != null) {
|
||||
setIntField(input, "rotation", display.getRotation());
|
||||
}
|
||||
int width = root.getWidth();
|
||||
if (width <= 0 && root.getRootView() != null) {
|
||||
width = root.getRootView().getWidth();
|
||||
setIntField(input, "rotation", info.rotation);
|
||||
}
|
||||
if (width > 0) {
|
||||
setIntField(input, "statusBarWidth", width);
|
||||
@@ -196,6 +214,9 @@ public final class ClockCameraTypeSupport {
|
||||
}
|
||||
info.cameraId = buildCameraId(
|
||||
info.semDisplayDeviceType,
|
||||
info.rootWidth,
|
||||
info.rootHeight,
|
||||
info.rotation,
|
||||
info.cutoutType,
|
||||
info.cutoutString);
|
||||
boolean explicitUdc = info.isUdcMainDisplay || "UDC".equals(info.cutoutType);
|
||||
|
||||
@@ -1129,6 +1129,29 @@ public final class SbtSettings {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setClockCameraDebugState(Context context,
|
||||
String cameraId,
|
||||
String autoType,
|
||||
String effectiveType) {
|
||||
if (context == null || MODULE_PACKAGE.equals(context.getPackageName()) || !hasSettingsProvider(context)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString(KEY_DEBUG_CURRENT_CAMERA_ID, cameraId != null ? cameraId : "");
|
||||
extras.putString(KEY_DEBUG_CURRENT_CAMERA_AUTO_TYPE, autoType != null ? autoType : "");
|
||||
extras.putString(KEY_DEBUG_CURRENT_CAMERA_EFFECTIVE_TYPE,
|
||||
effectiveType != null ? effectiveType : "");
|
||||
context.getContentResolver()
|
||||
.call(settingsProviderUri(),
|
||||
SbtSettingsProvider.METHOD_SET_CLOCK_CAMERA_DEBUG_STATE,
|
||||
null,
|
||||
extras);
|
||||
} catch (Throwable ignored) {
|
||||
// Debug camera metadata is advisory UI state only.
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasSettingsProvider(Context context) {
|
||||
if (context == null) {
|
||||
return false;
|
||||
|
||||
@@ -338,7 +338,8 @@ public class IconsDebugFragment extends Fragment {
|
||||
|
||||
if (TextUtils.isEmpty(cameraId)) {
|
||||
identifiedView.setText(getString(R.string.debug_camera_identified_as,
|
||||
getString(R.string.debug_camera_unknown)));
|
||||
getString(R.string.debug_camera_unknown),
|
||||
""));
|
||||
if (overrideRow != null) {
|
||||
overrideRow.setVisibility(View.GONE);
|
||||
}
|
||||
@@ -352,7 +353,8 @@ public class IconsDebugFragment extends Fragment {
|
||||
: ClockCameraTypeSupport.normalizeType(effectiveTypeFromReport));
|
||||
identifiedView.setText(getString(
|
||||
R.string.debug_camera_identified_as,
|
||||
readableType(currentAutoType)));
|
||||
readableType(currentAutoType),
|
||||
cameraId));
|
||||
|
||||
if (overrideRow != null && overrideView != null && actionButton != null) {
|
||||
overrideRow.setVisibility(View.VISIBLE);
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<string name="debug_notification_permission_required">Notification permission is required for debug icons.</string>
|
||||
<string name="debug_camera_current_title">Current camera</string>
|
||||
<string name="debug_camera_other_title">Other overridden cameras</string>
|
||||
<string name="debug_camera_identified_as">Identified as %1$s</string>
|
||||
<string name="debug_camera_identified_as">Identified as %1$s\n%2$s</string>
|
||||
<string name="debug_camera_overridden_as">Overridden as %1$s</string>
|
||||
<string name="debug_camera_action_wrong">This is wrong</string>
|
||||
<string name="debug_camera_action_undo">↶</string>
|
||||
@@ -131,7 +131,7 @@
|
||||
<string name="status_chips_hide_media_unlocked_label">Hide media chip (unlocked)</string>
|
||||
<string name="status_chips_hide_navigation_unlocked_label">Hide navigation chip (unlocked)</string>
|
||||
<string name="status_chips_hide_call_unlocked_label">Hide call chip (unlocked)</string>
|
||||
<string name="status_chips_hide_battery_label">Hide charging battery chip</string>
|
||||
<string name="status_chips_hide_battery_label">Hide charging battery chip (unlocked)</string>
|
||||
<string name="misc_title">Misc</string>
|
||||
<string name="battery_bar_title">Battery bar</string>
|
||||
<string name="battery_bar_master_toggle_title">Master toggle</string>
|
||||
|
||||
Reference in New Issue
Block a user