Clear ended call chips from status layout
This commit is contained in:
+12
-62
@@ -1,11 +1,9 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.layout;
|
package se.ajpanton.statusbartweak.runtime.layout;
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.KeyguardManager;
|
import android.app.KeyguardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@@ -13,7 +11,6 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
import android.telecom.TelecomManager;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
@@ -56,6 +53,7 @@ import se.ajpanton.statusbartweak.runtime.render.LockscreenCardsNotificationStri
|
|||||||
import se.ajpanton.statusbartweak.runtime.notifications.NotificationActiveKeyStore;
|
import se.ajpanton.statusbartweak.runtime.notifications.NotificationActiveKeyStore;
|
||||||
import se.ajpanton.statusbartweak.runtime.notifications.NotificationUnreadTracker;
|
import se.ajpanton.statusbartweak.runtime.notifications.NotificationUnreadTracker;
|
||||||
import se.ajpanton.statusbartweak.runtime.render.OwnedIconHostManager;
|
import se.ajpanton.statusbartweak.runtime.render.OwnedIconHostManager;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.render.StatusChipCallSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.render.UnlockedIconSnapshotRenderController;
|
import se.ajpanton.statusbartweak.runtime.render.UnlockedIconSnapshotRenderController;
|
||||||
import se.ajpanton.statusbartweak.runtime.render.UnlockedIconSnapshotRenderController.RenderResult;
|
import se.ajpanton.statusbartweak.runtime.render.UnlockedIconSnapshotRenderController.RenderResult;
|
||||||
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
||||||
@@ -2812,8 +2810,9 @@ final class StockLayoutCanvasController {
|
|||||||
staleViews.add(view);
|
staleViews.add(view);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!isTrackableStatusChipSurface(view)
|
boolean trackable = isTrackableStatusChipSurface(view);
|
||||||
&& !isTrackedHiddenStatusChipSource(root, view)) {
|
boolean retainedHidden = !trackable && isTrackedHiddenStatusChipSource(root, view);
|
||||||
|
if (!trackable && !retainedHidden) {
|
||||||
forgetTrackedStatusChipState(view);
|
forgetTrackedStatusChipState(view);
|
||||||
staleViews.add(view);
|
staleViews.add(view);
|
||||||
continue;
|
continue;
|
||||||
@@ -3365,7 +3364,7 @@ final class StockLayoutCanvasController {
|
|||||||
return visibility != View.VISIBLE
|
return visibility != View.VISIBLE
|
||||||
&& isTrackedStatusChipWriteTarget(view)
|
&& isTrackedStatusChipWriteTarget(view)
|
||||||
&& hasVisibleStatusChipContent(view)
|
&& hasVisibleStatusChipContent(view)
|
||||||
&& !isCallStatusChip(view);
|
&& !StatusChipCallSupport.isCallChip(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTrackedStatusChipWriteTarget(View view) {
|
private boolean isTrackedStatusChipWriteTarget(View view) {
|
||||||
@@ -3868,6 +3867,9 @@ final class StockLayoutCanvasController {
|
|||||||
if (ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)) {
|
if (ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (StatusChipCallSupport.isInactiveCallChip(view)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
int width = view.getWidth() > 0 ? view.getWidth() : view.getMeasuredWidth();
|
int width = view.getWidth() > 0 ? view.getWidth() : view.getMeasuredWidth();
|
||||||
int height = view.getHeight() > 0 ? view.getHeight() : view.getMeasuredHeight();
|
int height = view.getHeight() > 0 ? view.getHeight() : view.getMeasuredHeight();
|
||||||
if (width <= 0 || height <= 0) {
|
if (width <= 0 || height <= 0) {
|
||||||
@@ -3904,6 +3906,9 @@ final class StockLayoutCanvasController {
|
|||||||
if (view.getVisibility() != View.VISIBLE) {
|
if (view.getVisibility() != View.VISIBLE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (StatusChipCallSupport.isInactiveCallChip(view)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
String idName = ViewIdNames.idName(view);
|
String idName = ViewIdNames.idName(view);
|
||||||
if (!"ongoing_activity_capsule".equals(idName)) {
|
if (!"ongoing_activity_capsule".equals(idName)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -3932,31 +3937,12 @@ final class StockLayoutCanvasController {
|
|||||||
|| !isStatusChipCandidate(view)) {
|
|| !isStatusChipCandidate(view)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isCallStatusChip(view)
|
if (StatusChipCallSupport.isInactiveCallChip(view)) {
|
||||||
&& view.getVisibility() != View.VISIBLE
|
|
||||||
&& !isPhoneCallActive(view)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return hasVisibleStatusChipContent(view);
|
return hasVisibleStatusChipContent(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission") // The SystemUI process owns READ_PHONE_STATE; the explicit check below handles other hosts.
|
|
||||||
private boolean isPhoneCallActive(View view) {
|
|
||||||
if (view == null || view.getContext() == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (view.getContext().checkSelfPermission(Manifest.permission.READ_PHONE_STATE)
|
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
TelecomManager telecomManager = view.getContext().getSystemService(TelecomManager.class);
|
|
||||||
return telecomManager != null && telecomManager.isInCall();
|
|
||||||
} catch (RuntimeException ignored) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasVisibleStatusChipContent(View source) {
|
private boolean hasVisibleStatusChipContent(View source) {
|
||||||
if (!(source instanceof ViewGroup group)) {
|
if (!(source instanceof ViewGroup group)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -3986,42 +3972,6 @@ final class StockLayoutCanvasController {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCallStatusChip(View source) {
|
|
||||||
if (source == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ArrayDeque<View> queue = new ArrayDeque<>();
|
|
||||||
queue.add(source);
|
|
||||||
int scanned = 0;
|
|
||||||
while (!queue.isEmpty() && scanned++ < 48) {
|
|
||||||
View view = queue.removeFirst();
|
|
||||||
String className = view.getClass().getName().toLowerCase(Locale.ROOT);
|
|
||||||
String idName = ViewIdNames.idName(view).toLowerCase(Locale.ROOT);
|
|
||||||
if (className.contains("call") || idName.contains("call")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (containsCallToken(view.getContentDescription())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (view instanceof TextView textView && containsCallToken(textView.getText())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (view instanceof ViewGroup childGroup) {
|
|
||||||
for (int i = 0; i < childGroup.getChildCount(); i++) {
|
|
||||||
queue.addLast(childGroup.getChildAt(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean containsCallToken(CharSequence value) {
|
|
||||||
if (value == null || value.length() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String text = value.toString().toLowerCase(Locale.ROOT);
|
|
||||||
return text.contains("call") || text.contains("phone");
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isStatusChipCandidate(View view) {
|
private boolean isStatusChipCandidate(View view) {
|
||||||
String className = view.getClass().getName().toLowerCase(Locale.ROOT);
|
String className = view.getClass().getName().toLowerCase(Locale.ROOT);
|
||||||
|
|||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime.render;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.telecom.TelecomManager;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
|
|
||||||
|
/** Shared call-chip detection for source suppression and snapshot collection. */
|
||||||
|
public final class StatusChipCallSupport {
|
||||||
|
private StatusChipCallSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isInactiveCallChip(View source) {
|
||||||
|
return isCallChip(source) && !isPhoneCallActive(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isCallChip(View source) {
|
||||||
|
if (source == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ArrayDeque<View> queue = new ArrayDeque<>();
|
||||||
|
queue.add(source);
|
||||||
|
int scanned = 0;
|
||||||
|
while (!queue.isEmpty() && scanned++ < 48) {
|
||||||
|
View view = queue.removeFirst();
|
||||||
|
String className = view.getClass().getName().toLowerCase(Locale.ROOT);
|
||||||
|
String idName = ViewIdNames.idName(view).toLowerCase(Locale.ROOT);
|
||||||
|
if (className.contains("call") || idName.contains("call")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (containsCallToken(view.getContentDescription())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (view instanceof TextView textView && containsCallToken(textView.getText())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (view instanceof ViewGroup childGroup) {
|
||||||
|
for (int i = 0; i < childGroup.getChildCount(); i++) {
|
||||||
|
queue.addLast(childGroup.getChildAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
public static boolean isPhoneCallActive(View view) {
|
||||||
|
if (view == null || view.getContext() == null
|
||||||
|
|| view.getContext().checkSelfPermission(Manifest.permission.READ_PHONE_STATE)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
TelecomManager telecomManager = view.getContext().getSystemService(TelecomManager.class);
|
||||||
|
return telecomManager != null && telecomManager.isInCall();
|
||||||
|
} catch (RuntimeException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean containsCallToken(CharSequence value) {
|
||||||
|
if (value == null || value.length() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String text = value.toString().toLowerCase(Locale.ROOT);
|
||||||
|
return text.contains("call") || text.contains("phone");
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -1220,6 +1220,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
|| !view.isAttachedToWindow()
|
|| !view.isAttachedToWindow()
|
||||||
|| !ViewGeometry.isDescendantOf(view, root)
|
|| !ViewGeometry.isDescendantOf(view, root)
|
||||||
|| ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)
|
|| ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)
|
||||||
|
|| StatusChipCallSupport.isInactiveCallChip(view)
|
||||||
|| !isStatusChipCandidate(view)
|
|| !isStatusChipCandidate(view)
|
||||||
|| !hasRenderableStatusChipContent(view)) {
|
|| !hasRenderableStatusChipContent(view)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1245,6 +1246,9 @@ final class UnlockedStockSourceCollector {
|
|||||||
if (ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)) {
|
if (ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (StatusChipCallSupport.isInactiveCallChip(view)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
int width = view.getWidth() > 0 ? view.getWidth() : view.getMeasuredWidth();
|
int width = view.getWidth() > 0 ? view.getWidth() : view.getMeasuredWidth();
|
||||||
int height = view.getHeight() > 0 ? view.getHeight() : view.getMeasuredHeight();
|
int height = view.getHeight() > 0 ? view.getHeight() : view.getMeasuredHeight();
|
||||||
if (width <= 0 || height <= 0 || root == null || width >= root.getWidth() / 2) {
|
if (width <= 0 || height <= 0 || root == null || width >= root.getWidth() / 2) {
|
||||||
@@ -1336,6 +1340,9 @@ final class UnlockedStockSourceCollector {
|
|||||||
if (!allowHidden && view.getAlpha() <= 0f && !hasRenderableStatusChipContent(view)) {
|
if (!allowHidden && view.getAlpha() <= 0f && !hasRenderableStatusChipContent(view)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (StatusChipCallSupport.isInactiveCallChip(view)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
int width = view.getWidth() > 0 ? view.getWidth() : view.getMeasuredWidth();
|
int width = view.getWidth() > 0 ? view.getWidth() : view.getMeasuredWidth();
|
||||||
int height = view.getHeight() > 0 ? view.getHeight() : view.getMeasuredHeight();
|
int height = view.getHeight() > 0 ? view.getHeight() : view.getMeasuredHeight();
|
||||||
if (width <= 0 || height <= 0 || width >= root.getWidth() / 2) {
|
if (width <= 0 || height <= 0 || width >= root.getWidth() / 2) {
|
||||||
|
|||||||
Reference in New Issue
Block a user