Merge "Refactor FolderNameInfos." into ub-launcher3-rvc-dev
This commit is contained in:
commit
d2260a07b8
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue