Adds additional folder label states (UNLABELED & EMPTY_LABEL)
UNLABELED -> title==null and EMPTY_LABEL -> title=="". When adding new items for the folder if the folder is in UNLABELED state, auto-labeling will be enabled. This change also addresses auto-labeling issue due to false edit from UNLABELED to EMPTY. Bug: 159164315 Change-Id: Ia17cd27b4afb60420dc15c544f544061fc46ad33
This commit is contained in:
parent
5c9a1ef5cd
commit
ec75cbd85a
|
@ -96,8 +96,21 @@ enum Attribute {
|
||||||
ADD_TO_HOMESCREEN = 6; // play install + launcher home setting
|
ADD_TO_HOMESCREEN = 6; // play install + launcher home setting
|
||||||
ALLAPPS_PREDICTION = 7; // from prediction bar in all apps container
|
ALLAPPS_PREDICTION = 7; // from prediction bar in all apps container
|
||||||
HOTSEAT_PREDICTION = 8; // from prediction bar in hotseat container
|
HOTSEAT_PREDICTION = 8; // from prediction bar in hotseat container
|
||||||
SUGGESTED_LABEL = 9; // folder icon's label was suggested
|
|
||||||
MANUAL_LABEL = 10; // folder icon's label was manually edited
|
// Folder's label is one of the non-empty suggested values.
|
||||||
|
SUGGESTED_LABEL = 9;
|
||||||
|
|
||||||
|
// Folder's label is non-empty, manually entered by the user
|
||||||
|
// and different from any of suggested values.
|
||||||
|
MANUAL_LABEL = 10;
|
||||||
|
|
||||||
|
// Folder's label is not yet assigned( i.e., title == null).
|
||||||
|
// Eligible for auto-labeling.
|
||||||
|
UNLABELED = 11;
|
||||||
|
|
||||||
|
// Folder's label is empty(i.e., title == "").
|
||||||
|
// Not eligible for auto-labeling.
|
||||||
|
EMPTY_LABEL = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main app icons
|
// Main app icons
|
||||||
|
|
|
@ -114,9 +114,9 @@ public class HotseatEduController {
|
||||||
if (!putIntoFolder.isEmpty()) {
|
if (!putIntoFolder.isEmpty()) {
|
||||||
ItemInfo firstItem = putIntoFolder.get(0);
|
ItemInfo firstItem = putIntoFolder.get(0);
|
||||||
FolderInfo folderInfo = new FolderInfo();
|
FolderInfo folderInfo = new FolderInfo();
|
||||||
folderInfo.setTitle("");
|
|
||||||
mLauncher.getModelWriter().addItemToDatabase(folderInfo, firstItem.container,
|
mLauncher.getModelWriter().addItemToDatabase(folderInfo, firstItem.container,
|
||||||
firstItem.screenId, firstItem.cellX, firstItem.cellY);
|
firstItem.screenId, firstItem.cellX, firstItem.cellY);
|
||||||
|
folderInfo.setTitle("", mLauncher.getModelWriter());
|
||||||
folderInfo.contents.addAll(putIntoFolder);
|
folderInfo.contents.addAll(putIntoFolder);
|
||||||
for (int i = 0; i < folderInfo.contents.size(); i++) {
|
for (int i = 0; i < folderInfo.contents.size(); i++) {
|
||||||
ItemInfo item = folderInfo.contents.get(i);
|
ItemInfo item = folderInfo.contents.get(i);
|
||||||
|
|
|
@ -26,7 +26,6 @@ import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTI
|
||||||
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
|
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED;
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED;
|
||||||
import static com.android.launcher3.model.data.FolderInfo.FLAG_MANUAL_FOLDER_NAME;
|
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
@ -339,11 +338,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "onBackKey newTitle=" + newTitle);
|
Log.d(TAG, "onBackKey newTitle=" + newTitle);
|
||||||
}
|
}
|
||||||
mInfo.setTitle(newTitle);
|
mInfo.setTitle(newTitle, mLauncher.getModelWriter());
|
||||||
mInfo.setOption(FLAG_MANUAL_FOLDER_NAME, !mInfo.getAcceptedSuggestionIndex().isPresent(),
|
|
||||||
mLauncher.getModelWriter());
|
|
||||||
mFolderIcon.onTitleChanged(newTitle);
|
mFolderIcon.onTitleChanged(newTitle);
|
||||||
mLauncher.getModelWriter().updateItemInDatabase(mInfo);
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(mInfo.title)) {
|
if (TextUtils.isEmpty(mInfo.title)) {
|
||||||
mFolderName.setHint(R.string.folder_hint_text);
|
mFolderName.setHint(R.string.folder_hint_text);
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package com.android.launcher3.folder;
|
package com.android.launcher3.folder;
|
||||||
|
|
||||||
import static android.text.TextUtils.isEmpty;
|
|
||||||
|
|
||||||
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
|
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
|
||||||
import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMATION_DURATION;
|
import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMATION_DURATION;
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELED;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELED;
|
||||||
|
@ -72,6 +70,7 @@ import com.android.launcher3.logging.StatsLogManager;
|
||||||
import com.android.launcher3.model.data.AppInfo;
|
import com.android.launcher3.model.data.AppInfo;
|
||||||
import com.android.launcher3.model.data.FolderInfo;
|
import com.android.launcher3.model.data.FolderInfo;
|
||||||
import com.android.launcher3.model.data.FolderInfo.FolderListener;
|
import com.android.launcher3.model.data.FolderInfo.FolderListener;
|
||||||
|
import com.android.launcher3.model.data.FolderInfo.LabelState;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
import com.android.launcher3.touch.ItemClickHandler;
|
import com.android.launcher3.touch.ItemClickHandler;
|
||||||
|
@ -443,8 +442,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||||
if (!FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
|
if (!FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isEmpty(mFolderName.getText().toString())
|
if (!mInfo.getLabelState().equals(LabelState.UNLABELED)) {
|
||||||
|| mInfo.hasOption(FolderInfo.FLAG_MANUAL_FOLDER_NAME)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (nameInfos == null || !nameInfos.hasSuggestions()) {
|
if (nameInfos == null || !nameInfos.hasSuggestions()) {
|
||||||
|
@ -464,10 +462,9 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||||
CharSequence newTitle = nameInfos.getLabels()[0];
|
CharSequence newTitle = nameInfos.getLabels()[0];
|
||||||
FromState fromState = mInfo.getFromLabelState();
|
FromState fromState = mInfo.getFromLabelState();
|
||||||
|
|
||||||
mInfo.setTitle(newTitle);
|
mInfo.setTitle(newTitle, mFolder.mLauncher.getModelWriter());
|
||||||
onTitleChanged(mInfo.title);
|
onTitleChanged(mInfo.title);
|
||||||
mFolder.mFolderName.setText(mInfo.title);
|
mFolder.mFolderName.setText(mInfo.title);
|
||||||
mFolder.mLauncher.getModelWriter().updateItemInDatabase(mInfo);
|
|
||||||
|
|
||||||
// Logging for folder creation flow
|
// Logging for folder creation flow
|
||||||
StatsLogManager.newInstance(getContext()).logger()
|
StatsLogManager.newInstance(getContext()).logger()
|
||||||
|
|
|
@ -22,6 +22,7 @@ import static androidx.core.util.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
|
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
|
||||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
|
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
|
||||||
|
import static com.android.launcher3.logger.LauncherAtom.Attribute.EMPTY_LABEL;
|
||||||
import static com.android.launcher3.logger.LauncherAtom.Attribute.MANUAL_LABEL;
|
import static com.android.launcher3.logger.LauncherAtom.Attribute.MANUAL_LABEL;
|
||||||
import static com.android.launcher3.logger.LauncherAtom.Attribute.SUGGESTED_LABEL;
|
import static com.android.launcher3.logger.LauncherAtom.Attribute.SUGGESTED_LABEL;
|
||||||
import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_CUSTOM;
|
import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_CUSTOM;
|
||||||
|
@ -31,11 +32,14 @@ import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolder
|
||||||
|
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.launcher3.LauncherSettings;
|
import com.android.launcher3.LauncherSettings;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.folder.FolderNameInfos;
|
import com.android.launcher3.folder.FolderNameInfos;
|
||||||
import com.android.launcher3.logger.LauncherAtom;
|
import com.android.launcher3.logger.LauncherAtom;
|
||||||
|
import com.android.launcher3.logger.LauncherAtom.Attribute;
|
||||||
import com.android.launcher3.logger.LauncherAtom.FromState;
|
import com.android.launcher3.logger.LauncherAtom.FromState;
|
||||||
import com.android.launcher3.logger.LauncherAtom.ToState;
|
import com.android.launcher3.logger.LauncherAtom.ToState;
|
||||||
import com.android.launcher3.model.ModelWriter;
|
import com.android.launcher3.model.ModelWriter;
|
||||||
|
@ -74,6 +78,30 @@ public class FolderInfo extends ItemInfo {
|
||||||
|
|
||||||
public static final int FLAG_MANUAL_FOLDER_NAME = 0x00000008;
|
public static final int FLAG_MANUAL_FOLDER_NAME = 0x00000008;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Different states of folder label.
|
||||||
|
*/
|
||||||
|
public enum LabelState {
|
||||||
|
// Folder's label is not yet assigned( i.e., title == null). Eligible for auto-labeling.
|
||||||
|
UNLABELED(Attribute.UNLABELED),
|
||||||
|
|
||||||
|
// Folder's label is empty(i.e., title == ""). Not eligible for auto-labeling.
|
||||||
|
EMPTY(EMPTY_LABEL),
|
||||||
|
|
||||||
|
// Folder's label is one of the non-empty suggested values.
|
||||||
|
SUGGESTED(SUGGESTED_LABEL),
|
||||||
|
|
||||||
|
// Folder's label is non-empty, manually entered by the user
|
||||||
|
// and different from any of suggested values.
|
||||||
|
MANUAL(MANUAL_LABEL);
|
||||||
|
|
||||||
|
private final LauncherAtom.Attribute mLogAttribute;
|
||||||
|
|
||||||
|
LabelState(Attribute logAttribute) {
|
||||||
|
this.mLogAttribute = logAttribute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static final String EXTRA_FOLDER_SUGGESTIONS = "suggest";
|
public static final String EXTRA_FOLDER_SUGGESTIONS = "suggest";
|
||||||
|
|
||||||
public int options;
|
public int options;
|
||||||
|
@ -176,8 +204,7 @@ public class FolderInfo extends ItemInfo {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String dumpProperties() {
|
protected String dumpProperties() {
|
||||||
return super.dumpProperties()
|
return String.format("%s; labelState=%s", super.dumpProperties(), getLabelState());
|
||||||
+ " manuallyTypedTitle=" + hasOption(FLAG_MANUAL_FOLDER_NAME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -185,14 +212,41 @@ public class FolderInfo extends ItemInfo {
|
||||||
return getDefaultItemInfoBuilder()
|
return getDefaultItemInfoBuilder()
|
||||||
.setFolderIcon(LauncherAtom.FolderIcon.newBuilder().setCardinality(contents.size()))
|
.setFolderIcon(LauncherAtom.FolderIcon.newBuilder().setCardinality(contents.size()))
|
||||||
.setRank(rank)
|
.setRank(rank)
|
||||||
.setAttribute(hasOption(FLAG_MANUAL_FOLDER_NAME) ? MANUAL_LABEL : SUGGESTED_LABEL)
|
.setAttribute(getLabelState().mLogAttribute)
|
||||||
.setContainerInfo(getContainerInfo())
|
.setContainerInfo(getContainerInfo())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTitle(CharSequence title) {
|
public void setTitle(@Nullable CharSequence title, ModelWriter modelWriter) {
|
||||||
|
// Updating label from null to empty is considered as false touch.
|
||||||
|
// Retaining null title(ie., UNLABELED state) allows auto-labeling when new items added.
|
||||||
|
if (isEmpty(title) && this.title == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updating title to same value does not change any states.
|
||||||
|
if (title != null && title == this.title) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
LabelState newLabelState =
|
||||||
|
title == null ? LabelState.UNLABELED
|
||||||
|
: title.length() == 0 ? LabelState.EMPTY :
|
||||||
|
getAcceptedSuggestionIndex().isPresent() ? LabelState.SUGGESTED
|
||||||
|
: LabelState.MANUAL;
|
||||||
|
setOption(FLAG_MANUAL_FOLDER_NAME, newLabelState.equals(LabelState.MANUAL), modelWriter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current state of the current folder label.
|
||||||
|
*/
|
||||||
|
public LabelState getLabelState() {
|
||||||
|
return title == null ? LabelState.UNLABELED
|
||||||
|
: title.length() == 0 ? LabelState.EMPTY :
|
||||||
|
hasOption(FLAG_MANUAL_FOLDER_NAME) ? LabelState.MANUAL
|
||||||
|
: LabelState.SUGGESTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -233,13 +287,17 @@ public class FolderInfo extends ItemInfo {
|
||||||
* Returns {@link FromState} based on current {@link #title}.
|
* Returns {@link FromState} based on current {@link #title}.
|
||||||
*/
|
*/
|
||||||
public LauncherAtom.FromState getFromLabelState() {
|
public LauncherAtom.FromState getFromLabelState() {
|
||||||
return title == null
|
switch (getLabelState()){
|
||||||
? LauncherAtom.FromState.FROM_STATE_UNSPECIFIED
|
case EMPTY:
|
||||||
: title.length() == 0
|
return LauncherAtom.FromState.FROM_EMPTY;
|
||||||
? LauncherAtom.FromState.FROM_EMPTY
|
case MANUAL:
|
||||||
: hasOption(FLAG_MANUAL_FOLDER_NAME)
|
return LauncherAtom.FromState.FROM_CUSTOM;
|
||||||
? LauncherAtom.FromState.FROM_CUSTOM
|
case SUGGESTED:
|
||||||
: LauncherAtom.FromState.FROM_SUGGESTED;
|
return LauncherAtom.FromState.FROM_SUGGESTED;
|
||||||
|
case UNLABELED:
|
||||||
|
default:
|
||||||
|
return LauncherAtom.FromState.FROM_STATE_UNSPECIFIED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -52,6 +52,7 @@ import com.android.launcher3.logger.LauncherAtom.SearchResultContainer;
|
||||||
import com.android.launcher3.logger.LauncherAtom.SettingsContainer;
|
import com.android.launcher3.logger.LauncherAtom.SettingsContainer;
|
||||||
import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
|
import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
|
||||||
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer;
|
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer;
|
||||||
|
import com.android.launcher3.model.ModelWriter;
|
||||||
import com.android.launcher3.util.ContentWriter;
|
import com.android.launcher3.util.ContentWriter;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -405,7 +406,10 @@ public class ItemInfo {
|
||||||
return itemInfo;
|
return itemInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTitle(CharSequence title) {
|
/**
|
||||||
|
* Sets the title of the item and writes to DB model if needed.
|
||||||
|
*/
|
||||||
|
public void setTitle(CharSequence title, ModelWriter modelWriter) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue