diff --git a/Android.bp b/Android.bp index fc998809e1..cb695df241 100644 --- a/Android.bp +++ b/Android.bp @@ -32,7 +32,7 @@ android_library { } java_library_static { - name: "launcher-log-protos-lite", + name: "launcher_log_protos_lite", srcs: [ "protos/*.proto", "proto_overrides/*.proto", @@ -45,4 +45,5 @@ java_library_static { "proto_overrides", ], }, + static_libs: ["libprotobuf-java-lite"], } diff --git a/Android.mk b/Android.mk index a099ada991..c066a12aeb 100644 --- a/Android.mk +++ b/Android.mk @@ -48,7 +48,9 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \ androidx.preference_preference \ iconloader_base -LOCAL_STATIC_JAVA_LIBRARIES := LauncherPluginLib +LOCAL_STATIC_JAVA_LIBRARIES := \ + LauncherPluginLib \ + launcher_log_protos_lite LOCAL_SRC_FILES := \ $(call all-proto-files-under, protos) \ @@ -144,7 +146,10 @@ LOCAL_USE_AAPT2 := true LOCAL_AAPT2_ONLY := true LOCAL_MODULE_TAGS := optional -LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLibLauncherWrapper launcherprotosnano +LOCAL_STATIC_JAVA_LIBRARIES := \ + SystemUISharedLib \ + launcherprotosnano \ + launcher_log_protos_lite ifneq (,$(wildcard frameworks/base)) LOCAL_PRIVATE_PLATFORM_APIS := true else @@ -213,7 +218,10 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_MODULE_TAGS := optional -LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLibLauncherWrapper launcherprotosnano +LOCAL_STATIC_JAVA_LIBRARIES := \ + SystemUISharedLib \ + launcherprotosnano \ + launcher_log_protos_lite ifneq (,$(wildcard frameworks/base)) LOCAL_PRIVATE_PLATFORM_APIS := true else diff --git a/go/src/com/android/launcher3/model/WidgetsModel.java b/go/src/com/android/launcher3/model/WidgetsModel.java index 7269b417e4..7690b9d57c 100644 --- a/go/src/com/android/launcher3/model/WidgetsModel.java +++ b/go/src/com/android/launcher3/model/WidgetsModel.java @@ -22,7 +22,7 @@ import android.os.UserHandle; import androidx.annotation.Nullable; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.icons.ComponentWithLabel; +import com.android.launcher3.icons.ComponentWithLabelAndIcon; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.widget.WidgetListRowEntry; @@ -59,7 +59,7 @@ public class WidgetsModel { * @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise * only widgets and shortcuts associated with the package/user are. */ - public List update(LauncherAppState app, + public List update(LauncherAppState app, @Nullable PackageUserKey packageUser) { return Collections.emptyList(); } diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java index bce4e0f330..31a923e314 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java +++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java @@ -350,6 +350,17 @@ public class BaseIconFactory implements AutoCloseable { iconDpi); } + /** + * Badges the provided source with the badge info + */ + public BitmapInfo badgeBitmap(Bitmap source, BitmapInfo badgeInfo) { + Bitmap icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> { + getShadowGenerator().recreateIcon(source, c); + badgeWithDrawable(c, new FixedSizeBitmapDrawable(badgeInfo.icon)); + }); + return BitmapInfo.of(icon, badgeInfo.color); + } + private int extractColor(Bitmap bitmap) { return mDisableColorExtractor ? 0 : mColorExtractor.findDominantColorByHue(bitmap); } diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java index e807791d94..4c634cbc26 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java @@ -281,7 +281,8 @@ public abstract class BaseIconCache { ContentValues values = newContentValues(entry.bitmap, entry.title.toString(), componentName.getPackageName(), cachingLogic.getKeywords(object, mLocaleList)); - addIconToDB(values, componentName, info, userSerial); + addIconToDB(values, componentName, info, userSerial, + cachingLogic.getLastUpdatedTime(object, info)); } /** @@ -289,10 +290,10 @@ public abstract class BaseIconCache { * @param values {@link ContentValues} containing icon & title */ private void addIconToDB(ContentValues values, ComponentName key, - PackageInfo info, long userSerial) { + PackageInfo info, long userSerial, long lastUpdateTime) { values.put(IconDB.COLUMN_COMPONENT, key.flattenToString()); values.put(IconDB.COLUMN_USER, userSerial); - values.put(IconDB.COLUMN_LAST_UPDATED, info.lastUpdateTime); + values.put(IconDB.COLUMN_LAST_UPDATED, lastUpdateTime); values.put(IconDB.COLUMN_VERSION, info.versionCode); mIconDb.insertOrReplace(values); } @@ -362,7 +363,8 @@ public abstract class BaseIconCache { } if (object != null) { entry.title = cachingLogic.getLabel(object); - entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user); + entry.contentDescription = mPackageManager.getUserBadgedLabel( + cachingLogic.getDescription(object, entry.title), user); } } } @@ -449,7 +451,8 @@ public abstract class BaseIconCache { // package updates. ContentValues values = newContentValues( iconInfo, entry.title.toString(), packageName, null); - addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user)); + addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user), + info.lastUpdateTime); } catch (NameNotFoundException e) { if (DEBUG) Log.d(TAG, "Application not installed " + packageName); diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java index a89ede7b34..c12e9dcc15 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java @@ -34,6 +34,10 @@ public interface CachingLogic { CharSequence getLabel(T object); + default CharSequence getDescription(T object, CharSequence fallback) { + return fallback; + } + @NonNull BitmapInfo loadIcon(Context context, T object); diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java index d0db15728a..9e1ad7b7b2 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java @@ -24,6 +24,7 @@ import android.database.sqlite.SQLiteException; import android.os.SystemClock; import android.os.UserHandle; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Log; import android.util.SparseBooleanArray; @@ -61,7 +62,7 @@ public class IconCacheUpdateHandler { private final HashMap mPkgInfoMap; private final BaseIconCache mIconCache; - private final HashMap> mPackagesToIgnore = new HashMap<>(); + private final ArrayMap> mPackagesToIgnore = new ArrayMap<>(); private final SparseBooleanArray mItemsToDelete = new SparseBooleanArray(); private boolean mFilterMode = MODE_SET_INVALID_ITEMS; @@ -77,8 +78,16 @@ public class IconCacheUpdateHandler { createPackageInfoMap(); } - public void setPackagesToIgnore(UserHandle userHandle, Set packages) { - mPackagesToIgnore.put(userHandle, packages); + /** + * Sets a package to ignore for processing + */ + public void addPackagesToIgnore(UserHandle userHandle, String packageName) { + Set packages = mPackagesToIgnore.get(userHandle); + if (packages == null) { + packages = new HashSet<>(); + mPackagesToIgnore.put(userHandle, packages); + } + packages.add(packageName); } private void createPackageInfoMap() { @@ -180,6 +189,7 @@ public class IconCacheUpdateHandler { } continue; } + if (app == null) { if (mFilterMode == MODE_SET_INVALID_ITEMS) { mIconCache.remove(component, user); @@ -262,6 +272,7 @@ public class IconCacheUpdateHandler { T app = mAppsToUpdate.pop(); String pkg = mCachingLogic.getComponent(app).getPackageName(); PackageInfo info = mPkgInfoMap.get(pkg); + mIconCache.addIconToDBAndMemCache( app, mCachingLogic, info, mUserSerial, true /*replace existing*/); mUpdatedPackages.add(pkg); diff --git a/proguard.flags b/proguard.flags index 01302cfb54..e556c94466 100644 --- a/proguard.flags +++ b/proguard.flags @@ -48,3 +48,6 @@ -dontwarn android.view.** -dontwarn android.os.** -dontwarn android.graphics.** + +# Ignore warnings for hidden utility classes referenced from the shared lib +-dontwarn com.android.internal.util.** \ No newline at end of file diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto index 0560d680f6..ec1d55b753 100644 --- a/protos/launcher_log.proto +++ b/protos/launcher_log.proto @@ -58,6 +58,35 @@ message Target { optional TipType tip_type = 17; optional int32 search_query_length = 18; optional bool is_work_app = 19; + optional FromFolderLabelState from_folder_label_state = 20; + optional ToFolderLabelState to_folder_label_state = 21; + + // Note: proto does not support duplicate enum values, even if they belong to different enum type. + // Hence "FROM" and "TO" prefix added. + enum FromFolderLabelState{ + FROM_FOLDER_LABEL_STATE_UNSPECIFIED = 0; + FROM_EMPTY = 1; + FROM_CUSTOM = 2; + FROM_SUGGESTED = 3; + } + + enum ToFolderLabelState{ + TO_FOLDER_LABEL_STATE_UNSPECIFIED = 0; + TO_SUGGESTION0_WITH_VALID_PRIMARY = 1; + TO_SUGGESTION1_WITH_VALID_PRIMARY = 2; + TO_SUGGESTION1_WITH_EMPTY_PRIMARY = 3; + TO_SUGGESTION2_WITH_VALID_PRIMARY = 4; + TO_SUGGESTION2_WITH_EMPTY_PRIMARY = 5; + TO_SUGGESTION3_WITH_VALID_PRIMARY = 6; + TO_SUGGESTION3_WITH_EMPTY_PRIMARY = 7; + TO_EMPTY_WITH_VALID_SUGGESTIONS = 8; + TO_EMPTY_WITH_EMPTY_SUGGESTIONS = 9; + TO_EMPTY_WITH_SUGGESTIONS_DISABLED = 10; + TO_CUSTOM_WITH_VALID_SUGGESTIONS = 11; + TO_CUSTOM_WITH_EMPTY_SUGGESTIONS = 12; + TO_CUSTOM_WITH_SUGGESTIONS_DISABLED = 13; + UNCHANGED = 14; + } } // Used to define what type of item a Target would represent. @@ -120,6 +149,8 @@ enum ControlType { BACK_GESTURE = 19; UNDO = 20; DISMISS_PREDICTION = 21; + HYBRID_HOTSEAT_ACCEPTED = 22; + HYBRID_HOTSEAT_CANCELED = 23; } enum TipType { @@ -129,6 +160,7 @@ enum TipType { QUICK_SCRUB_TEXT = 3; PREDICTION_TEXT = 4; DWB_TOAST = 5; + HYBRID_HOTSEAT = 6; } // Used to define the action component of the LauncherEvent. @@ -138,7 +170,8 @@ message Action { AUTOMATED = 1; COMMAND = 2; TIP = 3; - // SOFT_KEYBOARD, HARD_KEYBOARD, ASSIST + SOFT_KEYBOARD = 4; + // HARD_KEYBOARD, ASSIST } enum Touch { diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java index 76972aff41..54f58e2081 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java @@ -43,7 +43,6 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.icons.IconCache; -import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.InstantAppResolver; @@ -170,14 +169,7 @@ public class DynamicItemCache { List details = shortcutKey.buildRequest(mContext).query(ShortcutRequest.ALL); if (!details.isEmpty()) { WorkspaceItemInfo si = new WorkspaceItemInfo(details.get(0), mContext); - try (LauncherIcons li = LauncherIcons.obtain(mContext)) { - si.bitmap = li.createShortcutIcon(details.get(0), true /* badged */, null); - } catch (Exception e) { - if (DEBUG) { - Log.e(TAG, "Error loading shortcut icon for " + shortcutKey.toString()); - } - return null; - } + mIconCache.getShortcutIcon(si, details.get(0)); return si; } if (DEBUG) { diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java index f82af62aac..834e6cf0fb 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -296,7 +296,7 @@ public class PredictionRowView extends LinearLayout implements predictedApp.container = LauncherSettings.Favorites.CONTAINER_PREDICTION; predictedApps.add(predictedApp); } else { - if (FeatureFlags.IS_DOGFOOD_BUILD) { + if (FeatureFlags.IS_STUDIO_BUILD) { Log.e(TAG, "Predicted app not found: " + mapper); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java index 4c879452ef..00e72b1e47 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java @@ -15,6 +15,9 @@ */ package com.android.launcher3.hybridhotseat; +import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.HYBRID_HOTSEAT_CANCELED; + import android.animation.PropertyValuesHolder; import android.content.Context; import android.content.res.Configuration; @@ -32,6 +35,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.views.AbstractSlideInView; @@ -95,6 +99,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable handleClose(true); mHotseatEduController.migrate(); mHotseatEduController.finishOnboarding(); + logUserAction(true); Toast.makeText(mLauncher, R.string.hotseat_items_migrated, Toast.LENGTH_LONG).show(); } @@ -102,6 +107,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable if (mHotseatEduController == null) return; Toast.makeText(getContext(), R.string.hotseat_no_migration, Toast.LENGTH_LONG).show(); mHotseatEduController.finishOnboarding(); + logUserAction(false); handleClose(true); } @@ -133,7 +139,28 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable mLauncher.getDeviceProfile().hotseatBarSizePx + insets.bottom; } + private void logUserAction(boolean migrated) { + LauncherLogProto.Action action = new LauncherLogProto.Action(); + LauncherLogProto.Target target = new LauncherLogProto.Target(); + action.type = LauncherLogProto.Action.Type.TOUCH; + action.touch = LauncherLogProto.Action.Touch.TAP; + target.containerType = LauncherLogProto.ContainerType.TIP; + target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT; + target.controlType = migrated ? LauncherLogProto.ControlType.HYBRID_HOTSEAT_ACCEPTED + : HYBRID_HOTSEAT_CANCELED; + LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target); + UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null); + } + private void logOnBoardingSeen() { + LauncherLogProto.Action action = new LauncherLogProto.Action(); + LauncherLogProto.Target target = new LauncherLogProto.Target(); + action.type = LauncherLogProto.Action.Type.TIP; + target.containerType = LauncherLogProto.ContainerType.TIP; + target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT; + LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target); + UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null); + } private void animateOpen() { if (mIsOpen || mOpenCloseAnimator.isRunning()) { return; @@ -165,6 +192,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable return; } mLauncher.getDragLayer().addView(this); + logOnBoardingSeen(); animateOpen(); for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) { WorkspaceItemInfo info = predictions.get(i); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index cc6ec6998d..0b054277e1 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -109,6 +109,7 @@ public class HotseatPredictionController implements DragController.DragListener, private AppPredictor mAppPredictor; private AllAppsStore mAllAppsStore; private AnimatorSet mIconRemoveAnimators; + private boolean mUIUpdatePaused = false; private HotseatEduController mHotseatEduController; @@ -168,7 +169,7 @@ public class HotseatPredictionController implements DragController.DragListener, } private void fillGapsWithPrediction(boolean animate, Runnable callback) { - if (!isReady() || mDragObject != null) { + if (!isReady() || mUIUpdatePaused || mDragObject != null) { return; } List predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers); @@ -249,6 +250,16 @@ public class HotseatPredictionController implements DragController.DragListener, } } + /** + * start and pauses predicted apps update on the hotseat + */ + public void setPauseUIUpdate(boolean paused) { + mUIUpdatePaused = paused; + if (!paused) { + fillGapsWithPrediction(); + } + } + /** * Creates App Predictor with all the current apps pinned on the hotseat */ @@ -447,17 +458,40 @@ public class HotseatPredictionController implements DragController.DragListener, /** * Unpins pinned app when it's converted into a folder */ - public void folderCreatedFromIcon(ItemInfo info, FolderInfo folderInfo) { + public void folderCreatedFromWorkspaceItem(ItemInfo info, FolderInfo folderInfo) { + if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { + return; + } AppTarget target = getAppTargetFromItemInfo(info); - if (folderInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT && !isInHotseat( - info)) { + ViewGroup hotseatVG = mHotseat.getShortcutsAndWidgets(); + ViewGroup firstScreenVG = mLauncher.getWorkspace().getScreenWithId( + Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets(); + + if (isInHotseat(folderInfo) && !getPinnedAppTargetsInViewGroup(hotseatVG).contains( + target)) { notifyItemAction(target, APP_LOCATION_HOTSEAT, APPTARGET_ACTION_UNPIN); - } else if (folderInfo.container == LauncherSettings.Favorites.CONTAINER_DESKTOP - && folderInfo.screenId == Workspace.FIRST_SCREEN_ID && !isInFirstPage(info)) { + } else if (isInFirstPage(folderInfo) && !getPinnedAppTargetsInViewGroup( + firstScreenVG).contains(target)) { notifyItemAction(target, APP_LOCATION_WORKSPACE, APPTARGET_ACTION_UNPIN); } } + /** + * Pins workspace item created when all folder items are removed but one + */ + public void folderConvertedToWorkspaceItem(ItemInfo info, FolderInfo folderInfo) { + if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { + return; + } + AppTarget target = getAppTargetFromItemInfo(info); + if (isInHotseat(info)) { + notifyItemAction(target, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN); + } else if (isInFirstPage(info)) { + notifyItemAction(target, APP_LOCATION_WORKSPACE, AppTargetEvent.ACTION_PIN); + } + } + + @Override public void onDragEnd() { if (mDragObject == null) { diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java index b2e1798453..4bbb48ce83 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java @@ -86,6 +86,7 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView { mIsDrawingDot = true; int count = canvas.save(); canvas.translate(-getWidth() * RING_EFFECT_RATIO, -getHeight() * RING_EFFECT_RATIO); + canvas.scale(1 + 2 * RING_EFFECT_RATIO, 1 + 2 * RING_EFFECT_RATIO); super.drawDotIfNecessary(canvas); canvas.restoreToCount(count); mIsDrawingDot = false; diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index f6bc5eaed0..30a4e508d9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -20,20 +20,24 @@ import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import android.content.Context; +import android.content.Intent; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.view.Gravity; +import android.view.View; + +import androidx.annotation.Nullable; import com.android.launcher3.BaseQuickstepLauncher; -import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.folder.Folder; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.popup.SystemShortcut; @@ -161,6 +165,15 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { onStateOrResumeChanged(); } + @Override + public boolean startActivitySafely(View v, Intent intent, ItemInfo item, + @Nullable String sourceContainer) { + if (mHotseatPredictionController != null) { + mHotseatPredictionController.setPauseUIUpdate(true); + } + return super.startActivitySafely(v, intent, item, sourceContainer); + } + @Override protected void onActivityFlagsChanged(int changeBits) { super.onActivityFlagsChanged(changeBits); @@ -170,16 +183,27 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { && (getActivityFlags() & ACTIVITY_STATE_TRANSITION_ACTIVE) == 0) { onStateOrResumeChanged(); } + + if ((changeBits & ACTIVITY_STATE_STARTED) != 0 && mHotseatPredictionController != null + && (getActivityFlags() & ACTIVITY_STATE_USER_ACTIVE) == 0) { + mHotseatPredictionController.setPauseUIUpdate(false); + } } @Override - public FolderIcon addFolder(CellLayout layout, WorkspaceItemInfo info, int container, - int screenId, int cellX, int cellY) { - FolderIcon fi = super.addFolder(layout, info, container, screenId, cellX, cellY); + public void folderCreatedFromItem(Folder folder, WorkspaceItemInfo itemInfo) { + super.folderCreatedFromItem(folder, itemInfo); if (mHotseatPredictionController != null) { - mHotseatPredictionController.folderCreatedFromIcon(info, fi.getFolder().getInfo()); + mHotseatPredictionController.folderCreatedFromWorkspaceItem(itemInfo, folder.getInfo()); + } + } + + @Override + public void folderConvertedToItem(Folder folder, WorkspaceItemInfo itemInfo) { + super.folderConvertedToItem(folder, itemInfo); + if (mHotseatPredictionController != null) { + mHotseatPredictionController.folderConvertedToWorkspaceItem(itemInfo, folder.getInfo()); } - return fi; } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java index 644cfcb3a5..a1c837861d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -33,6 +33,7 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; +import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; import android.graphics.Rect; import android.view.View; @@ -125,7 +126,8 @@ public class OverviewState extends LauncherState { @Override public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) { - if (this == OVERVIEW && ENABLE_OVERVIEW_ACTIONS.get()) { + if (this == OVERVIEW && ENABLE_OVERVIEW_ACTIONS.get() + && removeShelfFromOverview(launcher)) { // Treat the QSB as part of the hotseat so they move together. return getHotseatScaleAndTranslation(launcher); } @@ -158,7 +160,7 @@ public class OverviewState extends LauncherState { if (launcher.getDeviceProfile().isVerticalBarLayout()) { return VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON; } else { - if (ENABLE_OVERVIEW_ACTIONS.get()) { + if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(launcher)) { return VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON; } @@ -229,6 +231,7 @@ public class OverviewState extends LauncherState { builder.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2); builder.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2); Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get() + && removeShelfFromOverview(launcher) ? OVERSHOOT_1_2 : OVERSHOOT_1_7; builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java index 28fc3dadd5..1b6d291e19 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java @@ -234,6 +234,7 @@ public final class LauncherActivityInterface implements BaseActivityInterface windowAnim.addAnimatorListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { + if (mRecentsAnimationController == null) { + // If the recents animation is interrupted, we still end the running + // animation (not canceled) so this is still called. In that case, we can + // skip doing any future work here for the current gesture. + return; + } // Finalize the state and notify of the change mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED); } @@ -939,6 +944,12 @@ public class LauncherSwipeHandler windowAnim.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { + if (mRecentsAnimationController == null) { + // If the recents animation is interrupted, we still end the running + // animation (not canceled) so this is still called. In that case, we can + // skip doing any future work here for the current gesture. + return; + } if (target == NEW_TASK && mRecentsView != null && mRecentsView.getNextPage() == mRecentsView.getRunningTaskIndex()) { // We are about to launch the current running task, so use LAST_TASK state @@ -973,7 +984,7 @@ public class LauncherSwipeHandler } mLauncherTransitionController.getAnimationPlayer().setDuration(Math.max(0, duration)); - if (QUICKSTEP_SPRINGS.get()) { + if (UNSTABLE_SPRINGS.get()) { mLauncherTransitionController.dispatchOnStartWithVelocity(end, velocityPxPerMs.y); } mLauncherTransitionController.getAnimationPlayer().start(); @@ -1142,8 +1153,7 @@ public class LauncherSwipeHandler final int runningTaskId = mGestureState.getRunningTaskId(); if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { if (mRecentsAnimationController != null) { - SharedApiCompat.setWillFinishToHome(mRecentsAnimationController.getController(), - true /* willFinishToHome */); + mRecentsAnimationController.getController().setWillFinishToHome(true); // Update the screenshot of the task if (mTaskSnapshot == null) { mTaskSnapshot = mRecentsAnimationController.screenshotTask(runningTaskId); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index 3e6def3dfa..34b2bdb4a8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -1,23 +1,18 @@ package com.android.quickstep; -import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; - +import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.Log; -import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.testing.TestInformationHandler; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController; import com.android.quickstep.util.LayoutUtils; -import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.recents.model.Task; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class QuickstepTestInformationHandler extends TestInformationHandler { @@ -46,33 +41,8 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { } case TestProtocol.REQUEST_HOTSEAT_TOP: { - if (mLauncher == null) return null; - - response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, - PortraitStatesTouchController.getHotseatTop(mLauncher)); - return response; - } - - case TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN: { - try { - final int leftMargin = MAIN_EXECUTOR.submit(() -> - getRecentsView().getLeftGestureMargin()).get(); - response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, leftMargin); - } catch (ExecutionException | InterruptedException e) { - throw new RuntimeException(e); - } - return response; - } - - case TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN: { - try { - final int rightMargin = MAIN_EXECUTOR.submit(() -> - getRecentsView().getRightGestureMargin()).get(); - response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, rightMargin); - } catch (ExecutionException | InterruptedException e) { - throw new RuntimeException(e); - } - return response; + return getLauncherUIProperty( + Bundle::putInt, PortraitStatesTouchController::getHotseatTop); } case TestProtocol.REQUEST_RECENT_TASKS_LIST: { @@ -99,11 +69,12 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { return super.call(method); } - private RecentsView getRecentsView() { + @Override + protected Activity getCurrentActivity() { OverviewComponentObserver observer = new OverviewComponentObserver(mContext, new RecentsAnimationDeviceState(mContext)); try { - return observer.getActivityInterface().getCreatedActivity().getOverviewPanel(); + return observer.getActivityInterface().getCreatedActivity(); } finally { observer.onDestroy(); } @@ -111,11 +82,6 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { @Override protected boolean isLauncherInitialized() { - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, - "isLauncherInitialized.TouchInteractionService.isInitialized=" + - TouchInteractionService.isInitialized()); - } return super.isLauncherInitialized() && TouchInteractionService.isInitialized(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 6af6da35bc..582002921f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -142,16 +142,13 @@ public class TouchInteractionService extends Service implements PluginListener ActiveGestureLog.INSTANCE.addLog("startQuickstep"); } if (mInputMonitor != null) { - TestLogging.recordEvent("pilferPointers"); + TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers"); mInputMonitor.pilferPointers(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java index 6bfc3fd6b9..823b254d80 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java @@ -23,6 +23,7 @@ import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.logging.StatsLogUtils; import com.android.launcher3.testing.TestLogging; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.quickstep.GestureState; @@ -64,7 +65,7 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer { private void onInterceptTouch() { if (mInputMonitor != null) { - TestLogging.recordEvent("pilferPointers"); + TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers"); mInputMonitor.pilferPointers(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index cc10ca92f4..a673ab61b7 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -73,7 +73,6 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; -import android.view.WindowInsets; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ListView; @@ -345,7 +344,7 @@ public abstract class RecentsView extends PagedView impl setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); mTaskTopMargin = getResources() .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin); - mTaskBottomMargin = LayoutUtils.thumbnailBottomMargin(getResources()); + mTaskBottomMargin = LayoutUtils.thumbnailBottomMargin(context); mSquaredTouchSlop = squaredTouchSlop(context); mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents); @@ -1251,7 +1250,7 @@ public abstract class RecentsView extends PagedView impl } public PendingAnimation createAllTasksDismissAnimation(long duration) { - if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) { + if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) { throw new IllegalStateException("Another pending animation is still running"); } AnimatorSet anim = new AnimatorSet(); @@ -1595,7 +1594,7 @@ public abstract class RecentsView extends PagedView impl } public PendingAnimation createTaskLauncherAnimation(TaskView tv, long duration) { - if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) { + if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) { throw new IllegalStateException("Another pending animation is still running"); } @@ -1889,16 +1888,6 @@ public abstract class RecentsView extends PagedView impl } } - public int getLeftGestureMargin() { - final WindowInsets insets = getRootWindowInsets(); - return Math.max(insets.getSystemGestureInsets().left, insets.getSystemWindowInsetLeft()); - } - - public int getRightGestureMargin() { - final WindowInsets insets = getRootWindowInsets(); - return Math.max(insets.getSystemGestureInsets().right, insets.getSystemWindowInsetRight()); - } - /** If it's in the live tile mode, switch the running task into screenshot mode. */ public void switchToScreenshot(ThumbnailData thumbnailData, Runnable onFinishRunnable) { TaskView taskView = getRunningTaskView(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java index 49f667ecb7..8ed139269a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java @@ -54,6 +54,7 @@ import com.android.systemui.plugins.OverviewScreenshotActions; import com.android.systemui.plugins.PluginListener; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.system.ConfigurationCompat; /** * A task in the Recents view. @@ -357,7 +358,8 @@ public class TaskThumbnailView extends View implements PluginListener resultCallback, Handler resultCallbackHandler) { if (mTask != null) { final ActivityOptions opts; - if (Utilities.IS_RUNNING_IN_TEST_HARNESS) { - TestLogging.recordEvent("startActivityFromRecentsAsync:" + mTask); - } + TestLogging.recordEvent( + TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask); if (animate) { opts = mActivity.getActivityLaunchOptions(this); if (freezeTaskList) { @@ -679,9 +680,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private final int mMarginBottom; private FullscreenDrawParams mFullscreenParams; - TaskOutlineProvider(Resources res, FullscreenDrawParams fullscreenParams) { - mMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin); - mMarginBottom = LayoutUtils.thumbnailBottomMargin(res); + TaskOutlineProvider(Context context, FullscreenDrawParams fullscreenParams) { + mMarginTop = context.getResources().getDimensionPixelSize( + R.dimen.task_thumbnail_top_margin); + mMarginBottom = LayoutUtils.thumbnailBottomMargin(context); mFullscreenParams = fullscreenParams; } diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index 5f81e1f5e5..45a62ab151 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -67,13 +67,13 @@ Close - Get suggested apps on the home screen + Easily access your most-used apps - Tap to set up + Pixel suggests your favorite apps based on your routines. Tap to learn more. Suggested apps replace the bottom row of apps - To pin a favorite app, drag it over a suggested app. To hide a suggested app, touch & hold it. + Your current apps will move to the last screen. To pin or block a suggested app, drag it off the bottom row. Bottom row of apps moved to last screen diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index 8eb639b65c..44704077ea 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -25,6 +25,7 @@ import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_COUNT; import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN; import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_COUNT; import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN; +import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; import android.animation.AnimatorSet; import android.animation.ValueAnimator; @@ -35,6 +36,7 @@ import android.os.CancellationSignal; import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.LauncherStateManager.StateHandler; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.WellbeingModel; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.proxy.ProxyActivityStarter; @@ -172,7 +174,7 @@ public abstract class BaseQuickstepLauncher extends Launcher @Override public void startActivityForResult(Intent intent, int requestCode, Bundle options) { if (requestCode != -1) { - mPendingActivityRequestCode = -1; + mPendingActivityRequestCode = requestCode; StartActivityParams params = new StartActivityParams(this, requestCode); params.intent = intent; params.options = options; @@ -193,6 +195,16 @@ public abstract class BaseQuickstepLauncher extends Launcher } } + @Override + protected void setupViews() { + super.setupViews(); + + if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) { + // Overview is above all other launcher elements, including qsb, so move it to the top. + getOverviewPanel().bringToFront(); + } + } + @Override protected StateHandler[] createStateHandlers() { return new StateHandler[] { diff --git a/quickstep/src/com/android/launcher3/uioverrides/DisplayRotationListener.java b/quickstep/src/com/android/launcher3/uioverrides/DisplayRotationListener.java deleted file mode 100644 index 2d9a161475..0000000000 --- a/quickstep/src/com/android/launcher3/uioverrides/DisplayRotationListener.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2018 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.uioverrides; - -import android.content.Context; -import android.os.Handler; - -import com.android.systemui.shared.system.RotationWatcher; - -/** - * Utility class for listening for rotation changes - */ -public class DisplayRotationListener extends RotationWatcher { - - private final Runnable mCallback; - private Handler mHandler; - - public DisplayRotationListener(Context context, Runnable callback) { - super(context); - mCallback = callback; - } - - @Override - public void enable() { - if (mHandler == null) { - mHandler = new Handler(); - } - super.enable(); - } - - @Override - protected void onRotationChanged(int i) { - mHandler.post(mCallback); - } -} diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java index 6e7c087bb7..2e422b77f6 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java +++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java @@ -14,8 +14,12 @@ package com.android.launcher3.uioverrides.plugins; +import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; + import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.systemui.plugins.Plugin; @@ -24,6 +28,9 @@ import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginManagerImpl; import com.android.systemui.shared.plugins.PluginPrefs; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; import java.util.Set; public class PluginManagerWrapper { @@ -75,4 +82,27 @@ public class PluginManagerWrapper { public static boolean hasPlugins(Context context) { return PluginPrefs.hasPlugins(context); } + + public void dump(PrintWriter pw) { + final List enabledPlugins = new ArrayList<>(); + final List disabledPlugins = new ArrayList<>(); + for (String action : getPluginActions()) { + for (ResolveInfo resolveInfo : mContext.getPackageManager().queryIntentServices( + new Intent(action), MATCH_DISABLED_COMPONENTS)) { + ComponentName installedPlugin = new ComponentName( + resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); + if (mPluginEnabler.isEnabled(installedPlugin)) { + enabledPlugins.add(installedPlugin); + } else { + disabledPlugins.add(installedPlugin); + } + } + } + + pw.println("PluginManager:"); + pw.println(" numEnabledPlugins=" + enabledPlugins.size()); + pw.println(" numDisabledPlugins=" + disabledPlugins.size()); + pw.println(" enabledPlugins=" + enabledPlugins); + pw.println(" disabledPlugins=" + disabledPlugins); + } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index 99b2a81386..d5ce73429d 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -25,7 +25,7 @@ import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRE import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.LINEAR; -import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS; +import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import android.animation.TimeInterpolator; @@ -277,7 +277,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr private void handleFirstSwipeToOverview(final ValueAnimator animator, final long expectedDuration, final LauncherState targetState, final float velocity, final boolean isFling) { - if (QUICKSTEP_SPRINGS.get() && mFromState == OVERVIEW && mToState == ALL_APPS + if (UNSTABLE_SPRINGS.get() && mFromState == OVERVIEW && mToState == ALL_APPS && targetState == OVERVIEW) { mFinishFastOnSecondTouch = true; } else if (mFromState == NORMAL && mToState == OVERVIEW && targetState == OVERVIEW) { diff --git a/quickstep/src/com/android/quickstep/MultiStateCallback.java b/quickstep/src/com/android/quickstep/MultiStateCallback.java index 6c65e01c20..b3875aef52 100644 --- a/quickstep/src/com/android/quickstep/MultiStateCallback.java +++ b/quickstep/src/com/android/quickstep/MultiStateCallback.java @@ -130,7 +130,7 @@ public class MultiStateCallback { final LinkedList callbacks; if (mCallbacks.indexOfKey(stateMask) >= 0) { callbacks = mCallbacks.get(stateMask); - if (FeatureFlags.IS_DOGFOOD_BUILD && callbacks.contains(callback)) { + if (FeatureFlags.IS_STUDIO_BUILD && callbacks.contains(callback)) { throw new IllegalStateException("Existing callback for state found"); } } else { diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java index 73b78db6cd..85ef4c6a91 100644 --- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java +++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java @@ -35,6 +35,7 @@ import android.util.SparseIntArray; import com.android.systemui.shared.system.PackageManagerWrapper; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Objects; @@ -233,4 +234,13 @@ public final class OverviewComponentObserver { public BaseActivityInterface getActivityInterface() { return mActivityInterface; } + + public void dump(PrintWriter pw) { + pw.println("OverviewComponentObserver:"); + pw.println(" isDefaultHome=" + mIsDefaultHome); + pw.println(" isHomeDisabled=" + mIsHomeDisabled); + pw.println(" homeAndOverviewSame=" + mIsHomeAndOverviewSame); + pw.println(" overviewIntent=" + mOverviewIntent); + pw.println(" homeIntent=" + mCurrentHomeIntent); + } } diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java index 9817e32ae9..32268a49b5 100644 --- a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java +++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java @@ -15,11 +15,6 @@ */ package com.android.quickstep; -import static android.content.Context.MODE_PRIVATE; - -import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; -import static com.android.launcher3.config.FeatureFlags.FLAGS_PREF_NAME; - import android.content.Context; import android.content.pm.PackageManager; import android.os.UserManager; @@ -27,7 +22,6 @@ import android.util.Log; import com.android.launcher3.BuildConfig; import com.android.launcher3.MainProcessInitializer; -import com.android.launcher3.config.FeatureFlags; import com.android.systemui.shared.system.ThreadedRendererCompat; @SuppressWarnings("unused") @@ -55,22 +49,7 @@ public class QuickstepProcessInitializer extends MainProcessInitializer { super.init(context); // Elevate GPU priority for Quickstep and Remote animations. - ThreadedRendererCompat.setContextPriority(ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG); - - // Force disable some feature flags based on the system ui navigation mode. - SysUINavigationMode.Mode currMode = SysUINavigationMode.INSTANCE.get(context) - .addModeChangeListener(mode -> disableFeatureFlagsForSysuiNavMode(context, mode)); - disableFeatureFlagsForSysuiNavMode(context, currMode); - } - - private void disableFeatureFlagsForSysuiNavMode(Context ctx, SysUINavigationMode.Mode mode) { - if (mode == SysUINavigationMode.Mode.TWO_BUTTONS) { - ctx.getSharedPreferences(FLAGS_PREF_NAME, MODE_PRIVATE) - .edit() - .putBoolean(ENABLE_OVERVIEW_ACTIONS.key, false) - .apply(); - - FeatureFlags.initialize(ctx); - } + ThreadedRendererCompat.setContextPriority( + ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG); } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java index acf61b4142..0f98b325fa 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java @@ -62,6 +62,12 @@ public class RecentsAnimationCallbacks implements mListeners.remove(listener); } + @UiThread + public void removeAllListeners() { + Preconditions.assertUIThread(); + mListeners.clear(); + } + public void notifyAnimationCanceled() { mCancelled = true; onAnimationCanceled(null); diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java index d3be0b9c47..21a4918b1b 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -198,6 +198,7 @@ public class RecentsAnimationController { if (mInputConsumerController != null) { mInputConsumerController.setInputListener(null); } + mInputProxySupplier = null; } private boolean onInputConsumerEvent(InputEvent ev) { diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index d0afb214ab..4b33d21cba 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -180,7 +180,7 @@ public class RecentsAnimationDeviceState implements mDefaultDisplay.addChangeListener(this); } - if (mMode == NO_BUTTON) { + if (newMode == NO_BUTTON) { mExclusionListener.register(); } else { mExclusionListener.unregister(); diff --git a/quickstep/src/com/android/quickstep/SysUINavigationMode.java b/quickstep/src/com/android/quickstep/SysUINavigationMode.java index 388b323a50..375e589603 100644 --- a/quickstep/src/com/android/quickstep/SysUINavigationMode.java +++ b/quickstep/src/com/android/quickstep/SysUINavigationMode.java @@ -122,6 +122,12 @@ public class SysUINavigationMode { } } + /** @return Whether we can remove the shelf from overview. */ + public static boolean removeShelfFromOverview(Context context) { + // The shelf is core to the two-button mode model, so we need to continue supporting it. + return getMode(context) != Mode.TWO_BUTTONS; + } + public interface NavigationModeChangeListener { void onNavigationModeChanged(Mode newMode); diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index d9cb240c19..458d6a9553 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -29,7 +29,6 @@ import android.util.Log; import android.view.MotionEvent; import com.android.launcher3.util.MainThreadInitializedObject; -import com.android.quickstep.util.SharedApiCompat; import com.android.systemui.shared.recents.ISystemUiProxy; /** @@ -278,7 +277,7 @@ public class SystemUiProxy implements ISystemUiProxy { mLastShelfVisible = visible; mLastShelfHeight = shelfHeight; try { - SharedApiCompat.setShelfHeight(mSystemUiProxy, visible, shelfHeight); + mSystemUiProxy.setShelfHeight(visible, shelfHeight); } catch (RemoteException e) { Log.w(TAG, "Failed call setShelfHeight visible: " + visible + " height: " + shelfHeight, e); diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index e3e8ace96b..6902e37613 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -55,7 +55,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn // Notify if recents animation is still running if (mController != null) { String msg = "New recents animation started before old animation completed"; - if (FeatureFlags.IS_DOGFOOD_BUILD) { + if (FeatureFlags.IS_STUDIO_BUILD) { throw new IllegalArgumentException(msg); } else { Log.e("TaskAnimationManager", msg, new Exception()); @@ -156,9 +156,9 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mTargets.release(); } - // Remove gesture state from callbacks - if (mCallbacks != null && mLastGestureState != null) { - mCallbacks.removeListener(mLastGestureState); + // Clean up all listeners to ensure we don't get subsequent callbacks + if (mCallbacks != null) { + mCallbacks.removeAllListeners(); } mController = null; diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialActivity.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialActivity.java index 295ab4897e..d2a0951c62 100644 --- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialActivity.java +++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialActivity.java @@ -16,7 +16,10 @@ package com.android.quickstep.interaction; import android.graphics.Color; +import android.graphics.Rect; import android.os.Bundle; +import android.util.DisplayMetrics; +import android.view.Display; import android.view.View; import android.view.Window; @@ -26,6 +29,7 @@ import com.android.launcher3.R; import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialStep; import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialType; +import java.util.List; import java.util.Optional; /** Shows the Back gesture interactive tutorial in full screen mode. */ @@ -46,6 +50,12 @@ public class BackGestureTutorialActivity extends FragmentActivity { .commit(); } + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + disableSystemGestures(); + } + @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); @@ -70,4 +80,14 @@ public class BackGestureTutorialActivity extends FragmentActivity { | View.SYSTEM_UI_FLAG_FULLSCREEN); getWindow().setNavigationBarColor(Color.TRANSPARENT); } + + private void disableSystemGestures() { + Display display = getDisplay(); + if (display != null) { + DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + getWindow().setSystemGestureExclusionRects( + List.of(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels))); + } + } } diff --git a/quickstep/src/com/android/quickstep/util/BinderTracker.java b/quickstep/src/com/android/quickstep/util/BinderTracker.java index 32d0d53779..cb04e5b015 100644 --- a/quickstep/src/com/android/quickstep/util/BinderTracker.java +++ b/quickstep/src/com/android/quickstep/util/BinderTracker.java @@ -31,7 +31,7 @@ public class BinderTracker { private static final String TAG = "BinderTracker"; public static void start() { - if (!FeatureFlags.IS_DOGFOOD_BUILD) { + if (!FeatureFlags.IS_STUDIO_BUILD) { Log.wtf(TAG, "Accessing tracker in released code.", new Exception()); return; } @@ -40,7 +40,7 @@ public class BinderTracker { } public static void stop() { - if (!FeatureFlags.IS_DOGFOOD_BUILD) { + if (!FeatureFlags.IS_STUDIO_BUILD) { Log.wtf(TAG, "Accessing tracker in released code.", new Exception()); return; } diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java index b249f48389..1d8a79f683 100644 --- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java +++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java @@ -16,6 +16,7 @@ package com.android.quickstep.util; import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; +import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -59,7 +60,7 @@ public class LayoutUtils { } else { Resources res = context.getResources(); - if (ENABLE_OVERVIEW_ACTIONS.get()) { + if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) { //TODO: this needs to account for the swipe gesture height and accessibility // UI when shown. extraSpace = 0; @@ -83,6 +84,7 @@ public class LayoutUtils { float taskWidth, taskHeight, paddingHorz; Resources res = context.getResources(); Rect insets = dp.getInsets(); + final boolean overviewActionsEnabled = ENABLE_OVERVIEW_ACTIONS.get(); if (dp.isMultiWindowMode) { if (multiWindowStrategy == MULTI_WINDOW_STRATEGY_HALF_SCREEN) { @@ -112,7 +114,7 @@ public class LayoutUtils { final int paddingResId; if (dp.isVerticalBarLayout()) { paddingResId = R.dimen.landscape_task_card_horz_space; - } else if (ENABLE_OVERVIEW_ACTIONS.get()) { + } else if (overviewActionsEnabled && removeShelfFromOverview(context)) { paddingResId = R.dimen.portrait_task_card_horz_space_big_overview; } else { paddingResId = R.dimen.portrait_task_card_horz_space; @@ -120,9 +122,11 @@ public class LayoutUtils { paddingHorz = res.getDimension(paddingResId); } - float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin); - float bottomMargin = thumbnailBottomMargin(res); - float paddingVert = res.getDimension(R.dimen.task_card_vert_space); + float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin); + float bottomMargin = thumbnailBottomMargin(context); + + float paddingVert = overviewActionsEnabled && removeShelfFromOverview(context) + ? 0 : res.getDimension(R.dimen.task_card_vert_space); // Note this should be same as dp.availableWidthPx and dp.availableHeightPx unless // we override the insets ourselves. @@ -140,14 +144,14 @@ public class LayoutUtils { // Center in the visible space float x = insets.left + (launcherVisibleWidth - outWidth) / 2; float y = insets.top + Math.max(topIconMargin, - (launcherVisibleHeight - extraVerticalSpace - outHeight) / 2); + (launcherVisibleHeight - extraVerticalSpace - outHeight - bottomMargin) / 2); outRect.set(Math.round(x), Math.round(y), Math.round(x) + Math.round(outWidth), Math.round(y) + Math.round(outHeight)); } public static int getShelfTrackingDistance(Context context, DeviceProfile dp) { // Track the bottom of the window. - if (ENABLE_OVERVIEW_ACTIONS.get()) { + if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) { Rect taskSize = new Rect(); calculateLauncherTaskSize(context, dp, taskSize); return (dp.heightPx - taskSize.height()) / 2; @@ -162,9 +166,9 @@ public class LayoutUtils { * Get the margin that the task thumbnail view should use. * @return the margin in pixels. */ - public static int thumbnailBottomMargin(Resources resources) { - if (ENABLE_OVERVIEW_ACTIONS.get()) { - return resources.getDimensionPixelSize(R.dimen.overview_actions_height); + public static int thumbnailBottomMargin(Context context) { + if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) { + return context.getResources().getDimensionPixelSize(R.dimen.overview_actions_height); } else { return 0; } diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java index 7ed1e21dfb..1ce3549f39 100644 --- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java +++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java @@ -160,7 +160,8 @@ public class ShelfScrimView extends ScrimView Context context = getContext(); if ((OVERVIEW.getVisibleElements(mLauncher) & ALL_APPS_HEADER_EXTRA) == 0) { mDragHandleProgress = 1; - if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) { + if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() + && SysUINavigationMode.removeShelfFromOverview(context)) { // Fade in all apps background quickly to distinguish from swiping from nav bar. mMidAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha); mMidProgress = OverviewState.getDefaultVerticalProgress(mLauncher); diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java index 97424bb8f9..1229a637b4 100644 --- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java +++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java @@ -197,7 +197,8 @@ public class NavigationModeSwitchRule implements TestRule { Wait.atMost(() -> "Switching nav mode: " + launcher.getNavigationModeMismatchError(), - () -> launcher.getNavigationModeMismatchError() == null, WAIT_TIME_MS, launcher); + () -> launcher.getNavigationModeMismatchError() == null, + 60000 /* b/148422894 */, launcher); return true; } diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java index d2f5d8f097..724af66836 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java @@ -25,7 +25,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.content.Intent; -import android.os.RemoteException; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; @@ -48,7 +47,6 @@ import com.android.quickstep.views.RecentsView; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -83,17 +81,6 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { isInBackground(launcher))); } - @Test - @PortraitLandscape - @Ignore // Enable after b/131115533 - public void testPressRecentAppsLauncherAndGetOverview() throws RemoteException { - mDevice.pressRecentApps(); - waitForState("Launcher internal state didn't switch to Overview", - () -> LauncherState.OVERVIEW); - - assertNotNull("getOverview() returned null", mLauncher.getOverview()); - } - @Test @NavigationModeSwitch @PortraitLandscape @@ -271,10 +258,8 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { @Test @NavigationModeSwitch @PortraitLandscape - // b/143285809 Remove @Stability on 02/21/20 if the test doesn't flake. + // b/143285809 Remove @Stability on 02/27/20 if the test doesn't flake. @TestStabilityRule.Stability(flavors = LOCAL | UNBUNDLED_POSTSUBMIT) - // b/143285809 - @Ignore public void testQuickSwitchFromApp() throws Exception { startTestActivity(2); startTestActivity(3); diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml index 893d79654f..923352e707 100644 --- a/res/layout/user_folder_icon_normalized.xml +++ b/res/layout/user_folder_icon_normalized.xml @@ -46,9 +46,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" + style="@style/TextHeadline" android:layout_weight="1" android:background="@android:color/transparent" - android:fontFamily="sans-serif-condensed" android:textStyle="bold" android:gravity="center_horizontal" android:hint="@string/folder_hint_text" @@ -58,7 +58,7 @@ android:singleLine="true" android:textColor="?attr/folderTextColor" android:textColorHighlight="?android:attr/colorControlHighlight" - android:textColorHint="?attr/folderTextColor" + android:textColorHint="?attr/folderHintColor" android:textSize="@dimen/folder_label_text_size" /> diff --git a/res/layout/work_tab_footer.xml b/res/layout/work_tab_footer.xml index db95416b33..2cffedd2a6 100644 --- a/res/layout/work_tab_footer.xml +++ b/res/layout/work_tab_footer.xml @@ -32,6 +32,8 @@ android:layout_weight="1" android:drawableStart="@drawable/ic_corp" android:drawablePadding="3dp" + android:drawableTint="?attr/workProfileOverlayTextColor" + android:textColor="?attr/workProfileOverlayTextColor" android:layout_height="wrap_content" android:ellipsize="end" android:gravity="center_vertical" diff --git a/res/values/attrs.xml b/res/values/attrs.xml index de17eb7b4f..5a15ec66cc 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -40,6 +40,8 @@ + + @@ -115,6 +117,7 @@ + diff --git a/res/values/strings.xml b/res/values/strings.xml index bfa92f7537..0775c0c530 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -142,7 +142,7 @@ This is a system app and can\'t be uninstalled. - Unnamed Folder + Edit Name diff --git a/res/values/styles.xml b/res/values/styles.xml index 35ae49c8ee..cee268b28d 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -48,7 +48,9 @@ #CDFFFFFF ?android:attr/colorPrimary #FF212121 + #FF616161 #CCFFFFFF + #FF212121 false false @@ -76,6 +78,7 @@ #CDFFFFFF #FF80868B ?attr/workspaceTextColor +