Loading src/com/android/launcher3/ExtendedEditText.java +1 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ public class ExtendedEditText extends EditText { * Implemented by listeners of the back key. */ public interface OnBackKeyListener { public boolean onBackKey(); boolean onBackKey(); } private OnBackKeyListener mBackKeyListener; Loading src/com/android/launcher3/folder/Folder.java +33 −11 Original line number Diff line number Diff line Loading @@ -297,16 +297,22 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } public void startEditingFolderName() { post(new Runnable() { @Override public void run() { post(() -> { if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) { 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(""); mIsEditingName = true; } }); } @Override public boolean onBackKey() { // Convert to a string here to ensure that no other state associated with the text field Loading @@ -316,11 +322,19 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mFolderIcon.onTitleChanged(newTitle); 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)) { mFolderName.setHint(R.string.folder_hint_text); mFolderName.setText(""); } else { mFolderName.setHint(null); } } sendCustomAccessibilityEvent( this, AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, Loading Loading @@ -403,8 +417,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mFolderName.setHint(null); } else { mFolderName.setText(""); if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) { mFolderName.setHint(""); } else { mFolderName.setHint(R.string.folder_hint_text); } } // In case any children didn't come across during loading, clean up the folder accordingly mFolderIcon.post(() -> { if (getItemCount() <= 1) { Loading @@ -420,7 +438,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo if (FeatureFlags.FOLDER_NAME_SUGGEST.get() && TextUtils.isEmpty(mFolderName.getText().toString())) { if (suggestName.length > 0 && !TextUtils.isEmpty(suggestName[0])) { mFolderName.setHint(suggestName[0]); mFolderName.setHint(""); mFolderName.setText(suggestName[0]); mInfo.title = suggestName[0]; animateOpen(mInfo.contents, 0, true); Loading Loading @@ -534,6 +552,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo openFolder.close(true); } if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) { mLauncher.getFolderNameProvider().load(getContext()); } mContent.bindItems(items); centerAboutIcon(); mItemsInvalidated = true; Loading Loading @@ -1350,6 +1371,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo return itemsOnCurrentPage; } @Override public void onFocusChange(View v, boolean hasFocus) { if (v == mFolderName) { if (hasFocus) { Loading src/com/android/launcher3/folder/FolderNameProvider.java +32 −4 Original line number Diff line number Diff line Loading @@ -18,13 +18,16 @@ package com.android.launcher3.folder; import android.content.Context; import android.os.Process; import android.text.TextUtils; import android.util.Log; import com.android.launcher3.AppInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.config.FeatureFlags; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; Loading @@ -38,16 +41,26 @@ import java.util.stream.Collectors; */ 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 * name edit box can also be used to provide suggestion. */ 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, ArrayList<WorkspaceItemInfo> workspaceItemInfos, CharSequence[] candidates) { CharSequence suggest; if (DEBUG) { Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(candidates)); } // If all the icons are from work profile, // Then, suggest "Work" as the folder name List<WorkspaceItemInfo> distinctItemInfos = workspaceItemInfos.stream() Loading Loading @@ -75,19 +88,28 @@ public class FolderNameProvider { // Place it as first viable suggestion and shift everything else info.ifPresent(i -> setAsFirstSuggestion(candidates, i.title.toString())); } if (DEBUG) { Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(candidates)); } return candidates[0]; } private void setAsFirstSuggestion(CharSequence[] candidatesOut, CharSequence candidate) { if (contains(candidatesOut, candidate)) { return; } for (int i = candidatesOut.length - 1; i > 0; i--) { if (TextUtils.isEmpty(candidatesOut[i])) { candidatesOut[i - 1] = candidatesOut[i]; if (!TextUtils.isEmpty(candidatesOut[i - 1])) { candidatesOut[i] = candidatesOut[i - 1]; } candidatesOut[0] = candidate; } candidatesOut[0] = candidate; } private void setAsLastSuggestion(CharSequence[] candidatesOut, CharSequence candidate) { if (contains(candidatesOut, candidate)) { return; } for (int i = 0; i < candidate.length(); i++) { if (TextUtils.isEmpty(candidatesOut[i])) { candidatesOut[i] = candidate; Loading @@ -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. private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) { Map<Object, Boolean> map = new ConcurrentHashMap<>(); Loading Loading
src/com/android/launcher3/ExtendedEditText.java +1 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ public class ExtendedEditText extends EditText { * Implemented by listeners of the back key. */ public interface OnBackKeyListener { public boolean onBackKey(); boolean onBackKey(); } private OnBackKeyListener mBackKeyListener; Loading
src/com/android/launcher3/folder/Folder.java +33 −11 Original line number Diff line number Diff line Loading @@ -297,16 +297,22 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo } public void startEditingFolderName() { post(new Runnable() { @Override public void run() { post(() -> { if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) { 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(""); mIsEditingName = true; } }); } @Override public boolean onBackKey() { // Convert to a string here to ensure that no other state associated with the text field Loading @@ -316,11 +322,19 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mFolderIcon.onTitleChanged(newTitle); 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)) { mFolderName.setHint(R.string.folder_hint_text); mFolderName.setText(""); } else { mFolderName.setHint(null); } } sendCustomAccessibilityEvent( this, AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, Loading Loading @@ -403,8 +417,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mFolderName.setHint(null); } else { mFolderName.setText(""); if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) { mFolderName.setHint(""); } else { mFolderName.setHint(R.string.folder_hint_text); } } // In case any children didn't come across during loading, clean up the folder accordingly mFolderIcon.post(() -> { if (getItemCount() <= 1) { Loading @@ -420,7 +438,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo if (FeatureFlags.FOLDER_NAME_SUGGEST.get() && TextUtils.isEmpty(mFolderName.getText().toString())) { if (suggestName.length > 0 && !TextUtils.isEmpty(suggestName[0])) { mFolderName.setHint(suggestName[0]); mFolderName.setHint(""); mFolderName.setText(suggestName[0]); mInfo.title = suggestName[0]; animateOpen(mInfo.contents, 0, true); Loading Loading @@ -534,6 +552,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo openFolder.close(true); } if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) { mLauncher.getFolderNameProvider().load(getContext()); } mContent.bindItems(items); centerAboutIcon(); mItemsInvalidated = true; Loading Loading @@ -1350,6 +1371,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo return itemsOnCurrentPage; } @Override public void onFocusChange(View v, boolean hasFocus) { if (v == mFolderName) { if (hasFocus) { Loading
src/com/android/launcher3/folder/FolderNameProvider.java +32 −4 Original line number Diff line number Diff line Loading @@ -18,13 +18,16 @@ package com.android.launcher3.folder; import android.content.Context; import android.os.Process; import android.text.TextUtils; import android.util.Log; import com.android.launcher3.AppInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.config.FeatureFlags; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; Loading @@ -38,16 +41,26 @@ import java.util.stream.Collectors; */ 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 * name edit box can also be used to provide suggestion. */ 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, ArrayList<WorkspaceItemInfo> workspaceItemInfos, CharSequence[] candidates) { CharSequence suggest; if (DEBUG) { Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(candidates)); } // If all the icons are from work profile, // Then, suggest "Work" as the folder name List<WorkspaceItemInfo> distinctItemInfos = workspaceItemInfos.stream() Loading Loading @@ -75,19 +88,28 @@ public class FolderNameProvider { // Place it as first viable suggestion and shift everything else info.ifPresent(i -> setAsFirstSuggestion(candidates, i.title.toString())); } if (DEBUG) { Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(candidates)); } return candidates[0]; } private void setAsFirstSuggestion(CharSequence[] candidatesOut, CharSequence candidate) { if (contains(candidatesOut, candidate)) { return; } for (int i = candidatesOut.length - 1; i > 0; i--) { if (TextUtils.isEmpty(candidatesOut[i])) { candidatesOut[i - 1] = candidatesOut[i]; if (!TextUtils.isEmpty(candidatesOut[i - 1])) { candidatesOut[i] = candidatesOut[i - 1]; } candidatesOut[0] = candidate; } candidatesOut[0] = candidate; } private void setAsLastSuggestion(CharSequence[] candidatesOut, CharSequence candidate) { if (contains(candidatesOut, candidate)) { return; } for (int i = 0; i < candidate.length(); i++) { if (TextUtils.isEmpty(candidatesOut[i])) { candidatesOut[i] = candidate; Loading @@ -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. private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) { Map<Object, Boolean> map = new ConcurrentHashMap<>(); Loading