diff --git a/app/src/main/java/com/sevtinge/hyperceiler/module/app/SystemUI.java b/app/src/main/java/com/sevtinge/hyperceiler/module/app/SystemUI.java index 52f19d505a..977761f280 100644 --- a/app/src/main/java/com/sevtinge/hyperceiler/module/app/SystemUI.java +++ b/app/src/main/java/com/sevtinge/hyperceiler/module/app/SystemUI.java @@ -23,6 +23,7 @@ import com.sevtinge.hyperceiler.module.hook.systemui.controlcenter.FlashLight; import com.sevtinge.hyperceiler.module.hook.systemui.controlcenter.GmsTile; import com.sevtinge.hyperceiler.module.hook.systemui.controlcenter.MuteVisibleNotifications; +import com.sevtinge.hyperceiler.module.hook.systemui.controlcenter.NotificationRowMenu; import com.sevtinge.hyperceiler.module.hook.systemui.controlcenter.NotificationWeather; import com.sevtinge.hyperceiler.module.hook.systemui.controlcenter.NotificationWeatherNew; import com.sevtinge.hyperceiler.module.hook.systemui.controlcenter.NotificationWeatherOld; @@ -210,6 +211,7 @@ public void handleLoadPackage() { initHook(new AutoCollapse(), mPrefsMap.getBoolean("system_ui_control_auto_close")); initHook(RedirectToNotificationChannelSetting.INSTANCE, mPrefsMap.getBoolean("system_ui_control_center_redirect_notice")); initHook(ControlCenterStyle.INSTANCE, mPrefsMap.getBoolean("system_control_center_unlock_old")); + initHook(new NotificationRowMenu(), mPrefsMap.getBoolean("system_ui_control_center_notifrowmenu")); // Actions initHook(new StatusBarActions()); diff --git a/app/src/main/java/com/sevtinge/hyperceiler/module/hook/systemui/controlcenter/NotificationRowMenu.java b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/systemui/controlcenter/NotificationRowMenu.java new file mode 100644 index 0000000000..8cd8275bbb --- /dev/null +++ b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/systemui/controlcenter/NotificationRowMenu.java @@ -0,0 +1,135 @@ +package com.sevtinge.hyperceiler.module.hook.systemui.controlcenter; + +import android.app.ActivityManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.UserHandle; +import android.util.TypedValue; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.sevtinge.hyperceiler.R; +import com.sevtinge.hyperceiler.module.base.BaseHook; +import com.sevtinge.hyperceiler.utils.Helpers; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.function.Consumer; + +import de.robv.android.xposed.XposedHelpers; + +public class NotificationRowMenu extends BaseHook { + @Override + public void init() { + int appInfoIconResId = mResHook.addResource("ic_appinfo", R.drawable.ic_appinfo12); + int forceCloseIconResId = mResHook.addResource("ic_forceclose", R.drawable.ic_forceclose12); + int openInFwIconResId = mResHook.addResource("ic_openinfw", R.drawable.ic_openinfw); + int appInfoDescId = mResHook.addResource("miui_notification_menu_appinfo_title", R.string.system_notifrowmenu_appinfo); + int forceCloseDescId = mResHook.addResource("miui_notification_menu_forceclose_title", R.string.system_notifrowmenu_forceclose); + int openInFwDescId = mResHook.addResource("miui_notification_menu_openinfw_title", R.string.system_notifrowmenu_openinfw); + mResHook.setDensityReplacement("com.android.systemui", "dimen", "notification_menu_icon_padding", 0); + mResHook.setDensityReplacement("com.android.systemui", "dimen", "miui_notification_modal_menu_margin_left_right", 3); + mResHook.setResReplacement("com.android.systemui", "drawable", "miui_notification_menu_ic_bg_active", R.drawable.miui_notification_menu_ic_bg_active); + mResHook.setResReplacement("com.android.systemui", "drawable", "miui_notification_menu_ic_bg_inactive", R.drawable.miui_notification_menu_ic_bg_inactive); + + Class MiuiNotificationMenuItem = findClass("com.android.systemui.statusbar.notification.row.MiuiNotificationMenuRow.MiuiNotificationMenuItem", lpparam.classLoader); + findAndHookMethod("com.android.systemui.statusbar.notification.row.MiuiNotificationMenuRow", "createMenuViews", boolean.class, boolean.class, new MethodHook() { + @Override + @SuppressWarnings("unchecked") + protected void after(final MethodHookParam param) throws Throwable { + Context mContext = (Context) XposedHelpers.getObjectField(param.thisObject, "mContext"); + ArrayList mMenuItems = (ArrayList)XposedHelpers.getObjectField(param.thisObject, "mMenuItems"); + + Object infoBtn = null; + Object forceCloseBtn = null; + Object openFwBtn = null; + Constructor MenuItem = MiuiNotificationMenuItem.getConstructors()[0]; + try { + infoBtn = MenuItem.newInstance(param.thisObject, mContext, appInfoDescId, null, appInfoIconResId); + forceCloseBtn = MenuItem.newInstance(param.thisObject, mContext, forceCloseDescId, null, forceCloseIconResId); + openFwBtn = MenuItem.newInstance(param.thisObject, mContext, openInFwDescId, null, openInFwIconResId); + } catch (Throwable t1) { + logW(TAG, "com.android.systemui", t1); + } + if (infoBtn == null || forceCloseBtn == null || openFwBtn == null) return; + Object notification = XposedHelpers.getObjectField(param.thisObject, "mSbn"); + Object expandNotifyRow = XposedHelpers.getObjectField(param.thisObject, "mParent"); + mMenuItems.add(infoBtn); + mMenuItems.add(forceCloseBtn); + mMenuItems.add(openFwBtn); + XposedHelpers.setObjectField(param.thisObject, "mMenuItems", mMenuItems); + int menuMargin = (int) XposedHelpers.getObjectField(param.thisObject, "mMenuMargin"); + LinearLayout mMenuContainer = (LinearLayout)XposedHelpers.getObjectField(param.thisObject, "mMenuContainer"); + View mInfoBtn = (View) XposedHelpers.callMethod(infoBtn, "getMenuView"); + View mForceCloseBtn = (View) XposedHelpers.callMethod(forceCloseBtn, "getMenuView"); + View mOpenFwBtn = (View) XposedHelpers.callMethod(openFwBtn, "getMenuView"); + + View.OnClickListener itemClick = new View.OnClickListener() { + @Override + public void onClick(View view) { + if (view == null) return; + String pkgName = (String)XposedHelpers.callMethod(notification, "getPackageName"); + int uid = (int)XposedHelpers.callMethod(notification, "getAppUid"); + int user = 0; + try { + user = (int)XposedHelpers.callStaticMethod(UserHandle.class, "getUserId", uid); + } catch (Throwable t) { + logW(TAG, "com.android.systemui", t); + } + + if (view == mInfoBtn) { + Helpers.openAppInfo(mContext, pkgName, user); + mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + } else if (view == mForceCloseBtn) { + ActivityManager am = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE); + if (user != 0) + XposedHelpers.callMethod(am, "forceStopPackageAsUser", pkgName, user); + else + XposedHelpers.callMethod(am, "forceStopPackage", pkgName); + try { + CharSequence appName = mContext.getPackageManager().getApplicationLabel(mContext.getPackageManager().getApplicationInfo(pkgName, 0)); + //Toast.makeText(mContext, Helpers.getModuleRes(mContext).getString(R.string.force_closed, appName), Toast.LENGTH_SHORT).show(); + } catch (Throwable ignore) {} + } + else if (view == mOpenFwBtn) { + Class Dependency = findClass("com.android.systemui.Dependency", lpparam.classLoader); + Object AppMiniWindowManager = XposedHelpers.callStaticMethod(Dependency, "get", findClassIfExists("com.android.systemui.statusbar.notification.policy.AppMiniWindowManager", lpparam.classLoader)); + String miniWindowPkg = (String) XposedHelpers.callMethod(expandNotifyRow, "getMiniWindowTargetPkg"); + PendingIntent notifyIntent = (PendingIntent) XposedHelpers.callMethod(expandNotifyRow, "getPendingIntent"); + String ModalControllerForDep = "com.android.systemui.statusbar.notification.modal.ModalController"; + Object ModalController = XposedHelpers.callStaticMethod(Dependency, "get", findClass(ModalControllerForDep, lpparam.classLoader)); + XposedHelpers.callMethod(ModalController, "animExitModelCollapsePanels"); + XposedHelpers.callMethod(AppMiniWindowManager, "launchMiniWindowActivity", miniWindowPkg, notifyIntent); +// mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + } + } + }; + mInfoBtn.setOnClickListener(itemClick); + mForceCloseBtn.setOnClickListener(itemClick); + mOpenFwBtn.setOnClickListener(itemClick); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(-2, -2); + layoutParams.leftMargin = menuMargin; + layoutParams.rightMargin = menuMargin; + mMenuContainer.addView(mInfoBtn, layoutParams); + mMenuContainer.addView(mForceCloseBtn, layoutParams); + mMenuContainer.addView(mOpenFwBtn, layoutParams); + int menuWidth = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + 52, + mContext.getResources().getDisplayMetrics() + ); + int titleId = mContext.getResources().getIdentifier("modal_menu_title", "id", lpparam.packageName); + mMenuItems.forEach(new Consumer() { + @Override + public void accept(Object obj) { + View menuView = (View) XposedHelpers.callMethod(obj, "getMenuView"); + ((TextView) menuView.findViewById(titleId)).setMaxWidth(menuWidth); + } + }); + } + }); + } +} diff --git a/app/src/main/java/com/sevtinge/hyperceiler/utils/Helpers.java b/app/src/main/java/com/sevtinge/hyperceiler/utils/Helpers.java index b52c9c4d18..7b731b7702 100644 --- a/app/src/main/java/com/sevtinge/hyperceiler/utils/Helpers.java +++ b/app/src/main/java/com/sevtinge/hyperceiler/utils/Helpers.java @@ -2,12 +2,14 @@ import static com.sevtinge.hyperceiler.utils.log.AndroidLogUtils.LogD; import static com.sevtinge.hyperceiler.utils.log.AndroidLogUtils.LogI; +import static com.sevtinge.hyperceiler.utils.log.XposedLogUtils.logE; import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityOptions; import android.app.Application; import android.content.Context; +import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; @@ -21,6 +23,7 @@ import android.net.Uri; import android.os.Environment; import android.os.Handler; +import android.os.UserHandle; import android.util.LruCache; import android.widget.TextView; @@ -316,6 +319,28 @@ public void onChange(String name, boolean defValue) { } } + public static void openAppInfo(Context context, String pkg, int user) { + try { + Intent intent = new Intent("miui.intent.action.APP_MANAGER_APPLICATION_DETAIL"); + intent.setPackage("com.miui.securitycenter"); + intent.putExtra("package_name", pkg); + if (user != 0) intent.putExtra("miui.intent.extra.USER_ID", user); + context.startActivity(intent); + } catch (Throwable t) { + try { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + intent.setData(Uri.parse("package:" + pkg)); + if (user != 0) + XposedHelpers.callMethod(context, "startActivityAsUser", intent, XposedHelpers.newInstance(UserHandle.class, user)); + else + context.startActivity(intent); + } catch (Throwable t2) { + logE(TAG, "openAppInfo" + t2); + } + } + } + @SuppressWarnings("unchecked") public static Set getSharedStringSetPref(Context context, String name) { Uri uri = stringSetPrefToUri(name); @@ -412,10 +437,10 @@ public static String getPackageVersionName(XC_LoadPackage.LoadPackageParam lppar File apkPath = new File(lpparam.appInfo.sourceDir); Object pkg = XposedHelpers.callMethod(parser, "parsePackage", apkPath, 0); String versionName = (String) XposedHelpers.getObjectField(pkg, "mVersionName"); - XposedLogUtils.logI("getPackageVersionName", lpparam + " versionName is " + versionName); + //XposedLogUtils.logI("getPackageVersionName", lpparam.packageName + " versionName is " + versionName); return versionName; } catch (Throwable e) { - XposedLogUtils.logW("getPackageVersionName", e); + //XposedLogUtils.logW("getPackageVersionName", e); return "null"; } } @@ -427,10 +452,10 @@ public static int getPackageVersionCode(XC_LoadPackage.LoadPackageParam lpparam) File apkPath = new File(lpparam.appInfo.sourceDir); Object pkg = XposedHelpers.callMethod(parser, "parsePackage", apkPath, 0); int versionCode = XposedHelpers.getIntField(pkg, "mVersionCode"); - XposedLogUtils.logI("getPackageVersionCode", lpparam + " versionCode is " + versionCode); + //XposedLogUtils.logI("getPackageVersionCode", lpparam.packageName + " versionCode is " + versionCode); return versionCode; } catch (Throwable e) { - XposedLogUtils.logW("getPackageVersionCode", e); + //XposedLogUtils.logW("getPackageVersionCode", e); return -1; } } diff --git a/app/src/main/java/com/sevtinge/hyperceiler/utils/hook/HookUtils.java b/app/src/main/java/com/sevtinge/hyperceiler/utils/hook/HookUtils.java index 134b23543d..fa777c16b8 100644 --- a/app/src/main/java/com/sevtinge/hyperceiler/utils/hook/HookUtils.java +++ b/app/src/main/java/com/sevtinge/hyperceiler/utils/hook/HookUtils.java @@ -31,7 +31,7 @@ public Class findClassIfExists(String className) { try { return findClass(className); } catch (XposedHelpers.ClassNotFoundError e) { - logE("findClassIfExists", "find " + className + " is Null: " + e); + //logE("findClassIfExists", "find " + className + " is Null: " + e); return null; } } @@ -40,7 +40,7 @@ public Class findClassIfExists(String newClassName, String oldClassName) { try { return findClass(findClassIfExists(newClassName) != null ? newClassName : oldClassName); } catch (XposedHelpers.ClassNotFoundError e) { - logE("findClassIfExists", "find " + newClassName + " and " + oldClassName + " is Null: " + e); + //logE("findClassIfExists", "find " + newClassName + " and " + oldClassName + " is Null: " + e); return null; } } @@ -49,7 +49,7 @@ public Class findClassIfExists(String className, ClassLoader classLoader) { try { return findClass(className, classLoader); } catch (XposedHelpers.ClassNotFoundError e) { - logE("findClassIfExists", "find " + className + " is Null: " + e); + //logE("findClassIfExists", "find " + className + " is Null: " + e); return null; } } @@ -91,7 +91,7 @@ public void beforeHookedMethod(MethodHookParam param) throws Throwable { try { this.before(param); } catch (Throwable t) { - logE("BeforeHook", t); + //logE("BeforeHook", t); } } @@ -100,7 +100,7 @@ public void afterHookedMethod(MethodHookParam param) throws Throwable { try { this.after(param); } catch (Throwable t) { - logE("AfterHook", t); + //logE("AfterHook", t); } } } @@ -109,7 +109,7 @@ public void hookMethod(Method method, MethodHook callback) { try { XposedBridge.hookMethod(method, callback); } catch (Throwable t) { - logE("hookMethod", "Failed to hook " + method.getName() + " method"); + //logE("hookMethod", "Failed to hook " + method.getName() + " method"); } } @@ -125,7 +125,7 @@ public static void findAndHookMethod(String className, ClassLoader classLoader, try { XposedHelpers.findAndHookMethod(className, classLoader, methodName, parameterTypesAndCallback); } catch (Throwable t) { - logE("findAndHookMethod", "Failed to hook " + methodName + " method in " + className); + //logE("findAndHookMethod", "Failed to hook " + methodName + " method in " + className); } } @@ -133,7 +133,7 @@ public XC_MethodHook.Unhook findAndHookMethodUseUnhook(String className, ClassLo try { return XposedHelpers.findAndHookMethod(className, classLoader, methodName, parameterTypesAndCallback); } catch (Throwable t) { - logE("findAndHookMethodUseUnhook", "Failed to hook " + methodName + " method in " + className); + //logE("findAndHookMethodUseUnhook", "Failed to hook " + methodName + " method in " + className); return null; } } @@ -142,7 +142,7 @@ public XC_MethodHook.Unhook findAndHookMethodUseUnhook(Class clazz, String me try { return XposedHelpers.findAndHookMethod(clazz, methodName, parameterTypesAndCallback); } catch (Throwable t) { - logE("findAndHookMethodUseUnhook", "Failed to hook " + methodName + " method in " + clazz.getCanonicalName()); + //logE("findAndHookMethodUseUnhook", "Failed to hook " + methodName + " method in " + clazz.getCanonicalName()); return null; } } @@ -152,7 +152,7 @@ public boolean findAndHookMethodSilently(String className, String methodName, Ob findAndHookMethod(className, methodName, parameterTypesAndCallback); return true; } catch (Throwable t) { - logE("findAndHookMethodSilently", className + methodName + " is null: " + t); + //logE("findAndHookMethodSilently", className + methodName + " is null: " + t); return false; } } @@ -162,7 +162,7 @@ public boolean findAndHookMethodSilently(String className, ClassLoader classLoad XposedHelpers.findAndHookMethod(className, classLoader, methodName, parameterTypesAndCallback); return true; } catch (Throwable t) { - logE("findAndHookMethodSilently", className + methodName + " is null: " + t); + //logE("findAndHookMethodSilently", className + methodName + " is null: " + t); return false; } } @@ -172,7 +172,7 @@ public boolean findAndHookMethodSilently(Class clazz, String methodName, Obje findAndHookMethod(clazz, methodName, parameterTypesAndCallback); return true; } catch (Throwable t) { - logE("findAndHookMethodSilently", clazz + methodName + " is null: " + t); + //logE("findAndHookMethodSilently", clazz + methodName + " is null: " + t); return false; } } @@ -200,7 +200,7 @@ public void hookAllMethods(String className, String methodName, MethodHook callb XposedBridge.hookAllMethods(hookClass, methodName, callback); } } catch (Throwable t) { - logE("HookAllMethods", className + " is " + methodName + " abnormal: " + t); + //logE("HookAllMethods", className + " is " + methodName + " abnormal: " + t); } } @@ -208,7 +208,7 @@ public static void hookAllMethods(Class hookClass, String methodName, MethodH try { XposedBridge.hookAllMethods(hookClass, methodName, callback); } catch (Throwable t) { - logE("HookAllMethods", hookClass + " is " + methodName + " abnormal: " + t); + //logE("HookAllMethods", hookClass + " is " + methodName + " abnormal: " + t); } } @@ -219,7 +219,7 @@ public static void hookAllMethods(String className, ClassLoader classLoader, Str XposedBridge.hookAllMethods(hookClass, methodName, callback); } } catch (Throwable t) { - logE("hookAllMethods", className + " is abnormal", t); + //logE("hookAllMethods", className + " is abnormal", t); } } @@ -251,7 +251,7 @@ public void hookAllConstructors(String className, MethodHook callback) { XposedBridge.hookAllConstructors(hookClass, callback); } } catch (Throwable t) { - logE("hookAllConstructors", className + " is abnormal: " + t); + //logE("hookAllConstructors", className + " is abnormal: " + t); } } @@ -259,7 +259,7 @@ public void hookAllConstructors(Class hookClass, MethodHook callback) { try { XposedBridge.hookAllConstructors(hookClass, callback); } catch (Throwable t) { - logE("hookAllConstructors", hookClass + " is abnormal: " + t); + //logE("hookAllConstructors", hookClass + " is abnormal: " + t); } } @@ -270,7 +270,7 @@ public void hookAllConstructors(String className, ClassLoader classLoader, Metho XposedBridge.hookAllConstructors(hookClass, callback); } } catch (Throwable t) { - logE("hookAllConstructors", className + " is abnormal", t); + //logE("hookAllConstructors", className + " is abnormal", t); } } @@ -297,13 +297,13 @@ public void setDeclaredField(XC_MethodHook.MethodHookParam param, String iNeedSt Object result = setString.get(param.thisObject); checkLast("getDeclaredField", iNeedString, iNeedTo, result); } catch (IllegalAccessException e) { - logE("IllegalAccessException to: " + iNeedString + " need to: " + iNeedTo + " code: " + e); + //logE("IllegalAccessException to: " + iNeedString + " need to: " + iNeedTo + " code: " + e); } } catch (NoSuchFieldException e) { - logE("No such the: " + iNeedString + " code: " + e); + //logE("No such the: " + iNeedString + " code: " + e); } } else { - logE("Param is null Field: " + iNeedString + " to: " + iNeedTo); + //logE("Param is null Field: " + iNeedString + " to: " + iNeedTo); } } @@ -311,7 +311,7 @@ public void checkLast(String setObject, Object fieldName, Object value, Object l if (value.equals(last)) { logI(setObject + " Success! set " + fieldName + " to " + value); } else { - logE(setObject + " Failed! set " + fieldName + " to " + value + " hope: " + value + " but: " + last); + //logE(setObject + " Failed! set " + fieldName + " to " + value + " hope: " + value + " but: " + last); } } } diff --git a/app/src/main/res/drawable-xxhdpi-v4/ic_appinfo12.png b/app/src/main/res/drawable-xxhdpi-v4/ic_appinfo12.png new file mode 100644 index 0000000000..fabe15f3c4 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v4/ic_appinfo12.png differ diff --git a/app/src/main/res/drawable-xxhdpi-v4/ic_forceclose12.png b/app/src/main/res/drawable-xxhdpi-v4/ic_forceclose12.png new file mode 100644 index 0000000000..b881c0e20b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v4/ic_forceclose12.png differ diff --git a/app/src/main/res/drawable/ic_openinfw.xml b/app/src/main/res/drawable/ic_openinfw.xml new file mode 100644 index 0000000000..b266f68340 --- /dev/null +++ b/app/src/main/res/drawable/ic_openinfw.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/drawable/miui_notification_menu_ic_bg_active.xml b/app/src/main/res/drawable/miui_notification_menu_ic_bg_active.xml new file mode 100644 index 0000000000..43c48c8005 --- /dev/null +++ b/app/src/main/res/drawable/miui_notification_menu_ic_bg_active.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/miui_notification_menu_ic_bg_inactive.xml b/app/src/main/res/drawable/miui_notification_menu_ic_bg_inactive.xml new file mode 100644 index 0000000000..464a8c8d15 --- /dev/null +++ b/app/src/main/res/drawable/miui_notification_menu_ic_bg_inactive.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 3f21e1cb97..c40a7e0d8b 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -665,6 +665,8 @@ 对调控制中心与通知抽屉 蓝牙磁贴样式 蓝牙磁贴移至网络磁贴区域 + 扩展通知菜单 + 从通知菜单打开应用信息、强制关闭应用和浮窗打开 新控制中心 经典控制中心 @@ -1330,6 +1332,10 @@ 通知悬浮窗 分享至三方应用 + 应用信息 + 浮窗 + 强制关闭 + 标记新模块 铃声 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d0545eeaad..3d9f2b524e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -662,6 +662,11 @@ Number of columns in collapsed panel (Landscape) Bluetooth tile style Move the bluetooth tile near the network tile + Extended notification menu + Open app info, force close app and open in floating window from notification menu (swipe notification to the left to open it) + App info + Floating window + Force close Other Charge animation diff --git a/app/src/main/res/xml/system_ui_control_center.xml b/app/src/main/res/xml/system_ui_control_center.xml index 702e25c6fe..dcdead0245 100644 --- a/app/src/main/res/xml/system_ui_control_center.xml +++ b/app/src/main/res/xml/system_ui_control_center.xml @@ -34,6 +34,12 @@ android:summary="@string/system_ui_control_center_redirect_notice_desc" android:title="@string/system_ui_control_center_redirect_notice" /> + +