Loading bliss/res_overrides/values/config.xml +2 −0 Original line number Diff line number Diff line Loading @@ -6,4 +6,6 @@ <item>@string/quickstep_component</item> <item>@string/launcher_component</item> </string-array> <bool name="default_single_mode">true</bool> </resources> bliss/src/foundation/e/bliss/LauncherAppMonitor.java +13 −7 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import com.android.launcher3.LauncherPrefs; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.Utilities; import com.android.launcher3.util.MainThreadInitializedObject; import java.io.FileDescriptor; import java.io.PrintWriter; Loading @@ -35,6 +34,8 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import foundation.e.bliss.multimode.MultiModeController; public class LauncherAppMonitor extends LauncherApps.Callback implements SharedPreferences.OnSharedPreferenceChangeListener, Loading @@ -49,7 +50,7 @@ public class LauncherAppMonitor extends LauncherApps.Callback private Launcher mLauncher; // private MultiModeController mMultiModeController = null; private MultiModeController mMultiModeController = null; public static LauncherAppMonitor getInstance(final Context context) { return INSTANCE.get(context.getApplicationContext()); Loading Loading @@ -94,9 +95,10 @@ public class LauncherAppMonitor extends LauncherApps.Callback } } private LauncherAppMonitor(Context context) { LauncherPrefs.get(context).addListener(this); // mMultiModeController = new MultiModeController(context, this); public LauncherAppMonitor(Context context) { context.getSystemService(LauncherApps.class).registerCallback(this); LauncherPrefs.getPrefs(context).registerOnSharedPreferenceChangeListener(this); mMultiModeController = new MultiModeController(context, this); } @Override Loading Loading @@ -470,4 +472,8 @@ public class LauncherAppMonitor extends LauncherApps.Callback @Override public void onAppSharedPreferenceChanged(@Nullable String key) { } public MultiModeController getMultiModeController() { return mMultiModeController; } } No newline at end of file bliss/src/foundation/e/bliss/multimode/MultiModeController.kt 0 → 100644 +112 −0 Original line number Diff line number Diff line /* * Copyright © MURENA SAS 2023. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.bliss.multimode import android.content.Context import android.content.SharedPreferences import android.content.res.Resources import android.util.Log import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherPrefs import com.android.launcher3.R import com.android.launcher3.model.data.AppInfo import com.android.launcher3.util.Executors.MODEL_EXECUTOR import foundation.e.bliss.BaseController import foundation.e.bliss.LauncherAppMonitor import foundation.e.bliss.LauncherAppMonitorCallback import foundation.e.bliss.preferences.BlissPrefs import java.io.FileDescriptor import java.io.PrintWriter class MultiModeController(val context: Context, val monitor: LauncherAppMonitor) : BaseController { private val idp by lazy { InvariantDeviceProfile.INSTANCE.get(context) } private val mAppMonitorCallback: LauncherAppMonitorCallback = object : LauncherAppMonitorCallback { override fun onLoadAllAppsEnd(apps: ArrayList<AppInfo?>?) { MODEL_EXECUTOR.submit( VerifyIdleAppTask( context, apps, null, null, false, monitor.launcher.model.mBgDataModel ) ) } override fun onAppSharedPreferenceChanged(key: String?) { when (key) { BlissPrefs.PREF_SINGLE_LAYER_MODE -> { monitor.launcher.model.forceReload() } else -> Unit } } override fun dump( prefix: String?, fd: FileDescriptor?, w: PrintWriter?, dumpAll: Boolean ) { w?.let { println() println("$prefix $TAG: ${this@MultiModeController}") } } } init { sharedPreferences = LauncherPrefs.getPrefs(context) resources = context.resources monitor.registerCallback(mAppMonitorCallback) Log.d(TAG, this.toString()) } override fun dumpState( prefix: String?, fd: FileDescriptor?, writer: PrintWriter?, dumpAll: Boolean ) { writer?.let { println() println("$prefix $TAG: ${this@MultiModeController}") } } companion object { private const val TAG = "MultiModeController" @JvmField var sharedPreferences: SharedPreferences? = null @JvmField var resources: Resources? = null private fun throwIfControllerNotInit() { val launcherAppMonitor = LauncherAppMonitor.getInstanceNoCreate() if (launcherAppMonitor == null || launcherAppMonitor.multiModeController == null) { throw RuntimeException("MultiModeController is not init.") } } @JvmStatic val isSingleLayerMode: Boolean get() { throwIfControllerNotInit() return sharedPreferences!! .getBoolean( BlissPrefs.PREF_SINGLE_LAYER_MODE, resources!!.getBoolean(R.bool.default_single_mode) ) .apply { Log.d(TAG, "Single Layer Mode (getter): $this") return@apply } } } } bliss/src/foundation/e/bliss/multimode/VerifyIdleAppTask.java 0 → 100644 +124 −0 Original line number Diff line number Diff line /* * Copyright © MURENA SAS 2023. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.bliss.multimode; import android.content.ComponentName; import android.content.Context; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.os.UserHandle; import android.util.Log; import android.util.Pair; import androidx.annotation.WorkerThread; import com.android.launcher3.LauncherAppState; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ItemInfoMatcher; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.function.Predicate; @WorkerThread public class VerifyIdleAppTask implements Runnable { private static final String TAG = "VerifyIdleAppTask"; private final Context mContext; private final Collection<AppInfo> mApps; private final String mPackageNames; private final UserHandle mUser; private final boolean mIsAddPackage; private boolean mIgnoreLoaded; private BgDataModel mBgdataModel; public VerifyIdleAppTask(Context context, Collection<AppInfo> apps, String packageNames, UserHandle user, boolean isAdd, BgDataModel bgDataModel) { mContext = context; mApps = apps; mPackageNames = packageNames; mUser = user; mIsAddPackage = isAdd; mBgdataModel = bgDataModel; } private static void verifyShortcutHighRes(Context context, AppInfo appInfo) { if (appInfo != null) { if (appInfo.usingLowResIcon()) { LauncherAppState.getInstance(context).getIconCache().getTitleAndIcon(appInfo, false); } } } @Override public void run() { if (!MultiModeController.isSingleLayerMode()) { return; } final Map<ComponentKey, Object> map = new HashMap<>(); if (mApps != null && mApps.size() > 0) { // All apps loading, we ignore loaded. mIgnoreLoaded = true; for (AppInfo app : mApps) { map.put(new ComponentKey(app.componentName, app.user), app); } } else if (mPackageNames != null && mUser != null) { // App add or update, should not ignore loaded. mIgnoreLoaded = false; final LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); if (mIsAddPackage || launcherApps.isPackageEnabled(mPackageNames, mUser)) { final List<LauncherActivityInfo> infos = launcherApps.getActivityList(mPackageNames, mUser); for (LauncherActivityInfo info : infos) { map.put(new ComponentKey(info.getComponentName(), info.getUser()), info); } } } verifyAllApps(mContext, map, mIsAddPackage); } List<Pair<ItemInfo, Object>> verifyAllApps(Context context, Map<ComponentKey, Object> map, boolean animated) { List<Pair<ItemInfo, Object>> newItems = new ArrayList<>(); synchronized (mBgdataModel) { for (Map.Entry<ComponentKey, Object> entry : map.entrySet()) { ComponentKey componentKey = entry.getKey(); HashSet<ComponentName> components = new HashSet<>(1); components.add(componentKey.componentName); Predicate<ItemInfo> matcher = ItemInfoMatcher.ofComponents(components, componentKey.user); if (mBgdataModel.workspaceItems.stream().noneMatch(matcher)) { Object obj = entry.getValue(); if (obj instanceof AppInfo) { verifyShortcutHighRes(context, (AppInfo) obj); newItems.add(Pair.create((AppInfo) obj, null)); } else if (obj instanceof LauncherActivityInfo) { LauncherActivityInfo info = (LauncherActivityInfo) obj; newItems.add(new ItemInstallQueue.PendingInstallShortcutInfo( info.getApplicationInfo().packageName, info.getUser()).getItemInfo(context)); } Log.d(TAG, "will bind " + componentKey.componentName + " to workspace."); } } } LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); if (appState != null && newItems.size() > 0) { appState.getModel().addAndBindAddedWorkspaceItems(newItems, animated, mIgnoreLoaded); } return newItems; } } No newline at end of file bliss/src/foundation/e/bliss/preferences/BlissPrefs.kt 0 → 100644 +12 −0 Original line number Diff line number Diff line /* * Copyright © MURENA SAS 2023. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.bliss.preferences object BlissPrefs { const val PREF_SINGLE_LAYER_MODE = "pref_single_layer" } Loading
bliss/res_overrides/values/config.xml +2 −0 Original line number Diff line number Diff line Loading @@ -6,4 +6,6 @@ <item>@string/quickstep_component</item> <item>@string/launcher_component</item> </string-array> <bool name="default_single_mode">true</bool> </resources>
bliss/src/foundation/e/bliss/LauncherAppMonitor.java +13 −7 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import com.android.launcher3.LauncherPrefs; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.Utilities; import com.android.launcher3.util.MainThreadInitializedObject; import java.io.FileDescriptor; import java.io.PrintWriter; Loading @@ -35,6 +34,8 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import foundation.e.bliss.multimode.MultiModeController; public class LauncherAppMonitor extends LauncherApps.Callback implements SharedPreferences.OnSharedPreferenceChangeListener, Loading @@ -49,7 +50,7 @@ public class LauncherAppMonitor extends LauncherApps.Callback private Launcher mLauncher; // private MultiModeController mMultiModeController = null; private MultiModeController mMultiModeController = null; public static LauncherAppMonitor getInstance(final Context context) { return INSTANCE.get(context.getApplicationContext()); Loading Loading @@ -94,9 +95,10 @@ public class LauncherAppMonitor extends LauncherApps.Callback } } private LauncherAppMonitor(Context context) { LauncherPrefs.get(context).addListener(this); // mMultiModeController = new MultiModeController(context, this); public LauncherAppMonitor(Context context) { context.getSystemService(LauncherApps.class).registerCallback(this); LauncherPrefs.getPrefs(context).registerOnSharedPreferenceChangeListener(this); mMultiModeController = new MultiModeController(context, this); } @Override Loading Loading @@ -470,4 +472,8 @@ public class LauncherAppMonitor extends LauncherApps.Callback @Override public void onAppSharedPreferenceChanged(@Nullable String key) { } public MultiModeController getMultiModeController() { return mMultiModeController; } } No newline at end of file
bliss/src/foundation/e/bliss/multimode/MultiModeController.kt 0 → 100644 +112 −0 Original line number Diff line number Diff line /* * Copyright © MURENA SAS 2023. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.bliss.multimode import android.content.Context import android.content.SharedPreferences import android.content.res.Resources import android.util.Log import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherPrefs import com.android.launcher3.R import com.android.launcher3.model.data.AppInfo import com.android.launcher3.util.Executors.MODEL_EXECUTOR import foundation.e.bliss.BaseController import foundation.e.bliss.LauncherAppMonitor import foundation.e.bliss.LauncherAppMonitorCallback import foundation.e.bliss.preferences.BlissPrefs import java.io.FileDescriptor import java.io.PrintWriter class MultiModeController(val context: Context, val monitor: LauncherAppMonitor) : BaseController { private val idp by lazy { InvariantDeviceProfile.INSTANCE.get(context) } private val mAppMonitorCallback: LauncherAppMonitorCallback = object : LauncherAppMonitorCallback { override fun onLoadAllAppsEnd(apps: ArrayList<AppInfo?>?) { MODEL_EXECUTOR.submit( VerifyIdleAppTask( context, apps, null, null, false, monitor.launcher.model.mBgDataModel ) ) } override fun onAppSharedPreferenceChanged(key: String?) { when (key) { BlissPrefs.PREF_SINGLE_LAYER_MODE -> { monitor.launcher.model.forceReload() } else -> Unit } } override fun dump( prefix: String?, fd: FileDescriptor?, w: PrintWriter?, dumpAll: Boolean ) { w?.let { println() println("$prefix $TAG: ${this@MultiModeController}") } } } init { sharedPreferences = LauncherPrefs.getPrefs(context) resources = context.resources monitor.registerCallback(mAppMonitorCallback) Log.d(TAG, this.toString()) } override fun dumpState( prefix: String?, fd: FileDescriptor?, writer: PrintWriter?, dumpAll: Boolean ) { writer?.let { println() println("$prefix $TAG: ${this@MultiModeController}") } } companion object { private const val TAG = "MultiModeController" @JvmField var sharedPreferences: SharedPreferences? = null @JvmField var resources: Resources? = null private fun throwIfControllerNotInit() { val launcherAppMonitor = LauncherAppMonitor.getInstanceNoCreate() if (launcherAppMonitor == null || launcherAppMonitor.multiModeController == null) { throw RuntimeException("MultiModeController is not init.") } } @JvmStatic val isSingleLayerMode: Boolean get() { throwIfControllerNotInit() return sharedPreferences!! .getBoolean( BlissPrefs.PREF_SINGLE_LAYER_MODE, resources!!.getBoolean(R.bool.default_single_mode) ) .apply { Log.d(TAG, "Single Layer Mode (getter): $this") return@apply } } } }
bliss/src/foundation/e/bliss/multimode/VerifyIdleAppTask.java 0 → 100644 +124 −0 Original line number Diff line number Diff line /* * Copyright © MURENA SAS 2023. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.bliss.multimode; import android.content.ComponentName; import android.content.Context; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.os.UserHandle; import android.util.Log; import android.util.Pair; import androidx.annotation.WorkerThread; import com.android.launcher3.LauncherAppState; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ItemInfoMatcher; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.function.Predicate; @WorkerThread public class VerifyIdleAppTask implements Runnable { private static final String TAG = "VerifyIdleAppTask"; private final Context mContext; private final Collection<AppInfo> mApps; private final String mPackageNames; private final UserHandle mUser; private final boolean mIsAddPackage; private boolean mIgnoreLoaded; private BgDataModel mBgdataModel; public VerifyIdleAppTask(Context context, Collection<AppInfo> apps, String packageNames, UserHandle user, boolean isAdd, BgDataModel bgDataModel) { mContext = context; mApps = apps; mPackageNames = packageNames; mUser = user; mIsAddPackage = isAdd; mBgdataModel = bgDataModel; } private static void verifyShortcutHighRes(Context context, AppInfo appInfo) { if (appInfo != null) { if (appInfo.usingLowResIcon()) { LauncherAppState.getInstance(context).getIconCache().getTitleAndIcon(appInfo, false); } } } @Override public void run() { if (!MultiModeController.isSingleLayerMode()) { return; } final Map<ComponentKey, Object> map = new HashMap<>(); if (mApps != null && mApps.size() > 0) { // All apps loading, we ignore loaded. mIgnoreLoaded = true; for (AppInfo app : mApps) { map.put(new ComponentKey(app.componentName, app.user), app); } } else if (mPackageNames != null && mUser != null) { // App add or update, should not ignore loaded. mIgnoreLoaded = false; final LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); if (mIsAddPackage || launcherApps.isPackageEnabled(mPackageNames, mUser)) { final List<LauncherActivityInfo> infos = launcherApps.getActivityList(mPackageNames, mUser); for (LauncherActivityInfo info : infos) { map.put(new ComponentKey(info.getComponentName(), info.getUser()), info); } } } verifyAllApps(mContext, map, mIsAddPackage); } List<Pair<ItemInfo, Object>> verifyAllApps(Context context, Map<ComponentKey, Object> map, boolean animated) { List<Pair<ItemInfo, Object>> newItems = new ArrayList<>(); synchronized (mBgdataModel) { for (Map.Entry<ComponentKey, Object> entry : map.entrySet()) { ComponentKey componentKey = entry.getKey(); HashSet<ComponentName> components = new HashSet<>(1); components.add(componentKey.componentName); Predicate<ItemInfo> matcher = ItemInfoMatcher.ofComponents(components, componentKey.user); if (mBgdataModel.workspaceItems.stream().noneMatch(matcher)) { Object obj = entry.getValue(); if (obj instanceof AppInfo) { verifyShortcutHighRes(context, (AppInfo) obj); newItems.add(Pair.create((AppInfo) obj, null)); } else if (obj instanceof LauncherActivityInfo) { LauncherActivityInfo info = (LauncherActivityInfo) obj; newItems.add(new ItemInstallQueue.PendingInstallShortcutInfo( info.getApplicationInfo().packageName, info.getUser()).getItemInfo(context)); } Log.d(TAG, "will bind " + componentKey.componentName + " to workspace."); } } } LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); if (appState != null && newItems.size() > 0) { appState.getModel().addAndBindAddedWorkspaceItems(newItems, animated, mIgnoreLoaded); } return newItems; } } No newline at end of file
bliss/src/foundation/e/bliss/preferences/BlissPrefs.kt 0 → 100644 +12 −0 Original line number Diff line number Diff line /* * Copyright © MURENA SAS 2023. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package foundation.e.bliss.preferences object BlissPrefs { const val PREF_SINGLE_LAYER_MODE = "pref_single_layer" }