Merge "Refactor FolderNameInfos." into ub-launcher3-rvc-dev

This commit is contained in:
Jayaprakash Sundararaj 2020-06-20 06:59:45 +00:00 committed by Android (Google) Code Review
commit d2260a07b8
8 changed files with 185 additions and 209 deletions

View File

@ -16,6 +16,7 @@
package com.android.launcher3.folder; package com.android.launcher3.folder;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@ -61,16 +62,16 @@ public final class FolderNameProviderTest {
ArrayList<WorkspaceItemInfo> list = new ArrayList<>(); ArrayList<WorkspaceItemInfo> list = new ArrayList<>();
list.add(mItem1); list.add(mItem1);
list.add(mItem2); list.add(mItem2);
FolderNameInfo[] nameInfos = FolderNameInfos nameInfos = new FolderNameInfos();
new FolderNameInfo[FolderNameProvider.SUGGEST_MAX];
new FolderNameProvider().getSuggestedFolderName(mContext, list, nameInfos); new FolderNameProvider().getSuggestedFolderName(mContext, list, nameInfos);
assertEquals("Work", nameInfos[0].getLabel()); assertEquals("Work", nameInfos.getLabels()[0]);
nameInfos[0] = new FolderNameInfo("candidate1", 0.9); nameInfos.setLabel(0, "candidate1", 1.0f);
nameInfos[1] = new FolderNameInfo("candidate2", 0.8); nameInfos.setLabel(1, "candidate2", 1.0f);
nameInfos[2] = new FolderNameInfo("candidate3", 0.7); nameInfos.setLabel(2, "candidate3", 1.0f);
new FolderNameProvider().getSuggestedFolderName(mContext, list, nameInfos); new FolderNameProvider().getSuggestedFolderName(mContext, list, nameInfos);
assertEquals("Work", nameInfos[3].getLabel()); assertEquals("Work", nameInfos.getLabels()[3]);
assertTrue(nameInfos.hasSuggestions());
assertTrue(nameInfos.hasPrimary());
} }
} }

View File

@ -28,16 +28,12 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
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 static com.android.launcher3.model.data.FolderInfo.FLAG_MANUAL_FOLDER_NAME;
import static java.util.Arrays.asList;
import static java.util.Optional.ofNullable;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet; import android.animation.AnimatorSet;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetHostView;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Path; import android.graphics.Path;
import android.graphics.Rect; import android.graphics.Rect;
@ -104,6 +100,7 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.StringJoiner; import java.util.StringJoiner;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* Represents a set of icons chosen by the user or generated by the system. * Represents a set of icons chosen by the user or generated by the system.
@ -327,11 +324,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
public void startEditingFolderName() { public void startEditingFolderName() {
post(() -> { post(() -> {
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) { if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
ofNullable(mInfo) showLabelSuggestions();
.map(info -> info.suggestedFolderNames)
.map(folderNames -> (FolderNameInfo[]) folderNames
.getParcelableArrayExtra(FolderInfo.EXTRA_FOLDER_SUGGESTIONS))
.ifPresent(this::showLabelSuggestions);
} }
mFolderName.setHint(""); mFolderName.setHint("");
mIsEditingName = true; mIsEditingName = true;
@ -461,32 +454,24 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
* Show suggested folder title in FolderEditText if the first suggestion is non-empty, push * Show suggested folder title in FolderEditText if the first suggestion is non-empty, push
* rest of the suggestions to InputMethodManager. * rest of the suggestions to InputMethodManager.
*/ */
private void showLabelSuggestions(FolderNameInfo[] nameInfos) { private void showLabelSuggestions() {
if (nameInfos == null) { if (mInfo.suggestedFolderNames == null) {
return; return;
} }
// Open the Folder and Keyboard when the first or second suggestion is valid non-empty if (mInfo.suggestedFolderNames.hasSuggestions()) {
// string.
boolean shouldOpen = nameInfos.length > 0 && nameInfos[0] != null && !isEmpty(
nameInfos[0].getLabel())
|| nameInfos.length > 1 && nameInfos[1] != null && !isEmpty(
nameInfos[1].getLabel());
if (shouldOpen) {
// update the primary suggestion if the folder name is empty. // update the primary suggestion if the folder name is empty.
if (isEmpty(mFolderName.getText())) { if (isEmpty(mFolderName.getText())) {
CharSequence firstLabel = nameInfos[0] == null ? "" : nameInfos[0].getLabel(); if (mInfo.suggestedFolderNames.hasPrimary()) {
if (!isEmpty(firstLabel)) {
mFolderName.setHint(""); mFolderName.setHint("");
mFolderName.setText(firstLabel); mFolderName.setText(mInfo.suggestedFolderNames.getLabels()[0]);
mFolderName.selectAll(); mFolderName.selectAll();
} }
} }
mFolderName.showKeyboard(); mFolderName.showKeyboard();
mFolderName.displayCompletions( mFolderName.displayCompletions(
asList(nameInfos).subList(0, nameInfos.length).stream() Stream.of(mInfo.suggestedFolderNames.getLabels())
.filter(Objects::nonNull) .filter(Objects::nonNull)
.map(s -> s.getLabel().toString()) .map(Object::toString)
.filter(s -> !s.isEmpty()) .filter(s -> !s.isEmpty())
.filter(s -> !s.equalsIgnoreCase(mFolderName.getText().toString())) .filter(s -> !s.equalsIgnoreCase(mFolderName.getText().toString()))
.collect(Collectors.toList())); .collect(Collectors.toList()));
@ -1021,14 +1006,11 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
if (FeatureFlags.FOLDER_NAME_SUGGEST.get() && !isBind if (FeatureFlags.FOLDER_NAME_SUGGEST.get() && !isBind
&& total > 1 /* no need to update if there's one icon */) { && total > 1 /* no need to update if there's one icon */) {
Executors.MODEL_EXECUTOR.post(() -> { Executors.MODEL_EXECUTOR.post(() -> {
FolderNameInfo[] nameInfos = FolderNameInfos nameInfos = new FolderNameInfos();
new FolderNameInfo[FolderNameProvider.SUGGEST_MAX];
FolderNameProvider fnp = FolderNameProvider.newInstance(getContext()); FolderNameProvider fnp = FolderNameProvider.newInstance(getContext());
fnp.getSuggestedFolderName( fnp.getSuggestedFolderName(
getContext(), mInfo.contents, nameInfos); getContext(), mInfo.contents, nameInfos);
mInfo.suggestedFolderNames = new Intent().putExtra( mInfo.suggestedFolderNames = nameInfos;
FolderInfo.EXTRA_FOLDER_SUGGESTIONS,
nameInfos);
}); });
} }
} }

View File

@ -84,7 +84,7 @@ import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Stream;
/** /**
* An icon that can appear on in the workspace representing an {@link Folder}. * An icon that can appear on in the workspace representing an {@link Folder}.
@ -411,8 +411,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
if (!itemAdded) mPreviewItemManager.hidePreviewItem(index, true); if (!itemAdded) mPreviewItemManager.hidePreviewItem(index, true);
final int finalIndex = index; final int finalIndex = index;
FolderNameInfo[] nameInfos = FolderNameInfos nameInfos = new FolderNameInfos();
new FolderNameInfo[FolderNameProvider.SUGGEST_MAX];
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) { if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
Executors.MODEL_EXECUTOR.post(() -> { Executors.MODEL_EXECUTOR.post(() -> {
d.folderNameProvider.getSuggestedFolderName( d.folderNameProvider.getSuggestedFolderName(
@ -428,7 +427,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
} }
private void showFinalView(int finalIndex, final WorkspaceItemInfo item, private void showFinalView(int finalIndex, final WorkspaceItemInfo item,
FolderNameInfo[] nameInfos, InstanceId instanceId) { FolderNameInfos nameInfos, InstanceId instanceId) {
postDelayed(() -> { postDelayed(() -> {
mPreviewItemManager.hidePreviewItem(finalIndex, false); mPreviewItemManager.hidePreviewItem(finalIndex, false);
mFolder.showItem(item); mFolder.showItem(item);
@ -440,7 +439,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
/** /**
* Set the suggested folder name. * Set the suggested folder name.
*/ */
public void setLabelSuggestion(FolderNameInfo[] nameInfos, InstanceId instanceId) { public void setLabelSuggestion(FolderNameInfos nameInfos, InstanceId instanceId) {
if (!FeatureFlags.FOLDER_NAME_SUGGEST.get()) { if (!FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
return; return;
} }
@ -448,22 +447,21 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|| mInfo.hasOption(FolderInfo.FLAG_MANUAL_FOLDER_NAME)) { || mInfo.hasOption(FolderInfo.FLAG_MANUAL_FOLDER_NAME)) {
return; return;
} }
if (nameInfos == null || Stream.of(nameInfos) if (nameInfos == null || !nameInfos.hasSuggestions()) {
.allMatch(nameInfo -> nameInfo == null || isEmpty(nameInfo.getLabel()))) {
StatsLogManager.newInstance(getContext()).logger() StatsLogManager.newInstance(getContext()).logger()
.withInstanceId(instanceId) .withInstanceId(instanceId)
.withItemInfo(mInfo) .withItemInfo(mInfo)
.log(LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_SUGGESTIONS); .log(LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_SUGGESTIONS);
return; return;
} }
if (nameInfos[0] == null || isEmpty(nameInfos[0].getLabel())) { if (!nameInfos.hasPrimary()) {
StatsLogManager.newInstance(getContext()).logger() StatsLogManager.newInstance(getContext()).logger()
.withInstanceId(instanceId) .withInstanceId(instanceId)
.withItemInfo(mInfo) .withItemInfo(mInfo)
.log(LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_PRIMARY); .log(LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_PRIMARY);
return; return;
} }
CharSequence newTitle = nameInfos[0].getLabel(); CharSequence newTitle = nameInfos.getLabels()[0];
FromState fromState = mInfo.getFromLabelState(); FromState fromState = mInfo.getFromLabelState();
mInfo.setTitle(newTitle); mInfo.setTitle(newTitle);

View File

@ -1,93 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* 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 com.android.launcher3.folder;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import androidx.annotation.NonNull;
/**
* Information about a single label suggestions of the Folder.
*/
public final class FolderNameInfo implements Parcelable {
private final double mScore;
private final CharSequence mLabel;
/**
* Create a simple completion with label.
*
* @param label The text that should be inserted into the editor and pushed to
* InputMethodManager suggestions.
* @param score The score for the label between 0.0 and 1.0.
*/
public FolderNameInfo(CharSequence label, double score) {
mScore = score;
mLabel = label;
}
private FolderNameInfo(Parcel source) {
mScore = source.readDouble();
mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
}
public CharSequence getLabel() {
return mLabel;
}
public double getScore() {
return mScore;
}
/**
* Used to package this object into a {@link Parcel}.
*
* @param dest The {@link Parcel} to be written.
* @param flags The flags used for parceling.
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeDouble(mScore);
TextUtils.writeToParcel(mLabel, dest, flags);
}
/**
* Used to make this class parcelable.
*/
@NonNull
public static final Parcelable.Creator<FolderNameInfo> CREATOR =
new Parcelable.Creator<FolderNameInfo>() {
public FolderNameInfo createFromParcel(Parcel source) {
return new FolderNameInfo(source);
}
public FolderNameInfo[] newArray(int size) {
return new FolderNameInfo[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
@NonNull
public String toString() {
return String.format("%s:%.2f", mLabel, mScore);
}
}

View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* 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 com.android.launcher3.folder;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.Objects;
/**
* Information about a label suggestions of a Folder.
*/
public class FolderNameInfos {
public static final int SUCCESS = 1;
public static final int HAS_PRIMARY = 1 << 1;
public static final int HAS_SUGGESTIONS = 1 << 2;
public static final int ERROR_NO_PROVIDER = 1 << 3;
public static final int ERROR_APP_LOOKUP_FAILED = 1 << 4;
public static final int ERROR_ALL_APP_LOOKUP_FAILED = 1 << 5;
public static final int ERROR_NO_LABELS_GENERATED = 1 << 6;
public static final int ERROR_LABEL_LOOKUP_FAILED = 1 << 7;
public static final int ERROR_ALL_LABEL_LOOKUP_FAILED = 1 << 8;
public static final int ERROR_NO_PACKAGES = 1 << 9;
private int mStatus;
private final CharSequence[] mLabels;
private final Float[] mScores;
public FolderNameInfos() {
mStatus = 0;
mLabels = new CharSequence[FolderNameProvider.SUGGEST_MAX];
mScores = new Float[FolderNameProvider.SUGGEST_MAX];
}
/**
* set the status of FolderNameInfos.
*/
public void setStatus(int statusBit) {
mStatus = mStatus | statusBit;
}
/**
* returns status of FolderNameInfos generations.
*/
public int status() {
return mStatus;
}
/**
* return true if the first suggestion is a Primary suggestion.
*/
public boolean hasPrimary() {
return (mStatus & HAS_PRIMARY) > 0 && (mLabels[0] != null);
}
/**
* return true if there is at least one valid suggestion.
*/
public boolean hasSuggestions() {
for (CharSequence l : mLabels) {
if (l != null && !TextUtils.isEmpty(l)) return true;
}
return false;
}
/**
* assign label and score in the specified index.
*/
public void setLabel(int index, CharSequence label, Float score) {
if (index < mLabels.length) {
mLabels[index] = label;
mScores[index] = score;
}
}
/**
* returns true if the label is found in label suggestions/
*/
public boolean contains(CharSequence label) {
return Arrays.stream(mLabels)
.filter(Objects::nonNull)
.anyMatch(l -> l.toString().equalsIgnoreCase(label.toString()));
}
public CharSequence[] getLabels() {
return mLabels;
}
public Float[] getScores() {
return mScores;
}
@Override
@NonNull
public String toString() {
return String.format("status=%s, labels=%s", Integer.toBinaryString(mStatus),
Arrays.toString(mLabels));
}
}

View File

@ -96,10 +96,10 @@ public class FolderNameProvider implements ResourceBasedOverride {
*/ */
public void getSuggestedFolderName(Context context, public void getSuggestedFolderName(Context context,
ArrayList<WorkspaceItemInfo> workspaceItemInfos, ArrayList<WorkspaceItemInfo> workspaceItemInfos,
FolderNameInfo[] nameInfos) { FolderNameInfos nameInfos) {
Preconditions.assertWorkerThread(); Preconditions.assertWorkerThread();
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(nameInfos)); Log.d(TAG, "getSuggestedFolderName:" + nameInfos.toString());
} }
// If all the icons are from work profile, // If all the icons are from work profile,
// Then, suggest "Work" as the folder name // Then, suggest "Work" as the folder name
@ -124,7 +124,7 @@ public class FolderNameProvider implements ResourceBasedOverride {
info.ifPresent(i -> setAsFirstSuggestion(nameInfos, i.title.toString())); info.ifPresent(i -> setAsFirstSuggestion(nameInfos, i.title.toString()));
} }
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(nameInfos)); Log.d(TAG, "getSuggestedFolderName:" + nameInfos.toString());
} }
} }
@ -138,39 +138,37 @@ public class FolderNameProvider implements ResourceBasedOverride {
.findAny(); .findAny();
} }
private void setAsFirstSuggestion(FolderNameInfo[] nameInfos, CharSequence label) { private void setAsFirstSuggestion(FolderNameInfos nameInfos, CharSequence label) {
if (nameInfos.length == 0 || contains(nameInfos, label)) { if (nameInfos == null || nameInfos.contains(label)) {
return; return;
} }
for (int i = nameInfos.length - 1; i > 0; i--) { nameInfos.setStatus(FolderNameInfos.HAS_PRIMARY);
if (nameInfos[i - 1] != null && !TextUtils.isEmpty(nameInfos[i - 1].getLabel())) { nameInfos.setStatus(FolderNameInfos.HAS_SUGGESTIONS);
nameInfos[i] = nameInfos[i - 1]; CharSequence[] labels = nameInfos.getLabels();
Float[] scores = nameInfos.getScores();
for (int i = labels.length - 1; i > 0; i--) {
if (labels[i - 1] != null && !TextUtils.isEmpty(labels[i - 1])) {
nameInfos.setLabel(i, labels[i - 1], scores[i - 1]);
} }
} }
nameInfos[0] = new FolderNameInfo(label, 1.0); nameInfos.setLabel(0, label, 1.0f);
} }
private void setAsLastSuggestion(FolderNameInfo[] nameInfos, CharSequence label) { private void setAsLastSuggestion(FolderNameInfos nameInfos, CharSequence label) {
if (nameInfos.length == 0 || contains(nameInfos, label)) { if (nameInfos == null || nameInfos.contains(label)) {
return; return;
} }
nameInfos.setStatus(FolderNameInfos.HAS_PRIMARY);
for (int i = 0; i < nameInfos.length; i++) { nameInfos.setStatus(FolderNameInfos.HAS_SUGGESTIONS);
if (nameInfos[i] == null || TextUtils.isEmpty(nameInfos[i].getLabel())) { CharSequence[] labels = nameInfos.getLabels();
nameInfos[i] = new FolderNameInfo(label, 1.0); for (int i = 0; i < labels.length; i++) {
if (labels[i] == null || TextUtils.isEmpty(labels[i])) {
nameInfos.setLabel(i, label, 1.0f);
return; return;
} }
} }
// Overwrite the last suggestion. // Overwrite the last suggestion.
int lastIndex = nameInfos.length - 1; nameInfos.setLabel(labels.length - 1, label, 1.0f);
nameInfos[lastIndex] = new FolderNameInfo(label, 1.0);
}
private boolean contains(FolderNameInfo[] nameInfos, CharSequence label) {
return Arrays.stream(nameInfos)
.filter(Objects::nonNull)
.anyMatch(nameInfo -> nameInfo.getLabel().toString().equalsIgnoreCase(
label.toString()));
} }
private class FolderNameWorker extends BaseModelUpdateTask { private class FolderNameWorker extends BaseModelUpdateTask {

View File

@ -59,7 +59,7 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderGridOrganizer; import com.android.launcher3.folder.FolderGridOrganizer;
import com.android.launcher3.folder.FolderNameInfo; import com.android.launcher3.folder.FolderNameInfos;
import com.android.launcher3.folder.FolderNameProvider; import com.android.launcher3.folder.FolderNameProvider;
import com.android.launcher3.icons.ComponentWithLabelAndIcon; import com.android.launcher3.icons.ComponentWithLabelAndIcon;
import com.android.launcher3.icons.ComponentWithLabelAndIcon.ComponentWithIconCachingLogic; import com.android.launcher3.icons.ComponentWithLabelAndIcon.ComponentWithIconCachingLogic;
@ -953,13 +953,12 @@ public class LoaderTask implements Runnable {
synchronized (mBgDataModel) { synchronized (mBgDataModel) {
for (int i = 0; i < mBgDataModel.folders.size(); i++) { for (int i = 0; i < mBgDataModel.folders.size(); i++) {
FolderNameInfo[] suggestionInfos = FolderNameInfos suggestionInfos = new FolderNameInfos();
new FolderNameInfo[FolderNameProvider.SUGGEST_MAX];
FolderInfo info = mBgDataModel.folders.valueAt(i); FolderInfo info = mBgDataModel.folders.valueAt(i);
if (info.suggestedFolderNames == null) { if (info.suggestedFolderNames == null) {
provider.getSuggestedFolderName(mApp.getContext(), info.contents, provider.getSuggestedFolderName(mApp.getContext(), info.contents,
suggestionInfos); suggestionInfos);
info.suggestedFolderNames = new Intent().putExtra("suggest", suggestionInfos); info.suggestedFolderNames = suggestionInfos;
} }
} }
} }

View File

@ -29,17 +29,12 @@ import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolder
import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_FOLDER_LABEL_STATE_UNSPECIFIED; import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_FOLDER_LABEL_STATE_UNSPECIFIED;
import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_SUGGESTED; import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_SUGGESTED;
import static java.util.Arrays.stream;
import static java.util.Optional.ofNullable;
import android.content.Intent;
import android.os.Process; import android.os.Process;
import android.text.TextUtils;
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.FolderNameInfo; import com.android.launcher3.folder.FolderNameInfos;
import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logger.LauncherAtom;
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;
@ -51,8 +46,6 @@ import com.android.launcher3.userevent.LauncherLogProto.Target.ToFolderLabelStat
import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.ContentWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -85,7 +78,7 @@ public class FolderInfo extends ItemInfo {
public int options; public int options;
public Intent suggestedFolderNames; public FolderNameInfos suggestedFolderNames;
/** /**
* The apps and shortcuts * The apps and shortcuts
@ -224,17 +217,16 @@ public class FolderInfo extends ItemInfo {
public OptionalInt getAcceptedSuggestionIndex() { public OptionalInt getAcceptedSuggestionIndex() {
String newLabel = checkNotNull(title, String newLabel = checkNotNull(title,
"Expected valid folder label, but found null").toString(); "Expected valid folder label, but found null").toString();
return getSuggestedLabels() if (suggestedFolderNames == null || !suggestedFolderNames.hasSuggestions()) {
.map(suggestionsArray -> return OptionalInt.empty();
IntStream.range(0, suggestionsArray.length) }
.filter( CharSequence[] labels = suggestedFolderNames.getLabels();
index -> !isEmpty(suggestionsArray[index]) return IntStream.range(0, labels.length)
&& newLabel.equalsIgnoreCase( .filter(index -> !isEmpty(labels[index])
suggestionsArray[index])) && newLabel.equalsIgnoreCase(
.sequential() labels[index].toString()))
.findFirst() .sequential()
).orElse(OptionalInt.empty()); .findFirst();
} }
/** /**
@ -264,19 +256,15 @@ public class FolderInfo extends ItemInfo {
: LauncherAtom.ToState.TO_EMPTY_WITH_SUGGESTIONS_DISABLED; : LauncherAtom.ToState.TO_EMPTY_WITH_SUGGESTIONS_DISABLED;
} }
Optional<String[]> suggestedLabels = getSuggestedLabels(); // TODO: if suggestedFolderNames is null then it infrastructure issue, not
boolean isEmptySuggestions = suggestedLabels // ranking issue. We should log these appropriately.
.map(labels -> stream(labels).allMatch(TextUtils::isEmpty)) if (suggestedFolderNames == null || !suggestedFolderNames.hasSuggestions()) {
.orElse(true);
if (isEmptySuggestions) {
return title.length() > 0 return title.length() > 0
? LauncherAtom.ToState.TO_CUSTOM_WITH_EMPTY_SUGGESTIONS ? LauncherAtom.ToState.TO_CUSTOM_WITH_EMPTY_SUGGESTIONS
: LauncherAtom.ToState.TO_EMPTY_WITH_EMPTY_SUGGESTIONS; : LauncherAtom.ToState.TO_EMPTY_WITH_EMPTY_SUGGESTIONS;
} }
boolean hasValidPrimary = suggestedLabels boolean hasValidPrimary = suggestedFolderNames != null && suggestedFolderNames.hasPrimary();
.map(labels -> !isEmpty(labels[0]))
.orElse(false);
if (title.length() == 0) { if (title.length() == 0) {
return hasValidPrimary ? LauncherAtom.ToState.TO_EMPTY_WITH_VALID_PRIMARY return hasValidPrimary ? LauncherAtom.ToState.TO_EMPTY_WITH_VALID_PRIMARY
: LauncherAtom.ToState.TO_EMPTY_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY; : LauncherAtom.ToState.TO_EMPTY_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY;
@ -306,20 +294,6 @@ public class FolderInfo extends ItemInfo {
return LauncherAtom.ToState.TO_STATE_UNSPECIFIED; return LauncherAtom.ToState.TO_STATE_UNSPECIFIED;
} }
private Optional<String[]> getSuggestedLabels() {
return ofNullable(suggestedFolderNames)
.map(folderNames ->
(FolderNameInfo[])
folderNames.getParcelableArrayExtra(EXTRA_FOLDER_SUGGESTIONS))
.map(folderNameInfoArray ->
stream(folderNameInfoArray)
.filter(Objects::nonNull)
.map(FolderNameInfo::getLabel)
.filter(Objects::nonNull)
.map(CharSequence::toString)
.toArray(String[]::new));
}
/** /**
* Returns {@link LauncherLogProto.LauncherEvent} to log current folder label info. * Returns {@link LauncherLogProto.LauncherEvent} to log current folder label info.
* *