diff --git a/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/IWindowManager.aidl b/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/IWindowManager.aidl index 25b877678..49a6e1e38 100644 --- a/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/IWindowManager.aidl +++ b/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/IWindowManager.aidl @@ -1,9 +1,13 @@ package github.tornaco.android.thanos.core.wm; +import github.tornaco.android.thanos.core.wm.WindowState; + interface IWindowManager { int[] getScreenSize(); void setDialogForceCancelable(String packageName, boolean forceCancelable); boolean isDialogForceCancelable(String packageName); void reportDialogHasBeenForceSetCancelable(String packageName); + + List getVisibleWindows(); } \ No newline at end of file diff --git a/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/IWindowManager.java b/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/IWindowManager.java index d47842ab5..e8516b420 100644 --- a/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/IWindowManager.java +++ b/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/IWindowManager.java @@ -21,6 +21,10 @@ public static class Default implements github.tornaco.android.thanos.core.wm.IWi @Override public void reportDialogHasBeenForceSetCancelable(java.lang.String packageName) throws android.os.RemoteException { } + @Override public java.util.List getVisibleWindows() throws android.os.RemoteException + { + return null; + } @Override public android.os.IBinder asBinder() { return null; @@ -102,6 +106,14 @@ public static github.tornaco.android.thanos.core.wm.IWindowManager asInterface(a reply.writeNoException(); return true; } + case TRANSACTION_getVisibleWindows: + { + data.enforceInterface(descriptor); + java.util.List _result = this.getVisibleWindows(); + reply.writeNoException(); + reply.writeTypedList(_result); + return true; + } default: { return super.onTransact(code, data, reply, flags); @@ -203,12 +215,33 @@ public java.lang.String getInterfaceDescriptor() _data.recycle(); } } + @Override public java.util.List getVisibleWindows() throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + java.util.List _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + boolean _status = mRemote.transact(Stub.TRANSACTION_getVisibleWindows, _data, _reply, 0); + if (!_status && getDefaultImpl() != null) { + return getDefaultImpl().getVisibleWindows(); + } + _reply.readException(); + _result = _reply.createTypedArrayList(github.tornaco.android.thanos.core.wm.WindowState.CREATOR); + } + finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } public static github.tornaco.android.thanos.core.wm.IWindowManager sDefaultImpl; } static final int TRANSACTION_getScreenSize = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_setDialogForceCancelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_isDialogForceCancelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_reportDialogHasBeenForceSetCancelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); + static final int TRANSACTION_getVisibleWindows = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); public static boolean setDefaultImpl(github.tornaco.android.thanos.core.wm.IWindowManager impl) { // Only one user of this interface can use this function // at a time. This is a heuristic to detect if two different @@ -230,4 +263,5 @@ public static github.tornaco.android.thanos.core.wm.IWindowManager getDefaultImp public void setDialogForceCancelable(java.lang.String packageName, boolean forceCancelable) throws android.os.RemoteException; public boolean isDialogForceCancelable(java.lang.String packageName) throws android.os.RemoteException; public void reportDialogHasBeenForceSetCancelable(java.lang.String packageName) throws android.os.RemoteException; + public java.util.List getVisibleWindows() throws android.os.RemoteException; } diff --git a/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/WindowManager.java b/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/WindowManager.java index 71fc1d162..a661fe5c4 100644 --- a/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/WindowManager.java +++ b/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/WindowManager.java @@ -1,5 +1,10 @@ package github.tornaco.android.thanos.core.wm; +import android.os.UserHandle; + +import java.util.List; + +import github.tornaco.android.thanos.core.pm.Pkg; import lombok.AllArgsConstructor; import lombok.SneakyThrows; @@ -17,4 +22,20 @@ public void setDialogForceCancelable(String packageName, boolean forceCancelable public boolean isDialogForceCancelable(String packageName) { return server.isDialogForceCancelable(packageName); } + + @SneakyThrows + public List getVisibleWindows() { + return server.getVisibleWindows(); + } + + @SneakyThrows + public boolean hasVisibleWindows(String pkgName) { + return getVisibleWindows().stream().anyMatch(windowState -> windowState.packageName.equals(pkgName)); + } + + @SneakyThrows + public boolean hasVisibleWindows(Pkg pkg) { + return getVisibleWindows().stream().anyMatch(windowState -> windowState.packageName.equals(pkg.getPkgName()) + && UserHandle.getUserId(windowState.uid) == pkg.getUserId()); + } } diff --git a/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/WindowState.java b/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/WindowState.java new file mode 100644 index 000000000..188fc3fdc --- /dev/null +++ b/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/WindowState.java @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2022 Thanox + * + * 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 github.tornaco.android.thanos.core.wm; + +import android.os.Parcel; +import android.os.Parcelable; + +public class WindowState implements Parcelable { + public String packageName; + public int uid; + public boolean visible; + public int type; + + public WindowState(String packageName, int uid, boolean visible, int type) { + this.packageName = packageName; + this.uid = uid; + this.visible = visible; + this.type = type; + } + + protected WindowState(Parcel in) { + packageName = in.readString(); + uid = in.readInt(); + visible = in.readByte() != 0; + type = in.readInt(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public WindowState createFromParcel(Parcel in) { + return new WindowState(in); + } + + @Override + public WindowState[] newArray(int size) { + return new WindowState[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(packageName); + parcel.writeInt(uid); + parcel.writeByte((byte) (visible ? 1 : 0)); + parcel.writeInt(type); + } + + @Override + public String toString() { + return "WindowState{" + + "packageName='" + packageName + '\'' + + ", uid=" + uid + + ", visible=" + visible + + ", type=" + type + " " + WindowTypeMapping.INSTANCE.getMap().get(String.valueOf(type)) + + '}'; + } +} diff --git a/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/WindowTypeMapping.kt b/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/WindowTypeMapping.kt new file mode 100644 index 000000000..41c1bbf44 --- /dev/null +++ b/android/android_framework/base/src/main/java/github/tornaco/android/thanos/core/wm/WindowTypeMapping.kt @@ -0,0 +1,76 @@ +/* + * (C) Copyright 2022 Thanox + * + * 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 github.tornaco.android.thanos.core.wm + +object WindowTypeMapping { + + fun MutableMap.add(data: Pair) { + this[data.first] = data.second + } + + val map = mutableMapOf().apply { + add("2" to "TYPE_APPLICATION") + add("3" to "TYPE_APPLICATION_STARTING") + add("4" to "TYPE_DRAWN_APPLICATION") + add("1000" to "TYPE_APPLICATION_PANEL") + add("1001" to "TYPE_APPLICATION_MEDIA") + add("1002" to "TYPE_APPLICATION_SUB_PANEL") + add("1003" to "TYPE_APPLICATION_ATTACHED_DIALOG") + add("1004" to "TYPE_APPLICATION_MEDIA_OVERLAY") + add("1005" to "TYPE_APPLICATION_ABOVE_SUB_PANEL") + add("2000" to "TYPE_STATUS_BAR") + add("2001" to "TYPE_SEARCH_BAR") + add("2002" to "TYPE_PHONE") + add("2003" to "TYPE_SYSTEM_ALERT") + add("2004" to "TYPE_KEYGUARD") + add("2005" to "TYPE_TOAST") + add("2006" to "TYPE_SYSTEM_OVERLAY") + add("2007" to "TYPE_PRIORITY_PHONE") + add("2008" to "TYPE_SYSTEM_DIALOG") + add("2009" to "TYPE_KEYGUARD_DIALOG") + add("2010" to "TYPE_SYSTEM_ERROR") + add("2011" to "TYPE_INPUT_METHOD") + add("2012" to "TYPE_INPUT_METHOD_DIALOG") + add("2013" to "TYPE_WALLPAPER") + add("2014" to "TYPE_STATUS_BAR_PANEL") + add("2015" to "TYPE_SECURE_SYSTEM_OVERLAY") + add("2016" to "TYPE_DRAG") + add("2017" to "TYPE_STATUS_BAR_SUB_PANEL") + add("2018" to "TYPE_POINTER") + add("2019" to "TYPE_NAVIGATION_BAR") + add("2020" to "TYPE_VOLUME_OVERLAY") + add("2021" to "TYPE_BOOT_PROGRESS") + add("2022" to "TYPE_INPUT_CONSUMER") + add("2024" to "TYPE_NAVIGATION_BAR_PANEL") + add("2026" to "TYPE_DISPLAY_OVERLAY") + add("2027" to "TYPE_MAGNIFICATION_OVERLAY") + add("2030" to "TYPE_PRIVATE_PRESENTATION") + add("2031" to "TYPE_VOICE_INTERACTION") + add("2032" to "TYPE_ACCESSIBILITY_OVERLAY") + add("2033" to "TYPE_VOICE_INTERACTION_STARTING") + add("2034" to "TYPE_DOCK_DIVIDER") + add("2035" to "TYPE_QS_DIALOG") + add("2036" to "TYPE_SCREENSHOT") + add("2037" to "TYPE_PRESENTATION") + add("2038" to "TYPE_APPLICATION_OVERLAY") + add("2039" to "TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY") + add("2040" to "TYPE_NOTIFICATION_SHADE") + add("2041" to "TYPE_STATUS_BAR_ADDITIONAL") + } +} + diff --git a/android/android_framework/patch-common/src/main/java/github/tornaco/android/thanos/services/patch/common/wm/XWindowManagerService.kt b/android/android_framework/patch-common/src/main/java/github/tornaco/android/thanos/services/patch/common/wm/XWindowManagerService.kt new file mode 100644 index 000000000..a6b99066e --- /dev/null +++ b/android/android_framework/patch-common/src/main/java/github/tornaco/android/thanos/services/patch/common/wm/XWindowManagerService.kt @@ -0,0 +1,56 @@ +package github.tornaco.android.thanos.services.patch.common.wm + +import com.elvishew.xlog.XLog +import util.XposedHelpers +import java.util.function.Consumer + +object XWindowManagerService { + @JvmStatic + fun wmsClass(classLoader: ClassLoader): Class<*> { + return XposedHelpers.findClass( + "com.android.server.wm.WindowManagerService", + classLoader + ) + } + + @JvmStatic + fun getInstance(classLoader: ClassLoader): Any? { + return kotlin.runCatching { + XposedHelpers.callStaticMethod( + wmsClass(classLoader), + "getInstance" + ) + }.getOrElse { + XLog.e("XWindowManagerService#getInstance error") + null + } + } + + @JvmStatic + fun getRoot(wms: Any): Any? { + return kotlin.runCatching { + XposedHelpers.getObjectField( + wms, + "mRoot" + ) + }.getOrElse { + XLog.e("XWindowManagerService#getRoot error") + null + } + } + + // void forAllWindows(Consumer var1, boolean var2) + @JvmStatic + fun forAllWindows(root: Any, consumer: Consumer<*>) { + kotlin.runCatching { + XposedHelpers.callMethod( + root, + "forAllWindows", + consumer, + false /* traverseTopToBottom */ + ) + }.onFailure { + XLog.e("XWindowManagerService#forAllWindows error") + } + } +} \ No newline at end of file diff --git a/android/android_framework/patch-common/src/main/java/github/tornaco/android/thanos/services/patch/common/wm/XWindowState.kt b/android/android_framework/patch-common/src/main/java/github/tornaco/android/thanos/services/patch/common/wm/XWindowState.kt new file mode 100644 index 000000000..94c10cf77 --- /dev/null +++ b/android/android_framework/patch-common/src/main/java/github/tornaco/android/thanos/services/patch/common/wm/XWindowState.kt @@ -0,0 +1,31 @@ +package github.tornaco.android.thanos.services.patch.common.wm + +import android.annotation.SuppressLint +import com.elvishew.xlog.XLog +import github.tornaco.android.thanos.core.wm.WindowState +import util.XposedHelpers + + +object XWindowState { + + @SuppressLint("PrivateApi") + @JvmStatic + fun getState(state: Any?): WindowState? { + return if (state == null) null else try { + val visible = XposedHelpers.callMethod(state, "isVisible") as Boolean + val type = XposedHelpers.callMethod(state, "getWindowType") as Int + val uid = XposedHelpers.callMethod(state, "getOwningUid") as Int + val ownPackageName = + XposedHelpers.callMethod(state, "getOwningPackage") as String + WindowState( + ownPackageName, + uid, + visible, + type + ) + } catch (e: Throwable) { + XLog.e("XWindowState#getState error", e) + null + } + } +} \ No newline at end of file diff --git a/android/android_sdk/thanos.aidl b/android/android_sdk/thanos.aidl index 3cb8de3ee..6e990ed35 100644 --- a/android/android_sdk/thanos.aidl +++ b/android/android_sdk/thanos.aidl @@ -23,5 +23,6 @@ parcelable github.tornaco.android.thanos.core.power.SeenWakeLock; parcelable github.tornaco.android.thanos.core.su.SuRes; parcelable github.tornaco.android.thanos.core.plus.RR; parcelable github.tornaco.android.thanos.core.os.SwapInfo; +parcelable github.tornaco.android.thanos.core.wm.WindowState; parcelable android.content.pm.UserInfo; diff --git a/android/internal/Thanox-Internal b/android/internal/Thanox-Internal index ba3a97d5a..397c1a77f 160000 --- a/android/internal/Thanox-Internal +++ b/android/internal/Thanox-Internal @@ -1 +1 @@ -Subproject commit ba3a97d5a41815d6075165525ad0eaa67fd05504 +Subproject commit 397c1a77f1d568bf1ae48237d529de088bc37055