feat : Initial implementation Caddy (#5166)

- Introduced "Caddy" functionality to organize apps within the app drawer.
- Allows grouping of applications for better accessibility and user experience.
- Serves as a foundational feature for enhancing app drawer usability.
This commit is contained in:
John Andrew Camu
2025-01-15 13:01:51 +08:00
committed by GitHub
parent f96ffc9cd4
commit 448d718e6a
16 changed files with 383 additions and 16 deletions
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ This file is part of Lawnchair Launcher.
~
~ Lawnchair Launcher is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ Lawnchair Launcher is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with Lawnchair Launcher. If not, see <https://www.gnu.org/licenses/>.
-->
<com.android.launcher3.BubbleTextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
style="@style/BaseIcon"
android:includeFontPadding="false"
launcher:iconDisplay="drawer_folder" />
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ This file is part of Lawnchair Launcher.
~
~ Lawnchair Launcher is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ Lawnchair Launcher is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with Lawnchair Launcher. If not, see <https://www.gnu.org/licenses/>.
-->
<com.android.launcher3.folder.FolderIcon
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:paddingLeft="@dimen/dynamic_grid_cell_padding_x"
android:paddingRight="@dimen/dynamic_grid_cell_padding_x"
android:focusable="true" >
<com.android.launcher3.BubbleTextView
style="@style/BaseIcon"
android:id="@+id/folder_icon_name"
android:focusable="false"
android:layout_gravity="top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:iconDisplay="all_apps"/>
</com.android.launcher3.folder.FolderIcon>
+4
View File
@@ -59,6 +59,7 @@
General "words" used throughout Lawnchair
-->
<string name="others_category_label">Others</string>
<!-- Selection options -->
<string name="dynamic">Dynamic</string>
@@ -90,6 +91,9 @@
<string name="wallpapers">Wallpapers</string>
<string name="caddy_beta">Caddy (Beta)</string>
<string name="caddy">Caddy</string>
<!-- A11y description -->
<string name="accessibility_service_description">To lock your phone when performing a gesture, and to open Recents via gesture, Lawnchair requires accessibility access.\n\nLawnchair doesn\'t watch any user action, though the privilege to do so is required for all accessibility services. Lawnchair discards any event sent by the system.\n\nIn order to lock your phone, or to open Recents, Lawnchair uses the performGlobalAction Accessibility service.</string>
@@ -4,19 +4,23 @@ import android.content.Context
import android.util.Log
import androidx.lifecycle.lifecycleScope
import app.lawnchair.launcher
import app.lawnchair.preferences.PreferenceManager
import app.lawnchair.preferences2.PreferenceManager2
import app.lawnchair.util.categorizeApps
import com.android.launcher3.allapps.AllAppsStore
import com.android.launcher3.allapps.AlphabeticalAppsList
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem
import com.android.launcher3.allapps.PrivateProfileManager
import com.android.launcher3.allapps.WorkProfileManager
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.views.ActivityContext
import com.patrykmichalik.opto.core.onEach
import java.util.function.Predicate
class LawnchairAlphabeticalAppsList<T>(
context: T,
private val context: T,
appsStore: AllAppsStore<T>,
workProfileManager: WorkProfileManager?,
privateProfileManager: PrivateProfileManager?,
@@ -24,11 +28,11 @@ class LawnchairAlphabeticalAppsList<T>(
where T : Context, T : ActivityContext {
private var hiddenApps: Set<String> = setOf()
private val prefs = PreferenceManager2.getInstance(context)
private val prefs2 = PreferenceManager2.getInstance(context)
private val prefs = PreferenceManager.getInstance(context)
init {
try {
prefs.hiddenApps.onEach(launchIn = context.launcher.lifecycleScope) {
prefs2.hiddenApps.onEach(launchIn = context.launcher.lifecycleScope) {
hiddenApps = it
onAppsUpdated()
}
@@ -45,4 +49,35 @@ class LawnchairAlphabeticalAppsList<T>(
}
onAppsUpdated()
}
override fun addAppsWithSections(appList: List<AppInfo?>?, startPosition: Int): Int {
if (appList.isNullOrEmpty()) return startPosition
val drawerListDefault = prefs.drawerList.get()
var position = startPosition
if (!drawerListDefault) {
val categorizedApps = categorizeApps(context, appList)
if (categorizedApps.isNotEmpty()) {
for ((category, apps) in categorizedApps) {
if (apps.size <= 1) {
val app = apps[0]
mAdapterItems.add(AdapterItem.asApp(app))
} else {
val folderInfo = FolderInfo()
folderInfo.title = category
for (app in apps) {
folderInfo.add(app)
}
mAdapterItems.add(AdapterItem.asFolder(folderInfo))
}
position++
}
}
} else {
position = super.addAppsWithSections(appList, startPosition)
}
return position
}
}
@@ -115,6 +115,8 @@ class PreferenceManager private constructor(private val context: Context) :
val wallpaperBlur = IntPref("pref_wallpaperBlur", 25, recreate)
val wallpaperBlurFactorThreshold = FloatPref("pref_wallpaperBlurFactor", 3.0F, recreate)
val drawerList = BoolPref("pref_drawerList", true, recreate)
val recentsActionScreenshot = BoolPref("pref_recentsActionScreenshot", !isOnePlusStock)
val recentsActionShare = BoolPref("pref_recentsActionShare", isOnePlusStock)
val recentsActionLens = BoolPref("pref_recentsActionLens", true)
@@ -53,6 +53,7 @@ fun AppDrawerPreferences(
backArrowVisible = !LocalIsExpandedScreen.current,
modifier = modifier,
) {
AppDrawerSettings()
PreferenceGroup(heading = stringResource(id = R.string.general_label)) {
ColorPreference(preference = prefs2.appDrawerBackgroundColor)
SliderPreference(
@@ -0,0 +1,186 @@
package app.lawnchair.ui.preferences.destinations
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import app.lawnchair.preferences.preferenceManager
import com.android.launcher3.R
@Composable
fun AppDrawerSettings(
modifier: Modifier = Modifier,
) {
val prefs = preferenceManager()
val context = LocalContext.current
val resources = context.resources
var selectedOption by remember { mutableStateOf(prefs.drawerList.get()) }
Row(
modifier = modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.background)
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
) {
ButtonSection(
modifier = Modifier,
label = resources.getString(R.string.feed_default),
isSelected = selectedOption,
onClick = {
selectedOption = true
prefs.drawerList.set(true)
},
gridLayout = {
Column(modifier = Modifier, horizontalAlignment = Alignment.CenterHorizontally) {
Row(
modifier = Modifier,
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
repeat(4) {
Box(
modifier = Modifier
.size(16.dp)
.background(
MaterialTheme.colorScheme.surfaceVariant,
CircleShape,
),
)
}
}
}
},
)
Spacer(modifier = Modifier.width(16.dp))
ButtonSection(
modifier = Modifier,
label = resources.getString(R.string.caddy_beta),
isSelected = !selectedOption,
onClick = {
selectedOption = false
prefs.drawerList.set(false)
},
gridLayout = {
Column(modifier = Modifier, horizontalAlignment = Alignment.CenterHorizontally) {
Row(
modifier = Modifier,
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
repeat(2) {
Box(
modifier = Modifier
.size(16.dp)
.background(
MaterialTheme.colorScheme.surfaceVariant,
CircleShape,
),
)
}
}
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier,
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
repeat(2) {
Box(
modifier = Modifier
.size(16.dp)
.background(
MaterialTheme.colorScheme.surfaceVariant,
CircleShape,
),
)
}
}
}
},
)
}
}
@Composable
fun ButtonSection(
label: String,
isSelected: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
gridLayout: @Composable () -> Unit,
) {
val backgroundColor by animateColorAsState(
targetValue = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceContainer,
animationSpec = tween(durationMillis = 300),
)
val textColor by animateColorAsState(
targetValue = if (isSelected) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurface,
animationSpec = tween(durationMillis = 300),
)
Box(
modifier = modifier
.size(160.dp, 120.dp)
.background(backgroundColor, RoundedCornerShape(16.dp))
.clickable { onClick() }
.padding(12.dp),
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
modifier = Modifier
.height(24.dp)
.fillMaxWidth(0.8f)
.background(MaterialTheme.colorScheme.surfaceVariant, RoundedCornerShape(8.dp)),
)
gridLayout()
Text(
modifier = Modifier,
text = label,
color = textColor,
fontSize = 14.sp,
)
}
}
}
@Preview(showBackground = true)
@Composable
private fun PreviewToggleSelectionUI() {
Surface {
AppDrawerSettings()
}
}
@@ -17,6 +17,7 @@
package app.lawnchair.util
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
import android.graphics.Bitmap
@@ -29,6 +30,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import com.android.launcher3.AppFilter
import com.android.launcher3.LauncherAppState
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.pm.UserCache
@@ -76,3 +78,22 @@ class App(context: Context, private val info: LauncherActivityInfo) {
}
val appComparator: Comparator<App> = comparing { it.label.lowercase(Locale.getDefault()) }
val packageInfoCache = mutableMapOf<String, ApplicationInfo>()
fun categorizeApps(context: Context, appList: List<AppInfo?>?): Map<String, List<AppInfo>> {
val categories = mutableMapOf<String, MutableList<AppInfo>>()
val validAppList = appList?.filterNotNull() ?: emptyList()
for (appInfo in validAppList) {
val packageName = appInfo.targetPackage!!
val applicationInfo = packageInfoCache.getOrPut(packageName) {
context.packageManager.getApplicationInfo(packageName, 0)
}
val categoryTitle = ApplicationInfo.getCategoryTitle(context, applicationInfo.category) ?: context.resources.getString(R.string.others_category_label)
val categoryList = categories.getOrPut(categoryTitle.toString()) { mutableListOf() }
if (!categoryList.contains(appInfo)) {
categoryList.add(appInfo)
}
}
return categories.toSortedMap().mapValues { it.value }
}
+1
View File
@@ -94,6 +94,7 @@
<enum name="search_result_small" value="7" />
<enum name="prediction_row" value="8" />
<enum name="search_result_app_row" value="9" />
<enum name="drawer_folder" value="10"/>
</attr>
<attr name="centerVertically" format="boolean" />
</declare-styleable>
@@ -116,6 +116,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
public static final int DISPLAY_PREDICTION_ROW = 8;
public static final int DISPLAY_SEARCH_RESULT_APP_ROW = 9;
private static final int DISPLAY_DRAWER_FOLDER = 10;
private static final float MIN_LETTER_SPACING = -0.05f;
private static final int MAX_SEARCH_LOOP_COUNT = 20;
private static final Character NEW_LINE = '\n';
@@ -250,7 +252,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
defaultIconSize = mDeviceProfile.iconSizePx;
setCenterVertically(mDeviceProfile.iconCenterVertically);
} else if (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW
|| mDisplay == DISPLAY_SEARCH_RESULT_APP_ROW) {
|| mDisplay == DISPLAY_SEARCH_RESULT_APP_ROW || mDisplay == DISPLAY_DRAWER_FOLDER) {
setTextSize(TypedValue.COMPLEX_UNIT_PX, mDeviceProfile.allAppsIconTextSizePx);
setCompoundDrawablePadding(mDeviceProfile.allAppsIconDrawablePaddingPx);
defaultIconSize = mDeviceProfile.allAppsIconSizePx;
@@ -92,7 +92,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
// The number of results in current adapter
private int mAccessibilityResultsCount = 0;
// The current set of adapter items
private final ArrayList<AdapterItem> mAdapterItems = new ArrayList<>();
protected final ArrayList<AdapterItem> mAdapterItems = new ArrayList<>();
// The set of sections that we allow fast-scrolling to (includes non-merged
// sections)
private final List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>();
@@ -399,7 +399,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
return position;
}
private int addAppsWithSections(List<AppInfo> appList, int startPosition) {
protected int addAppsWithSections(List<AppInfo> appList, int startPosition) {
String lastSectionName = null;
boolean hasPrivateApps = false;
int position = startPosition;
@@ -32,6 +32,7 @@ import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -44,7 +45,9 @@ import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
@@ -74,11 +77,13 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex
public static final int VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER = 1 << 7;
public static final int VIEW_TYPE_WORK_EDU_CARD = 1 << 8;
public static final int NEXT_ID = 8;
public static final int VIEW_TYPE_FOLDER = 1 << 9;
public static final int NEXT_ID = 10;
// Common view type masks
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON | VIEW_TYPE_FOLDER;
public static final int VIEW_TYPE_MASK_PRIVATE_SPACE_HEADER = VIEW_TYPE_PRIVATE_SPACE_HEADER;
public static final int VIEW_TYPE_MASK_PRIVATE_SPACE_SYS_APPS_DIVIDER = VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
@@ -115,6 +120,8 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex
public int rowAppIndex;
// The associated ItemInfoWithIcon for the item
public AppInfo itemInfo = new AppInfo();
public FolderInfo folderInfo = new FolderInfo();
// Private App Decorator
public SectionDecorationInfo decorationInfo = null;
@@ -131,6 +138,12 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex
item.itemInfo = appInfo;
return item;
}
public static AdapterItem asFolder(FolderInfo folderInfo) {
AdapterItem item = new AdapterItem(VIEW_TYPE_FOLDER);
item.folderInfo = folderInfo;
return item;
}
public static AdapterItem asAppWithDecorationInfo(AppInfo appInfo,
SectionDecorationInfo decorationInfo) {
@@ -140,7 +153,7 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex
}
protected boolean isCountedForAccessibility() {
return viewType == VIEW_TYPE_ICON;
return viewType == VIEW_TYPE_ICON || viewType == VIEW_TYPE_FOLDER;
}
/**
@@ -257,6 +270,12 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex
case VIEW_TYPE_PRIVATE_SPACE_HEADER:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.private_space_header, parent, false));
case VIEW_TYPE_FOLDER:
FrameLayout fl = new FrameLayout(mActivityContext);
ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
return new ViewHolder(fl);
default:
if (mAdapterProvider.isViewSupported(viewType)) {
return mAdapterProvider.onCreateViewHolder(mLayoutInflater, parent, viewType);
@@ -333,6 +352,13 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex
case VIEW_TYPE_WORK_EDU_CARD:
((WorkEduCard) holder.itemView).setPosition(position);
break;
case VIEW_TYPE_FOLDER:
FolderInfo folderInfo = mApps.getAdapterItems().get(position).folderInfo;
ViewGroup container = (ViewGroup) holder.itemView;
container.removeAllViews();
container.addView(FolderIcon.inflateFolderAndIcon(R.layout.all_apps_folder_icon, mActivityContext,
container, folderInfo));
break;
default:
if (mAdapterProvider.isViewSupported(holder.getItemViewType())) {
mAdapterProvider.onBindView(holder, position);
+8 -2
View File
@@ -403,6 +403,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
if (dragObject.dragSource != this) {
return;
}
if (isInAppDrawer()) close(true);
mContent.removeItem(mCurrentDragView);
mItemsInvalidated = true;
@@ -415,6 +417,10 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
mItemAddedBackToSelfViaIcon = false;
}
public boolean isInAppDrawer() {
return mInfo.container == ItemInfo.NO_ID;
}
@Override
public void onDragEnd() {
if (mIsExternalDrag && mIsDragInProgress) {
@@ -583,7 +589,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
}
// In case any children didn't come across during loading, clean up the folder accordingly
mFolderIcon.post(() -> {
if (getItemCount() <= 1) {
if (getItemCount() <= 1 && !isInAppDrawer()) {
replaceFolderWithFinalItem();
}
});
@@ -971,7 +977,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
mRearrangeOnClose = false;
}
if (getItemCount() <= 1) {
if (!mIsDragInProgress && !mSuppressFolderDeletion) {
if (!mIsDragInProgress && !mSuppressFolderDeletion && !isInAppDrawer()) {
replaceFolderWithFinalItem();
} else if (mIsDragInProgress) {
mDeleteFolderOnDropCompleted = true;
@@ -207,7 +207,12 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
icon.mFolderName.setText(folderInfo.title);
icon.mFolderName.setCompoundDrawablePadding(0);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mFolderName.getLayoutParams();
lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
if (folderInfo.container == ItemInfo.NO_ID) {
lp.topMargin = grid.allAppsIconSizePx + grid.allAppsIconDrawablePaddingPx;
icon.mBackground = new PreviewBackground(activity.getDragLayer().getContext());
} else {
lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
}
icon.setTag(folderInfo);
icon.setOnClickListener(activity.getItemOnClickListener());
@@ -344,7 +349,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
final Launcher launcher = (Launcher) mActivity;
DragLayer dragLayer = launcher.getDragLayer();
Rect to = finalRect;
if (to == null) {
if (to == null && !isInAppDrawer()) {
to = new Rect();
Workspace<?> workspace = launcher.getWorkspace();
// Set cellLayout and this to it's final state to compute final animation locations
@@ -434,6 +439,10 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
addItem(item);
}
}
public boolean isInAppDrawer() {
return mInfo.container == ItemInfo.NO_ID;
}
/**
* Set the suggested folder name.
@@ -772,12 +781,14 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
}
public void clearLeaveBehindIfExists() {
if (isInAppDrawer()) return;
if (getParent() instanceof FolderIconParent) {
((FolderIconParent) getParent()).clearFolderLeaveBehind(this);
}
}
public void drawLeaveBehindIfExists() {
if (isInAppDrawer()) return;
if (getParent() instanceof FolderIconParent) {
((FolderIconParent) getParent()).drawFolderLeaveBehindForIcon(this);
}
@@ -37,6 +37,7 @@ import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Item;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
@@ -46,6 +47,7 @@ import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pageindicators.PageIndicatorDots;
import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
@@ -225,8 +227,13 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> implements Cli
icon = AppPairIcon.inflateIcon(R.layout.folder_app_pair, ActivityContext.lookupContext(
getContext()), null , api, BubbleTextView.DISPLAY_FOLDER);
} else {
icon = mViewCache.getView(R.layout.folder_application, getContext(), null);
((BubbleTextView) icon).applyFromWorkspaceItem((WorkspaceItemInfo) item);
if (mFolder.isInAppDrawer()) {
icon = mViewCache.getView(R.layout.all_apps_folder_application, getContext(), null);
((BubbleTextView) icon).applyFromItemInfoWithIcon((ItemInfoWithIcon) item);
} else {
icon = mViewCache.getView(R.layout.folder_application, getContext(), null);
((BubbleTextView) icon).applyFromWorkspaceItem((WorkspaceItemInfo) item);
}
}
icon.setOnClickListener(mFolder.mActivityContext.getItemOnClickListener());
@@ -35,6 +35,7 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.FloatProperty;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
@@ -47,6 +48,7 @@ import com.android.launcher3.apppairs.AppPairIconDrawingParams;
import com.android.launcher3.apppairs.AppPairIconGraphic;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -463,6 +465,10 @@ public class PreviewItemManager {
AppPairIconDrawingParams appPairParams = new AppPairIconDrawingParams(mContext, DISPLAY_FOLDER);
p.drawable = AppPairIconGraphic.composeDrawable(api, appPairParams);
p.drawable.setBounds(0, 0, mIconSize, mIconSize);
} else if (item instanceof ItemInfoWithIcon withIcon){
p.drawable = withIcon.newIcon(mContext,
Themes.isThemedIconEnabled(mContext) ? FLAG_THEMED : 0);
p.drawable.setBounds(0, 0, mIconSize, mIconSize);
}
p.item = item;