Merge "Show suggestion when user taps on folder's edit text" into ub-launcher3-master
This commit is contained in:
commit
bab1101b87
|
@ -44,7 +44,7 @@ public class ExtendedEditText extends EditText {
|
||||||
* Implemented by listeners of the back key.
|
* Implemented by listeners of the back key.
|
||||||
*/
|
*/
|
||||||
public interface OnBackKeyListener {
|
public interface OnBackKeyListener {
|
||||||
public boolean onBackKey();
|
boolean onBackKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
private OnBackKeyListener mBackKeyListener;
|
private OnBackKeyListener mBackKeyListener;
|
||||||
|
|
|
@ -297,16 +297,22 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startEditingFolderName() {
|
public void startEditingFolderName() {
|
||||||
post(new Runnable() {
|
post(() -> {
|
||||||
@Override
|
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
|
||||||
public void run() {
|
if (TextUtils.isEmpty(mFolderName.getText())) {
|
||||||
|
final String[] suggestedNames = new String[FolderNameProvider.SUGGEST_MAX];
|
||||||
|
mLauncher.getFolderNameProvider().getSuggestedFolderName(getContext(),
|
||||||
|
mInfo.contents, suggestedNames);
|
||||||
|
mFolderName.setText(suggestedNames[0]);
|
||||||
|
mFolderName.displayCompletions(Arrays.asList(suggestedNames).subList(1,
|
||||||
|
suggestedNames.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
mFolderName.setHint("");
|
mFolderName.setHint("");
|
||||||
mIsEditingName = true;
|
mIsEditingName = true;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onBackKey() {
|
public boolean onBackKey() {
|
||||||
// Convert to a string here to ensure that no other state associated with the text field
|
// Convert to a string here to ensure that no other state associated with the text field
|
||||||
|
@ -316,11 +322,19 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||||
mFolderIcon.onTitleChanged(newTitle);
|
mFolderIcon.onTitleChanged(newTitle);
|
||||||
mLauncher.getModelWriter().updateItemInDatabase(mInfo);
|
mLauncher.getModelWriter().updateItemInDatabase(mInfo);
|
||||||
|
|
||||||
|
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
|
||||||
|
mFolderName.setText(mInfo.title);
|
||||||
|
// TODO: depending on whether the title was manually edited or automatically
|
||||||
|
// suggested, apply different hint.
|
||||||
|
mFolderName.setHint("");
|
||||||
|
} else {
|
||||||
if (TextUtils.isEmpty(mInfo.title)) {
|
if (TextUtils.isEmpty(mInfo.title)) {
|
||||||
mFolderName.setHint(R.string.folder_hint_text);
|
mFolderName.setHint(R.string.folder_hint_text);
|
||||||
|
mFolderName.setText("");
|
||||||
} else {
|
} else {
|
||||||
mFolderName.setHint(null);
|
mFolderName.setHint(null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sendCustomAccessibilityEvent(
|
sendCustomAccessibilityEvent(
|
||||||
this, AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
|
this, AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
|
||||||
|
@ -403,8 +417,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||||
mFolderName.setHint(null);
|
mFolderName.setHint(null);
|
||||||
} else {
|
} else {
|
||||||
mFolderName.setText("");
|
mFolderName.setText("");
|
||||||
|
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
|
||||||
|
mFolderName.setHint("");
|
||||||
|
} else {
|
||||||
mFolderName.setHint(R.string.folder_hint_text);
|
mFolderName.setHint(R.string.folder_hint_text);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// In case any children didn't come across during loading, clean up the folder accordingly
|
// In case any children didn't come across during loading, clean up the folder accordingly
|
||||||
mFolderIcon.post(() -> {
|
mFolderIcon.post(() -> {
|
||||||
if (getItemCount() <= 1) {
|
if (getItemCount() <= 1) {
|
||||||
|
@ -420,7 +438,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||||
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()
|
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()
|
||||||
&& TextUtils.isEmpty(mFolderName.getText().toString())) {
|
&& TextUtils.isEmpty(mFolderName.getText().toString())) {
|
||||||
if (suggestName.length > 0 && !TextUtils.isEmpty(suggestName[0])) {
|
if (suggestName.length > 0 && !TextUtils.isEmpty(suggestName[0])) {
|
||||||
mFolderName.setHint(suggestName[0]);
|
mFolderName.setHint("");
|
||||||
mFolderName.setText(suggestName[0]);
|
mFolderName.setText(suggestName[0]);
|
||||||
mInfo.title = suggestName[0];
|
mInfo.title = suggestName[0];
|
||||||
animateOpen(mInfo.contents, 0, true);
|
animateOpen(mInfo.contents, 0, true);
|
||||||
|
@ -534,6 +552,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||||
openFolder.close(true);
|
openFolder.close(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
|
||||||
|
mLauncher.getFolderNameProvider().load(getContext());
|
||||||
|
}
|
||||||
mContent.bindItems(items);
|
mContent.bindItems(items);
|
||||||
centerAboutIcon();
|
centerAboutIcon();
|
||||||
mItemsInvalidated = true;
|
mItemsInvalidated = true;
|
||||||
|
@ -1350,6 +1371,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||||
return itemsOnCurrentPage;
|
return itemsOnCurrentPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
if (v == mFolderName) {
|
if (v == mFolderName) {
|
||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
|
|
|
@ -18,13 +18,16 @@ package com.android.launcher3.folder;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.launcher3.AppInfo;
|
import com.android.launcher3.AppInfo;
|
||||||
import com.android.launcher3.LauncherAppState;
|
import com.android.launcher3.LauncherAppState;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.WorkspaceItemInfo;
|
import com.android.launcher3.WorkspaceItemInfo;
|
||||||
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -38,16 +41,26 @@ import java.util.stream.Collectors;
|
||||||
*/
|
*/
|
||||||
public class FolderNameProvider {
|
public class FolderNameProvider {
|
||||||
|
|
||||||
|
private static final String TAG = FeatureFlags.FOLDER_NAME_SUGGEST.getKey();
|
||||||
|
private static final boolean DEBUG = FeatureFlags.FOLDER_NAME_SUGGEST.get();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IME usually has up to 3 suggest slots. In total, there are 4 suggest slots as the folder
|
* IME usually has up to 3 suggest slots. In total, there are 4 suggest slots as the folder
|
||||||
* name edit box can also be used to provide suggestion.
|
* name edit box can also be used to provide suggestion.
|
||||||
*/
|
*/
|
||||||
public static final int SUGGEST_MAX = 4;
|
public static final int SUGGEST_MAX = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When inheriting class requires precaching, override this method.
|
||||||
|
*/
|
||||||
|
public void load(Context context) {}
|
||||||
|
|
||||||
public CharSequence getSuggestedFolderName(Context context,
|
public CharSequence getSuggestedFolderName(Context context,
|
||||||
ArrayList<WorkspaceItemInfo> workspaceItemInfos, CharSequence[] candidates) {
|
ArrayList<WorkspaceItemInfo> workspaceItemInfos, CharSequence[] candidates) {
|
||||||
|
|
||||||
CharSequence suggest;
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(candidates));
|
||||||
|
}
|
||||||
// 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
|
||||||
List<WorkspaceItemInfo> distinctItemInfos = workspaceItemInfos.stream()
|
List<WorkspaceItemInfo> distinctItemInfos = workspaceItemInfos.stream()
|
||||||
|
@ -75,19 +88,28 @@ public class FolderNameProvider {
|
||||||
// Place it as first viable suggestion and shift everything else
|
// Place it as first viable suggestion and shift everything else
|
||||||
info.ifPresent(i -> setAsFirstSuggestion(candidates, i.title.toString()));
|
info.ifPresent(i -> setAsFirstSuggestion(candidates, i.title.toString()));
|
||||||
}
|
}
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(candidates));
|
||||||
|
}
|
||||||
return candidates[0];
|
return candidates[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAsFirstSuggestion(CharSequence[] candidatesOut, CharSequence candidate) {
|
private void setAsFirstSuggestion(CharSequence[] candidatesOut, CharSequence candidate) {
|
||||||
|
if (contains(candidatesOut, candidate)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (int i = candidatesOut.length - 1; i > 0; i--) {
|
for (int i = candidatesOut.length - 1; i > 0; i--) {
|
||||||
if (TextUtils.isEmpty(candidatesOut[i])) {
|
if (!TextUtils.isEmpty(candidatesOut[i - 1])) {
|
||||||
candidatesOut[i - 1] = candidatesOut[i];
|
candidatesOut[i] = candidatesOut[i - 1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
candidatesOut[0] = candidate;
|
candidatesOut[0] = candidate;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void setAsLastSuggestion(CharSequence[] candidatesOut, CharSequence candidate) {
|
private void setAsLastSuggestion(CharSequence[] candidatesOut, CharSequence candidate) {
|
||||||
|
if (contains(candidatesOut, candidate)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (int i = 0; i < candidate.length(); i++) {
|
for (int i = 0; i < candidate.length(); i++) {
|
||||||
if (TextUtils.isEmpty(candidatesOut[i])) {
|
if (TextUtils.isEmpty(candidatesOut[i])) {
|
||||||
candidatesOut[i] = candidate;
|
candidatesOut[i] = candidate;
|
||||||
|
@ -95,6 +117,12 @@ public class FolderNameProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean contains(CharSequence[] list, CharSequence key) {
|
||||||
|
return Arrays.asList(list).stream()
|
||||||
|
.filter(s -> s != null)
|
||||||
|
.anyMatch(s -> s.toString().equalsIgnoreCase(key.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
// This method can be moved to some Utility class location.
|
// This method can be moved to some Utility class location.
|
||||||
private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
|
private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
|
||||||
Map<Object, Boolean> map = new ConcurrentHashMap<>();
|
Map<Object, Boolean> map = new ConcurrentHashMap<>();
|
||||||
|
|
Loading…
Reference in New Issue