Prevent privacy overlay statusbar reveal
This commit is contained in:
+152
@@ -141,6 +141,10 @@ final class StockLayoutCanvasController {
|
|||||||
private final Map<View, Integer> aodBeforeDrawSignatureByRoot = new WeakHashMap<>();
|
private final Map<View, Integer> aodBeforeDrawSignatureByRoot = new WeakHashMap<>();
|
||||||
private final Set<View> trackedUnlockedStockSurfaces =
|
private final Set<View> trackedUnlockedStockSurfaces =
|
||||||
Collections.newSetFromMap(new WeakHashMap<>());
|
Collections.newSetFromMap(new WeakHashMap<>());
|
||||||
|
private final Set<View> suppressedHiddenStatusBarRoots =
|
||||||
|
Collections.newSetFromMap(new WeakHashMap<>());
|
||||||
|
private final Set<View> privacyOverlayHiddenStatusBarRoots =
|
||||||
|
Collections.newSetFromMap(new WeakHashMap<>());
|
||||||
private final Set<View> trackedLockedStatusBarIconSurfaces =
|
private final Set<View> trackedLockedStatusBarIconSurfaces =
|
||||||
Collections.newSetFromMap(new WeakHashMap<>());
|
Collections.newSetFromMap(new WeakHashMap<>());
|
||||||
private final Set<View> lockedStatusBarIconSurfaceReadyRoots =
|
private final Set<View> lockedStatusBarIconSurfaceReadyRoots =
|
||||||
@@ -195,6 +199,7 @@ final class StockLayoutCanvasController {
|
|||||||
private boolean notificationDrawerClosePending;
|
private boolean notificationDrawerClosePending;
|
||||||
private int aodVisualAlphaGeneration;
|
private int aodVisualAlphaGeneration;
|
||||||
private int systemBarRequestedVisibleTypes = WindowInsets.Type.statusBars();
|
private int systemBarRequestedVisibleTypes = WindowInsets.Type.statusBars();
|
||||||
|
private boolean statusBarTransientShown;
|
||||||
|
|
||||||
StockLayoutCanvasController(RuntimeContext runtimeContext) {
|
StockLayoutCanvasController(RuntimeContext runtimeContext) {
|
||||||
this.runtimeContext = runtimeContext;
|
this.runtimeContext = runtimeContext;
|
||||||
@@ -224,6 +229,7 @@ final class StockLayoutCanvasController {
|
|||||||
installShadeExpansionHooks(classLoader);
|
installShadeExpansionHooks(classLoader);
|
||||||
installShadeHeaderAnimationGuardHook(classLoader);
|
installShadeHeaderAnimationGuardHook(classLoader);
|
||||||
installSystemBarAttributeListener(classLoader);
|
installSystemBarAttributeListener(classLoader);
|
||||||
|
installTransientBarListener(classLoader);
|
||||||
installViewRootHook(classLoader);
|
installViewRootHook(classLoader);
|
||||||
hooksInstalled = true;
|
hooksInstalled = true;
|
||||||
}
|
}
|
||||||
@@ -259,6 +265,85 @@ final class StockLayoutCanvasController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
systemBarRequestedVisibleTypes = requestedVisibleTypes;
|
systemBarRequestedVisibleTypes = requestedVisibleTypes;
|
||||||
|
if (statusBarsRequestedVisible()) {
|
||||||
|
releaseSuppressedHiddenStatusBarRoots();
|
||||||
|
privacyOverlayHiddenStatusBarRoots.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void installTransientBarListener(ClassLoader classLoader) {
|
||||||
|
Class<?> commandQueueClass = ReflectionSupport.findClassIfExists(
|
||||||
|
"com.android.systemui.statusbar.CommandQueue",
|
||||||
|
classLoader);
|
||||||
|
if (commandQueueClass != null) {
|
||||||
|
XposedHookSupport.hookAllMethodsIfExists(
|
||||||
|
runtimeContext.getFramework(),
|
||||||
|
commandQueueClass,
|
||||||
|
"showTransient",
|
||||||
|
chain -> {
|
||||||
|
Object result = chain.proceed();
|
||||||
|
updateTransientBarState(chain.getArgs(), true);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
XposedHookSupport.hookAllMethodsIfExists(
|
||||||
|
runtimeContext.getFramework(),
|
||||||
|
commandQueueClass,
|
||||||
|
"abortTransient",
|
||||||
|
chain -> {
|
||||||
|
Object result = chain.proceed();
|
||||||
|
updateTransientBarState(chain.getArgs(), false);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
installStatusBarAutoHideElementListener(classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void installStatusBarAutoHideElementListener(ClassLoader classLoader) {
|
||||||
|
Class<?> statusBarAutoHideElementClass = ReflectionSupport.findClassIfExists(
|
||||||
|
"com.android.systemui.statusbar.phone.CentralSurfacesImpl$5",
|
||||||
|
classLoader);
|
||||||
|
if (statusBarAutoHideElementClass == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XposedHookSupport.hookAllMethodsIfExists(
|
||||||
|
runtimeContext.getFramework(),
|
||||||
|
statusBarAutoHideElementClass,
|
||||||
|
"hide",
|
||||||
|
chain -> {
|
||||||
|
Object result = chain.proceed();
|
||||||
|
updateStatusBarTransientShown(false);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTransientBarState(List<Object> args, boolean visible) {
|
||||||
|
Integer displayId = args != null && !args.isEmpty() ? asInteger(args.get(0)) : null;
|
||||||
|
boolean statusBarsAffected = transientArgsIncludeStatusBars(args);
|
||||||
|
if (displayId == null || displayId != 0 || !statusBarsAffected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateStatusBarTransientShown(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatusBarTransientShown(boolean shown) {
|
||||||
|
statusBarTransientShown = shown;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean transientArgsIncludeStatusBars(List<Object> args) {
|
||||||
|
if (args == null || args.size() < 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Object typesArg = args.get(1);
|
||||||
|
if (!(typesArg instanceof int[] types)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int statusBars = WindowInsets.Type.statusBars();
|
||||||
|
for (int type : types) {
|
||||||
|
if ((type & statusBars) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void installNotificationCollectionHooks(ClassLoader classLoader) {
|
private void installNotificationCollectionHooks(ClassLoader classLoader) {
|
||||||
@@ -449,6 +534,10 @@ final class StockLayoutCanvasController {
|
|||||||
Object target = chain.getThisObject();
|
Object target = chain.getThisObject();
|
||||||
Object alphaArg = firstArg(chain.getArgs());
|
Object alphaArg = firstArg(chain.getArgs());
|
||||||
if (target instanceof View view && alphaArg instanceof Float alpha) {
|
if (target instanceof View view && alphaArg instanceof Float alpha) {
|
||||||
|
rememberPrivacyOverlayHiddenStatusBarRoot(view);
|
||||||
|
if (shouldSuppressHiddenStatusBarRootAlpha(view, alpha)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (shouldSuppressPrivacyOverlayStatusBarAlpha(view, alpha)) {
|
if (shouldSuppressPrivacyOverlayStatusBarAlpha(view, alpha)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -510,6 +599,7 @@ final class StockLayoutCanvasController {
|
|||||||
Object target = chain.getThisObject();
|
Object target = chain.getThisObject();
|
||||||
Object translationArg = firstArg(chain.getArgs());
|
Object translationArg = firstArg(chain.getArgs());
|
||||||
if (target instanceof View view && translationArg instanceof Float translationX) {
|
if (target instanceof View view && translationArg instanceof Float translationX) {
|
||||||
|
rememberPrivacyOverlayHiddenStatusBarRoot(view);
|
||||||
if (shouldSuppressPrivacyOverlayStatusBarTranslationX(view, translationX)) {
|
if (shouldSuppressPrivacyOverlayStatusBarTranslationX(view, translationX)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -2219,6 +2309,10 @@ final class StockLayoutCanvasController {
|
|||||||
if (root == null || !hasDirectUnlockedLayoutHost(root)) {
|
if (root == null || !hasDirectUnlockedLayoutHost(root)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!statusBarsRequestedVisible() && !statusBarTransientShown) {
|
||||||
|
ownedIconHostManager.setUnlockedHostsTransform(root, 0f, 0f, 0f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (activeScene == null || !activeScene.isUnlocked()) {
|
if (activeScene == null || !activeScene.isUnlocked()) {
|
||||||
ownedIconHostManager.setUnlockedHostsTransform(root, 1f, 0f, 0f);
|
ownedIconHostManager.setUnlockedHostsTransform(root, 1f, 0f, 0f);
|
||||||
return;
|
return;
|
||||||
@@ -3564,6 +3658,64 @@ final class StockLayoutCanvasController {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean shouldSuppressHiddenStatusBarRootAlpha(View view, float alpha) {
|
||||||
|
boolean privacyOverlayRoot = privacyOverlayHiddenStatusBarRoots.contains(view);
|
||||||
|
boolean suppress = alpha > 0f
|
||||||
|
&& ownHiddenViewAlphaWriteDepth <= 0
|
||||||
|
&& isPhoneStatusBarRoot(view)
|
||||||
|
&& view.isAttachedToWindow()
|
||||||
|
&& isLayoutEnabled(view.getContext())
|
||||||
|
&& !statusBarsRequestedVisible()
|
||||||
|
&& (privacyOverlayRoot || !statusBarTransientShown);
|
||||||
|
if (suppress) {
|
||||||
|
suppressedHiddenStatusBarRoots.add(view);
|
||||||
|
}
|
||||||
|
return suppress;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rememberPrivacyOverlayHiddenStatusBarRoot(View view) {
|
||||||
|
if (view == null
|
||||||
|
|| !isPhoneStatusBarRoot(view)
|
||||||
|
|| !view.isAttachedToWindow()
|
||||||
|
|| statusBarsRequestedVisible()
|
||||||
|
|| !isLayoutEnabled(view.getContext())
|
||||||
|
|| ongoingPrivacyChipInRoot(view) == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
privacyOverlayHiddenStatusBarRoots.add(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseSuppressedHiddenStatusBarRoots() {
|
||||||
|
if (suppressedHiddenStatusBarRoots.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ArrayDeque<View> staleRoots = new ArrayDeque<>();
|
||||||
|
for (View root : suppressedHiddenStatusBarRoots) {
|
||||||
|
if (root == null || !root.isAttachedToWindow()) {
|
||||||
|
staleRoots.add(root);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!isLayoutEnabled(root.getContext())) {
|
||||||
|
staleRoots.add(root);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Runnable restore = () -> {
|
||||||
|
if (root.isAttachedToWindow()
|
||||||
|
&& statusBarsRequestedVisible()
|
||||||
|
&& root.getAlpha() <= 0f) {
|
||||||
|
root.setAlpha(1f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (root.getHandler() != null) {
|
||||||
|
root.post(restore);
|
||||||
|
} else {
|
||||||
|
restore.run();
|
||||||
|
}
|
||||||
|
staleRoots.add(root);
|
||||||
|
}
|
||||||
|
removeStaleViews(suppressedHiddenStatusBarRoots, staleRoots);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean shouldSuppressPrivacyOverlayStatusBarAlpha(View view, float alpha) {
|
private boolean shouldSuppressPrivacyOverlayStatusBarAlpha(View view, float alpha) {
|
||||||
if (alpha >= 0.99f
|
if (alpha >= 0.99f
|
||||||
|| ownHiddenViewAlphaWriteDepth > 0
|
|| ownHiddenViewAlphaWriteDepth > 0
|
||||||
|
|||||||
Reference in New Issue
Block a user