Snap for 6224475 from 98e484548c to rvc-release
Change-Id: I9a0f573059b3a664c2d90b1cad26343959f68998
This commit is contained in:
+2
-1
@@ -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"],
|
||||
}
|
||||
|
||||
+11
-3
@@ -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
|
||||
|
||||
@@ -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<ComponentWithLabel> update(LauncherAppState app,
|
||||
public List<ComponentWithLabelAndIcon> update(LauncherAppState app,
|
||||
@Nullable PackageUserKey packageUser) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -34,6 +34,10 @@ public interface CachingLogic<T> {
|
||||
|
||||
CharSequence getLabel(T object);
|
||||
|
||||
default CharSequence getDescription(T object, CharSequence fallback) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
BitmapInfo loadIcon(Context context, T object);
|
||||
|
||||
|
||||
+14
-3
@@ -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<String, PackageInfo> mPkgInfoMap;
|
||||
private final BaseIconCache mIconCache;
|
||||
|
||||
private final HashMap<UserHandle, Set<String>> mPackagesToIgnore = new HashMap<>();
|
||||
private final ArrayMap<UserHandle, Set<String>> 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<String> packages) {
|
||||
mPackagesToIgnore.put(userHandle, packages);
|
||||
/**
|
||||
* Sets a package to ignore for processing
|
||||
*/
|
||||
public void addPackagesToIgnore(UserHandle userHandle, String packageName) {
|
||||
Set<String> 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);
|
||||
|
||||
@@ -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.**
|
||||
@@ -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 {
|
||||
|
||||
+1
-9
@@ -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<ShortcutInfo> 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) {
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+28
@@ -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);
|
||||
|
||||
+40
-6
@@ -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<WorkspaceItemInfo> 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) {
|
||||
|
||||
+1
@@ -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;
|
||||
|
||||
+31
-7
@@ -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
|
||||
|
||||
+5
-2
@@ -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);
|
||||
|
||||
+1
@@ -234,6 +234,7 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
|
||||
public void adjustActivityControllerInterpolators() {
|
||||
if (mAdjustInterpolatorsRunnable != null) {
|
||||
mAdjustInterpolatorsRunnable.run();
|
||||
mAdjustInterpolatorsRunnable = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
|
||||
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
|
||||
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
|
||||
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
|
||||
import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
|
||||
@@ -75,7 +75,6 @@ import com.android.quickstep.inputconsumers.OverviewInputConsumer;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider;
|
||||
import com.android.quickstep.util.RectFSpringAnim;
|
||||
import com.android.quickstep.util.SharedApiCompat;
|
||||
import com.android.quickstep.util.ShelfPeekAnim;
|
||||
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
|
||||
import com.android.quickstep.views.LiveTileOverlay;
|
||||
@@ -918,6 +917,12 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
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<T extends BaseDraggingActivity>
|
||||
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<T extends BaseDraggingActivity>
|
||||
}
|
||||
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<T extends BaseDraggingActivity>
|
||||
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);
|
||||
|
||||
+6
-40
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+9
-16
@@ -142,16 +142,13 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
TouchInteractionService.this.initInputMonitor();
|
||||
preloadOverview(true /* fromInit */);
|
||||
});
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "TIS initialized");
|
||||
}
|
||||
sIsInitialized = true;
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void onOverviewToggle() {
|
||||
TestLogging.recordEvent("onOverviewToggle");
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
|
||||
mOverviewCommandHelper.onOverviewToggle();
|
||||
}
|
||||
|
||||
@@ -411,9 +408,6 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "TIS destroyed");
|
||||
}
|
||||
sIsInitialized = false;
|
||||
if (mDeviceState.isUserUnlocked()) {
|
||||
mInputConsumer.unregisterInputConsumer();
|
||||
@@ -444,13 +438,17 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
Log.e(TAG, "Unknown event " + ev);
|
||||
return;
|
||||
}
|
||||
MotionEvent event = (MotionEvent) ev;
|
||||
|
||||
TestLogging.recordMotionEvent(
|
||||
TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event);
|
||||
|
||||
if (!mDeviceState.isUserUnlocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
|
||||
TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
|
||||
MotionEvent event = (MotionEvent) ev;
|
||||
if (event.getAction() == ACTION_DOWN) {
|
||||
GestureState newGestureState = new GestureState(mOverviewComponentObserver,
|
||||
ActiveGestureLog.INSTANCE.generateAndSetLogId());
|
||||
@@ -731,20 +729,15 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
}
|
||||
} else {
|
||||
// Dump everything
|
||||
FeatureFlags.dump(pw);
|
||||
PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
|
||||
mDeviceState.dump(pw);
|
||||
mOverviewComponentObserver.dump(pw);
|
||||
pw.println("TouchState:");
|
||||
boolean resumed = mOverviewComponentObserver != null
|
||||
&& mOverviewComponentObserver.getActivityInterface().isResumed();
|
||||
pw.println(" resumed=" + resumed);
|
||||
pw.println(" mConsumer=" + mConsumer.getName());
|
||||
pw.println("FeatureFlags:");
|
||||
pw.println(" APPLY_CONFIG_AT_RUNTIME=" + APPLY_CONFIG_AT_RUNTIME.get());
|
||||
pw.println(" QUICKSTEP_SPRINGS=" + QUICKSTEP_SPRINGS.get());
|
||||
pw.println(" UNSTABLE_SPRINGS=" + UNSTABLE_SPRINGS.get());
|
||||
pw.println(" ADAPTIVE_ICON_WINDOW_ANIM=" + ADAPTIVE_ICON_WINDOW_ANIM.get());
|
||||
pw.println(" ENABLE_QUICKSTEP_LIVE_TILE=" + ENABLE_QUICKSTEP_LIVE_TILE.get());
|
||||
pw.println(" ENABLE_HINTS_IN_OVERVIEW=" + ENABLE_HINTS_IN_OVERVIEW.get());
|
||||
pw.println(" FAKE_LANDSCAPE_UI=" + FAKE_LANDSCAPE_UI.get());
|
||||
ActiveGestureLog.INSTANCE.dump("", pw);
|
||||
pw.println("ProtoTrace:");
|
||||
pw.println(" file="
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@ package com.android.quickstep.inputconsumers;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.quickstep.InputConsumer;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
|
||||
@@ -35,7 +36,7 @@ public abstract class DelegateInputConsumer implements InputConsumer {
|
||||
|
||||
protected void setActive(MotionEvent ev) {
|
||||
mState = STATE_ACTIVE;
|
||||
TestLogging.recordEvent("pilferPointers");
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers");
|
||||
mInputMonitor.pilferPointers();
|
||||
|
||||
// Send cancel event
|
||||
|
||||
+2
-1
@@ -38,6 +38,7 @@ import android.view.ViewConfiguration;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.DefaultDisplay;
|
||||
import com.android.quickstep.GestureState;
|
||||
import com.android.quickstep.InputConsumer;
|
||||
@@ -203,7 +204,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
|
||||
|
||||
private void startRecentsTransition() {
|
||||
mThresholdCrossed = true;
|
||||
TestLogging.recordEvent("pilferPointers");
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers");
|
||||
mInputMonitorCompat.pilferPointers();
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_MAIN)
|
||||
|
||||
+2
-1
@@ -45,6 +45,7 @@ import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
import com.android.quickstep.BaseActivityInterface;
|
||||
@@ -303,7 +304,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
if (mInteractionHandler == null) {
|
||||
return;
|
||||
}
|
||||
TestLogging.recordEvent("pilferPointers");
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers");
|
||||
mInputMonitorCompat.pilferPointers();
|
||||
|
||||
mActivityInterface.closeOverlay();
|
||||
|
||||
+2
-1
@@ -26,6 +26,7 @@ import androidx.annotation.Nullable;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.BaseActivityInterface;
|
||||
import com.android.quickstep.GestureState;
|
||||
@@ -107,7 +108,7 @@ public class OverviewInputConsumer<T extends BaseDraggingActivity>
|
||||
ActiveGestureLog.INSTANCE.addLog("startQuickstep");
|
||||
}
|
||||
if (mInputMonitor != null) {
|
||||
TestLogging.recordEvent("pilferPointers");
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers");
|
||||
mInputMonitor.pilferPointers();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T extends BaseActivity> 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<T extends BaseActivity> 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<T extends BaseActivity> 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<T extends BaseActivity> 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();
|
||||
|
||||
+3
-1
@@ -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<OverviewSc
|
||||
|
||||
final float thumbnailScale;
|
||||
int thumbnailRotation = mThumbnailData.rotation;
|
||||
int currentRotation = getDisplay() != null ? getDisplay().getRotation() : 0;
|
||||
int currentRotation = ConfigurationCompat.getWindowConfigurationRotation(
|
||||
getResources().getConfiguration());
|
||||
int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
|
||||
// Landscape vs portrait change
|
||||
boolean windowingModeSupportsRotation = !mActivity.isInMultiWindowMode()
|
||||
|
||||
@@ -22,6 +22,7 @@ import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LA
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -30,7 +31,6 @@ import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
@@ -58,6 +58,7 @@ import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
@@ -221,7 +222,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
mCurrentFullscreenParams = new FullscreenDrawParams(mCornerRadius);
|
||||
mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
|
||||
|
||||
mOutlineProvider = new TaskOutlineProvider(getResources(), mCurrentFullscreenParams);
|
||||
mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams);
|
||||
setOutlineProvider(mOutlineProvider);
|
||||
}
|
||||
|
||||
@@ -230,13 +231,14 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
super.onFinishInflate();
|
||||
mSnapshotView = findViewById(R.id.snapshot);
|
||||
mIconView = findViewById(R.id.icon);
|
||||
final Context context = getContext();
|
||||
|
||||
TaskView.LayoutParams thumbnailParams = (LayoutParams) mSnapshotView.getLayoutParams();
|
||||
thumbnailParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(getResources());
|
||||
thumbnailParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(context);
|
||||
mSnapshotView.setLayoutParams(thumbnailParams);
|
||||
|
||||
|
||||
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
|
||||
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
|
||||
mActionsView = mSnapshotView.getTaskOverlay().getActionsView();
|
||||
if (mActionsView != null) {
|
||||
TaskView.LayoutParams params = new TaskView.LayoutParams(LayoutParams.MATCH_PARENT,
|
||||
@@ -333,9 +335,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
Consumer<Boolean> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,13 +67,13 @@
|
||||
<string name="back_gesture_tutorial_close_button_content_description" translatable="false">Close</string>
|
||||
|
||||
<!-- Hotseat migration notification title -->
|
||||
<string translatable="false" name="hotseat_migrate_prompt_title">Get suggested apps on the home screen</string>
|
||||
<string translatable="false" name="hotseat_migrate_prompt_title">Easily access your most-used apps</string>
|
||||
<!-- Hotseat migration notification content -->
|
||||
<string translatable="false" name="hotseat_migrate_prompt_content">Tap to set up</string>
|
||||
<string translatable="false" name="hotseat_migrate_prompt_content">Pixel suggests your favorite apps based on your routines. Tap to learn more.</string>
|
||||
<!-- Hotseat migration wizard title -->
|
||||
<string translatable="false" name="hotseat_migrate_title">Suggested apps replace the bottom row of apps</string>
|
||||
<!-- Hotseat migration wizard message -->
|
||||
<string translatable="false" name="hotseat_migrate_message">To pin a favorite app, drag it over a suggested app. To hide a suggested app, touch & hold it.</string>
|
||||
<string translatable="false" name="hotseat_migrate_message">Your current apps will move to the last screen. To pin or block a suggested app, drag it off the bottom row.</string>
|
||||
<!-- Toast message user sees after opting into fully predicted hybrid hotseat -->
|
||||
<string translatable="false" name="hotseat_items_migrated">Bottom row of apps moved to last screen</string>
|
||||
<!-- Toast message user sees after opting into fully predicted hybrid hotseat -->
|
||||
|
||||
@@ -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[] {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<ComponentName> enabledPlugins = new ArrayList<>();
|
||||
final List<ComponentName> 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);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
@@ -130,7 +130,7 @@ public class MultiStateCallback {
|
||||
final LinkedList<Runnable> 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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -198,6 +198,7 @@ public class RecentsAnimationController {
|
||||
if (mInputConsumerController != null) {
|
||||
mInputConsumerController.setInputListener(null);
|
||||
}
|
||||
mInputProxySupplier = null;
|
||||
}
|
||||
|
||||
private boolean onInputConsumerEvent(InputEvent ev) {
|
||||
|
||||
@@ -180,7 +180,7 @@ public class RecentsAnimationDeviceState implements
|
||||
mDefaultDisplay.addChangeListener(this);
|
||||
}
|
||||
|
||||
if (mMode == NO_BUTTON) {
|
||||
if (newMode == NO_BUTTON) {
|
||||
mExclusionListener.register();
|
||||
} else {
|
||||
mExclusionListener.unregister();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,8 @@ public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" />
|
||||
|
||||
<com.android.launcher3.pageindicators.PageIndicatorDots
|
||||
|
||||
@@ -23,14 +23,14 @@
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:contentDescription="@string/work_apps_paused_title"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:tint="?attr/folderTextColor"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:tint="?attr/workProfileOverlayTextColor"
|
||||
android:src="@drawable/ic_corp_off" />
|
||||
|
||||
<TextView
|
||||
style="@style/TextHeadline"
|
||||
android:textColor="?attr/folderTextColor"
|
||||
android:textColor="?attr/workProfileOverlayTextColor"
|
||||
android:id="@+id/work_apps_paused_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -43,7 +43,7 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/folderTextColor"
|
||||
android:textColor="?attr/workProfileOverlayTextColor"
|
||||
android:text="@string/work_apps_paused_body"
|
||||
android:textAlignment="center"
|
||||
android:textSize="16sp" />
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
<attr name="folderIconRadius" format="float" />
|
||||
<attr name="folderIconBorderColor" format="color" />
|
||||
<attr name="folderTextColor" format="color" />
|
||||
<attr name="folderHintColor" format="color" />
|
||||
<attr name="workProfileOverlayTextColor" format="color" />
|
||||
|
||||
<!-- BubbleTextView specific attributes. -->
|
||||
<declare-styleable name="BubbleTextView">
|
||||
@@ -115,6 +117,7 @@
|
||||
<attr name="numFolderColumns" format="integer" />
|
||||
<!-- numHotseatIcons defaults to numColumns, if not specified -->
|
||||
<attr name="numHotseatIcons" format="integer" />
|
||||
<attr name="dbFile" format="string" />
|
||||
<attr name="defaultLayoutId" format="reference" />
|
||||
<attr name="demoModeLayoutId" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
<string name="uninstall_system_app_text">This is a system app and can\'t be uninstalled.</string>
|
||||
|
||||
<!-- Default folder title -->
|
||||
<string name="folder_hint_text">Unnamed Folder</string>
|
||||
<string name="folder_hint_text">Edit Name</string>
|
||||
|
||||
<!-- Accessibility -->
|
||||
<!-- The format string for when an app is temporarily disabled. -->
|
||||
|
||||
@@ -48,7 +48,9 @@
|
||||
<item name="folderFillColor">#CDFFFFFF</item>
|
||||
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
|
||||
<item name="folderTextColor">#FF212121</item>
|
||||
<item name="folderHintColor">#FF616161</item>
|
||||
<item name="loadingIconColor">#CCFFFFFF</item>
|
||||
<item name="workProfileOverlayTextColor">#FF212121</item>
|
||||
|
||||
<item name="android:windowTranslucentStatus">false</item>
|
||||
<item name="android:windowTranslucentNavigation">false</item>
|
||||
@@ -76,6 +78,7 @@
|
||||
<item name="folderFillColor">#CDFFFFFF</item>
|
||||
<item name="folderIconBorderColor">#FF80868B</item>
|
||||
<item name="folderTextColor">?attr/workspaceTextColor</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="LauncherTheme.Dark" parent="@style/LauncherTheme">
|
||||
@@ -96,8 +99,10 @@
|
||||
<item name="folderFillColor">#DD3C4043</item> <!-- 87% GM2 800 -->
|
||||
<item name="folderIconBorderColor">#FF80868B</item>
|
||||
<item name="folderTextColor">@android:color/white</item>
|
||||
<item name="folderHintColor">#FFCCCCCC</item>
|
||||
<item name="isMainColorDark">true</item>
|
||||
<item name="loadingIconColor">#99FFFFFF</item>
|
||||
<item name="workProfileOverlayTextColor">@android:color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark">
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
launcher:numFolderRows="2"
|
||||
launcher:numFolderColumns="3"
|
||||
launcher:numHotseatIcons="3"
|
||||
launcher:dbFile="launcher_3_by_3.db"
|
||||
launcher:defaultLayoutId="@xml/default_workspace_3x3" >
|
||||
|
||||
<display-option
|
||||
@@ -51,6 +52,7 @@
|
||||
launcher:numFolderRows="3"
|
||||
launcher:numFolderColumns="4"
|
||||
launcher:numHotseatIcons="4"
|
||||
launcher:dbFile="launcher_4_by_4.db"
|
||||
launcher:defaultLayoutId="@xml/default_workspace_4x4" >
|
||||
|
||||
<display-option
|
||||
@@ -102,6 +104,7 @@
|
||||
launcher:numFolderRows="4"
|
||||
launcher:numFolderColumns="4"
|
||||
launcher:numHotseatIcons="5"
|
||||
launcher:dbFile="launcher.db"
|
||||
launcher:defaultLayoutId="@xml/default_workspace_5x5" >
|
||||
|
||||
<display-option
|
||||
|
||||
@@ -52,7 +52,7 @@ LOCAL_JAVA_LIBRARIES := LauncherRoboTests
|
||||
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
||||
LOCAL_TEST_PACKAGE := Launcher3
|
||||
LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))../src
|
||||
LOCAL_INSTRUMENT_SOURCE_DIRS := packages/apps/Launcher3/src
|
||||
|
||||
LOCAL_ROBOTEST_TIMEOUT := 36000
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.android.launcher3.folder;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -61,15 +61,16 @@ public final class FolderNameProviderTest {
|
||||
ArrayList<WorkspaceItemInfo> list = new ArrayList<>();
|
||||
list.add(mItem1);
|
||||
list.add(mItem2);
|
||||
String[] suggestedNameOut = new String[FolderNameProvider.SUGGEST_MAX];
|
||||
new FolderNameProvider().getSuggestedFolderName(mContext, list, suggestedNameOut);
|
||||
assertTrue(suggestedNameOut[0].equals("Work"));
|
||||
FolderNameInfo[] nameInfos =
|
||||
new FolderNameInfo[FolderNameProvider.SUGGEST_MAX];
|
||||
new FolderNameProvider().getSuggestedFolderName(mContext, list, nameInfos);
|
||||
assertEquals("Work", nameInfos[0].getLabel());
|
||||
|
||||
suggestedNameOut[0] = "candidate1";
|
||||
suggestedNameOut[1] = "candidate2";
|
||||
suggestedNameOut[2] = "candidate3";
|
||||
new FolderNameProvider().getSuggestedFolderName(mContext, list, suggestedNameOut);
|
||||
assertTrue(suggestedNameOut[3].equals("Work"));
|
||||
nameInfos[0] = new FolderNameInfo("candidate1", 0.9);
|
||||
nameInfos[1] = new FolderNameInfo("candidate2", 0.8);
|
||||
nameInfos[2] = new FolderNameInfo("candidate3", 0.7);
|
||||
new FolderNameProvider().getSuggestedFolderName(mContext, list, nameInfos);
|
||||
assertEquals("Work", nameInfos[3].getLabel());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,9 @@ public class FileLogTest {
|
||||
@After
|
||||
public void tearDown() {
|
||||
// Clear existing logs
|
||||
new File(mTempDir, "log-0").delete();
|
||||
new File(mTempDir, "log-1").delete();
|
||||
for (int i = 0; i < FileLog.LOG_DAYS; i++) {
|
||||
new File(mTempDir, "log-" + i).delete();
|
||||
}
|
||||
mTempDir.delete();
|
||||
|
||||
mTestActive = false;
|
||||
@@ -89,8 +90,9 @@ public class FileLogTest {
|
||||
|
||||
Calendar threeDaysAgo = Calendar.getInstance();
|
||||
threeDaysAgo.add(Calendar.HOUR, -72);
|
||||
new File(mTempDir, "log-0").setLastModified(threeDaysAgo.getTimeInMillis());
|
||||
new File(mTempDir, "log-1").setLastModified(threeDaysAgo.getTimeInMillis());
|
||||
for (int i = 0; i < FileLog.LOG_DAYS; i++) {
|
||||
new File(mTempDir, "log-" + i).setLastModified(threeDaysAgo.getTimeInMillis());
|
||||
}
|
||||
|
||||
FileLog.print("Testing", "abracadabra", new Exception("cat! cat!"));
|
||||
writer = new StringWriter();
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.android.launcher3.logging.StatsLogUtils.LogStateProvider;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.logging.UserEventDispatcher.UserEventDelegate;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.SystemUiController;
|
||||
import com.android.launcher3.util.ViewCache;
|
||||
@@ -330,9 +331,7 @@ public abstract class BaseActivity extends Activity
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
TestLogging.recordEvent("start: shortcut: " + packageName);
|
||||
}
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: shortcut", packageName);
|
||||
getSystemService(LauncherApps.class).startShortcut(packageName, id, sourceBounds,
|
||||
startActivityOptions, user);
|
||||
} catch (SecurityException | IllegalStateException e) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ROTATION;
|
||||
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
@@ -37,9 +39,12 @@ import androidx.annotation.Nullable;
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.model.AppLaunchTracker;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.touch.ItemClickHandler;
|
||||
import com.android.launcher3.uioverrides.DisplayRotationListener;
|
||||
import com.android.launcher3.uioverrides.WallpaperColorInfo;
|
||||
import com.android.launcher3.util.DefaultDisplay;
|
||||
import com.android.launcher3.util.DefaultDisplay.DisplayInfoChangeListener;
|
||||
import com.android.launcher3.util.DefaultDisplay.Info;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
@@ -48,7 +53,7 @@ import com.android.launcher3.util.TraceHelper;
|
||||
* Extension of BaseActivity allowing support for drag-n-drop
|
||||
*/
|
||||
public abstract class BaseDraggingActivity extends BaseActivity
|
||||
implements WallpaperColorInfo.OnChangeListener {
|
||||
implements WallpaperColorInfo.OnChangeListener, DisplayInfoChangeListener {
|
||||
|
||||
private static final String TAG = "BaseDraggingActivity";
|
||||
|
||||
@@ -63,8 +68,6 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
|
||||
private int mThemeRes = R.style.AppTheme;
|
||||
|
||||
private DisplayRotationListener mRotationListener;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -72,7 +75,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
|
||||
mIsSafeModeEnabled = TraceHelper.whitelistIpcs("isSafeMode",
|
||||
() -> getPackageManager().isSafeMode());
|
||||
mRotationListener = new DisplayRotationListener(this, this::onDeviceRotationChanged);
|
||||
DefaultDisplay.INSTANCE.get(this).addChangeListener(this);
|
||||
|
||||
// Update theme
|
||||
WallpaperColorInfo.INSTANCE.get(this).addOnChangeListener(this);
|
||||
@@ -167,9 +170,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
startShortcutIntentSafely(intent, optsBundle, item, sourceContainer);
|
||||
} else if (user == null || user.equals(Process.myUserHandle())) {
|
||||
// Could be launching some bookkeeping activity
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
TestLogging.recordEvent("start: activity: " + intent);
|
||||
}
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: activity", intent);
|
||||
startActivity(intent, optsBundle);
|
||||
AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(),
|
||||
Process.myUserHandle(), sourceContainer);
|
||||
@@ -238,7 +239,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
WallpaperColorInfo.INSTANCE.get(this).removeOnChangeListener(this);
|
||||
mRotationListener.disable();
|
||||
DefaultDisplay.INSTANCE.get(this).removeChangeListener(this);
|
||||
}
|
||||
|
||||
public void runOnceOnStart(Runnable action) {
|
||||
@@ -251,15 +252,13 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
|
||||
protected void onDeviceProfileInitiated() {
|
||||
if (mDeviceProfile.isVerticalBarLayout()) {
|
||||
mRotationListener.enable();
|
||||
mDeviceProfile.updateIsSeascape(this);
|
||||
} else {
|
||||
mRotationListener.disable();
|
||||
}
|
||||
}
|
||||
|
||||
private void onDeviceRotationChanged() {
|
||||
if (mDeviceProfile.updateIsSeascape(this)) {
|
||||
@Override
|
||||
public void onDisplayInfoChanged(Info info, int flags) {
|
||||
if ((flags & CHANGE_ROTATION) != 0 && mDeviceProfile.updateIsSeascape(this)) {
|
||||
reapplyUi();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@ public class CellLayout extends ViewGroup implements Transposable {
|
||||
try {
|
||||
dispatchRestoreInstanceState(states);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
throw ex;
|
||||
}
|
||||
// Mismatched viewId / viewType preventing restore. Skip restore on production builds.
|
||||
|
||||
@@ -271,7 +271,7 @@ public class DeviceProfile {
|
||||
// In multi-window mode, we can have widthPx = availableWidthPx
|
||||
// and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles'
|
||||
// widthPx and heightPx values where it's needed.
|
||||
DeviceProfile profile = new DeviceProfile(context, inv, originalIdp, mwSize, mwSize,
|
||||
DeviceProfile profile = new DeviceProfile(context, inv, null, mwSize, mwSize,
|
||||
mwSize.x, mwSize.y, isLandscape, true);
|
||||
|
||||
// If there isn't enough vertical cell padding with the labels displayed, hide the labels.
|
||||
|
||||
@@ -96,7 +96,7 @@ public class FocusHelper {
|
||||
}
|
||||
|
||||
if (!(v.getParent() instanceof ShortcutAndWidgetContainer)) {
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
throw new IllegalStateException("Parent of the focused item is not supported.");
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -48,6 +48,8 @@ public class FolderInfo extends ItemInfo {
|
||||
|
||||
public static final int FLAG_MANUAL_FOLDER_NAME = 0x00000008;
|
||||
|
||||
public static final String EXTRA_FOLDER_SUGGESTIONS = "suggest";
|
||||
|
||||
public int options;
|
||||
|
||||
public Intent suggestedFolderNames;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
import static com.android.launcher3.util.ShortcutUtil.fetchAndUpdateShortcutIconAsync;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
@@ -44,7 +43,6 @@ import android.util.Pair;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.GraphicsUtils;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
@@ -61,7 +59,6 @@ import org.json.JSONStringer;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -491,13 +488,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
return Pair.create(si, null);
|
||||
} else if (shortcutInfo != null) {
|
||||
WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(shortcutInfo, mContext);
|
||||
if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
|
||||
fetchAndUpdateShortcutIconAsync(mContext, itemInfo, shortcutInfo, true);
|
||||
} else {
|
||||
LauncherIcons li = LauncherIcons.obtain(mContext);
|
||||
itemInfo.bitmap = li.createShortcutIcon(shortcutInfo);
|
||||
li.recycle();
|
||||
}
|
||||
LauncherAppState.getInstance(mContext).getIconCache().getShortcutIcon(
|
||||
itemInfo, shortcutInfo);
|
||||
return Pair.create(itemInfo, shortcutInfo);
|
||||
} else if (providerInfo != null) {
|
||||
LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo
|
||||
|
||||
@@ -119,6 +119,7 @@ public class InvariantDeviceProfile {
|
||||
*/
|
||||
public int numAllAppsColumns;
|
||||
|
||||
public String dbFile;
|
||||
public int defaultLayoutId;
|
||||
int demoModeLayoutId;
|
||||
|
||||
@@ -146,6 +147,7 @@ public class InvariantDeviceProfile {
|
||||
iconTextSize = p.iconTextSize;
|
||||
numHotseatIcons = p.numHotseatIcons;
|
||||
numAllAppsColumns = p.numAllAppsColumns;
|
||||
dbFile = p.dbFile;
|
||||
defaultLayoutId = p.defaultLayoutId;
|
||||
demoModeLayoutId = p.demoModeLayoutId;
|
||||
mExtraAttrs = p.mExtraAttrs;
|
||||
@@ -292,6 +294,7 @@ public class InvariantDeviceProfile {
|
||||
numRows = closestProfile.numRows;
|
||||
numColumns = closestProfile.numColumns;
|
||||
numHotseatIcons = closestProfile.numHotseatIcons;
|
||||
dbFile = closestProfile.dbFile;
|
||||
defaultLayoutId = closestProfile.defaultLayoutId;
|
||||
demoModeLayoutId = closestProfile.demoModeLayoutId;
|
||||
numFolderRows = closestProfile.numFolderRows;
|
||||
@@ -559,6 +562,7 @@ public class InvariantDeviceProfile {
|
||||
|
||||
private final int numHotseatIcons;
|
||||
|
||||
private final String dbFile;
|
||||
private final int defaultLayoutId;
|
||||
private final int demoModeLayoutId;
|
||||
|
||||
@@ -571,6 +575,7 @@ public class InvariantDeviceProfile {
|
||||
numRows = a.getInt(R.styleable.GridDisplayOption_numRows, 0);
|
||||
numColumns = a.getInt(R.styleable.GridDisplayOption_numColumns, 0);
|
||||
|
||||
dbFile = a.getString(R.styleable.GridDisplayOption_dbFile);
|
||||
defaultLayoutId = a.getResourceId(
|
||||
R.styleable.GridDisplayOption_defaultLayoutId, 0);
|
||||
demoModeLayoutId = a.getResourceId(
|
||||
|
||||
@@ -100,6 +100,7 @@ import com.android.launcher3.dot.DotInfo;
|
||||
import com.android.launcher3.dragndrop.DragController;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.dragndrop.DragView;
|
||||
import com.android.launcher3.folder.Folder;
|
||||
import com.android.launcher3.folder.FolderGridOrganizer;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
@@ -1155,7 +1156,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
/**
|
||||
* Finds all the views we need and configure them properly.
|
||||
*/
|
||||
private void setupViews() {
|
||||
protected void setupViews() {
|
||||
mDragLayer = findViewById(R.id.drag_layer);
|
||||
mFocusHandler = mDragLayer.getFocusIndicatorHelper();
|
||||
mWorkspace = mDragLayer.findViewById(R.id.workspace);
|
||||
@@ -1191,11 +1192,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
mDropTargetBar.setup(mDragController);
|
||||
|
||||
mAllAppsController.setupViews(mAppsView);
|
||||
|
||||
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
|
||||
// Overview is above all other launcher elements, including qsb, so move it to the top.
|
||||
mOverviewPanel.bringToFront();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1745,8 +1741,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
/**
|
||||
* Creates and adds new folder to CellLayout
|
||||
*/
|
||||
public FolderIcon addFolder(CellLayout layout, WorkspaceItemInfo info, int container,
|
||||
final int screenId, int cellX, int cellY) {
|
||||
public FolderIcon addFolder(CellLayout layout, int container, final int screenId, int cellX,
|
||||
int cellY) {
|
||||
final FolderInfo folderInfo = new FolderInfo();
|
||||
folderInfo.title = "";
|
||||
|
||||
@@ -1763,6 +1759,16 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
return newFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a workspace item is converted into a folder
|
||||
*/
|
||||
public void folderCreatedFromItem(Folder folder, WorkspaceItemInfo itemInfo){}
|
||||
|
||||
/**
|
||||
* Called when a folder is converted into a workspace item
|
||||
*/
|
||||
public void folderConvertedToItem(Folder folder, WorkspaceItemInfo itemInfo) {}
|
||||
|
||||
/**
|
||||
* Unbinds the view for the specified item, and removes the item and all its children.
|
||||
*
|
||||
@@ -1805,17 +1811,13 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
TestLogging.recordEvent("Key event: " + event);
|
||||
}
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Key event", event);
|
||||
return (event.getKeyCode() == KeyEvent.KEYCODE_HOME) || super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (Utilities.IS_RUNNING_IN_TEST_HARNESS && ev.getAction() != MotionEvent.ACTION_MOVE) {
|
||||
TestLogging.recordEvent("Touch event: " + ev);
|
||||
}
|
||||
TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@@ -2164,7 +2166,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
Object tag = v.getTag();
|
||||
String desc = "Collision while binding workspace item: " + item
|
||||
+ ". Collides with " + tag;
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
throw (new RuntimeException(desc));
|
||||
} else {
|
||||
Log.d(TAG, desc);
|
||||
|
||||
@@ -91,7 +91,7 @@ public class LauncherAppState {
|
||||
Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
|
||||
Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
|
||||
Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
mModelChangeReceiver.register(mContext, ACTION_FORCE_ROLOAD);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,12 @@ import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Parcel;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.launcher3.icons.ComponentWithLabel;
|
||||
import com.android.launcher3.icons.ComponentWithLabelAndIcon;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
|
||||
/**
|
||||
* This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords
|
||||
@@ -19,7 +21,7 @@ import com.android.launcher3.icons.ComponentWithLabel;
|
||||
* as opposed to a widget instance, and so should not be confused with {@link LauncherAppWidgetInfo}
|
||||
*/
|
||||
public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo
|
||||
implements ComponentWithLabel {
|
||||
implements ComponentWithLabelAndIcon {
|
||||
|
||||
public static final String CLS_CUSTOM_WIDGET_PREFIX = "#custom-widget-";
|
||||
|
||||
@@ -111,4 +113,9 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo
|
||||
public final UserHandle getUser() {
|
||||
return getProfile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getFullResIcon(IconCache cache) {
|
||||
return cache.getFullResIcon(provider.getPackageName(), icon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,13 @@ public class LauncherFiles {
|
||||
private static final String XML = ".xml";
|
||||
|
||||
public static final String LAUNCHER_DB = "launcher.db";
|
||||
public static final String LAUNCHER_4_BY_4_DB = "launcher_4_by_4.db";
|
||||
public static final String LAUNCHER_3_BY_3_DB = "launcher_3_by_3.db";
|
||||
public static final String LAUNCHER_2_BY_2_DB = "launcher_2_by_2.db";
|
||||
public static final String BACKUP_DB = "backup.db";
|
||||
public static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs";
|
||||
public static final String MANAGED_USER_PREFERENCES_KEY = "com.android.launcher3.managedusers.prefs";
|
||||
public static final String MANAGED_USER_PREFERENCES_KEY =
|
||||
"com.android.launcher3.managedusers.prefs";
|
||||
// This preference file is not backed up to cloud.
|
||||
public static final String DEVICE_PREFERENCES_KEY = "com.android.launcher3.device.prefs";
|
||||
|
||||
@@ -25,6 +30,10 @@ public class LauncherFiles {
|
||||
|
||||
public static final List<String> ALL_FILES = Collections.unmodifiableList(Arrays.asList(
|
||||
LAUNCHER_DB,
|
||||
LAUNCHER_4_BY_4_DB,
|
||||
LAUNCHER_3_BY_3_DB,
|
||||
LAUNCHER_2_BY_2_DB,
|
||||
BACKUP_DB,
|
||||
SHARED_PREFERENCES_KEY + XML,
|
||||
WIDGET_PREVIEWS_DB,
|
||||
MANAGED_USER_PREFERENCES_KEY + XML,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
|
||||
import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
|
||||
import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
|
||||
@@ -37,7 +37,6 @@ import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
import com.android.launcher3.model.AddWorkspaceItemsTask;
|
||||
import com.android.launcher3.model.AllAppsList;
|
||||
@@ -56,7 +55,6 @@ import com.android.launcher3.pm.InstallSessionTracker;
|
||||
import com.android.launcher3.pm.PackageInstallInfo;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.IntSparseArrayMap;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
@@ -68,7 +66,6 @@ import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
@@ -97,10 +94,6 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||
private boolean mModelLoaded;
|
||||
public boolean isModelLoaded() {
|
||||
synchronized (mLock) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
|
||||
"isModelLoaded: " + mModelLoaded + ", " + mLoaderTask);
|
||||
}
|
||||
return mModelLoaded && mLoaderTask == null;
|
||||
}
|
||||
}
|
||||
@@ -132,16 +125,6 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||
mBgAllAppsList = new AllAppsList(iconCache, appFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns AppInfo with corresponding package name.
|
||||
* TODO: move to enqueueModelTask
|
||||
*/
|
||||
public Optional<AppInfo> getAppInfoByPackageName(String pkg) {
|
||||
return mBgAllAppsList.data.stream()
|
||||
.filter(info -> info.componentName.getPackageName().equals(pkg))
|
||||
.findAny();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the provided items to the workspace.
|
||||
*/
|
||||
@@ -255,7 +238,7 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||
enqueueModelUpdateTask(new UserLockStateChangedTask(user));
|
||||
}
|
||||
}
|
||||
} else if (IS_DOGFOOD_BUILD && ACTION_FORCE_ROLOAD.equals(action)) {
|
||||
} else if (IS_STUDIO_BUILD && ACTION_FORCE_ROLOAD.equals(action)) {
|
||||
for (Callbacks cb : getCallbacks()) {
|
||||
if (cb instanceof Launcher) {
|
||||
((Launcher) cb).recreate();
|
||||
@@ -373,9 +356,6 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||
public boolean stopLoader() {
|
||||
synchronized (mLock) {
|
||||
LoaderTask oldTask = mLoaderTask;
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "LauncherModel.stopLoader");
|
||||
}
|
||||
mLoaderTask = null;
|
||||
if (oldTask != null) {
|
||||
oldTask.stopLocked();
|
||||
@@ -389,10 +369,6 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||
synchronized (mLock) {
|
||||
stopLoader();
|
||||
mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, mBgDataModel, results);
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
|
||||
"LauncherModel.startLoaderForResults " + mLoaderTask);
|
||||
}
|
||||
|
||||
// Always post the loader task, instead of running directly (even on same thread) so
|
||||
// that we exit any nested synchronized blocks
|
||||
@@ -494,10 +470,6 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||
public void close() {
|
||||
synchronized (mLock) {
|
||||
// If we are still the last one to be scheduled, remove ourselves.
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
|
||||
"LauncherModel.close " + mLoaderTask + ", " + mTask);
|
||||
}
|
||||
if (mLoaderTask == mTask) {
|
||||
mLoaderTask = null;
|
||||
}
|
||||
@@ -573,9 +545,7 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||
public void updateAndBindWorkspaceItem(WorkspaceItemInfo si, ShortcutInfo info) {
|
||||
updateAndBindWorkspaceItem(() -> {
|
||||
si.updateFromDeepShortcutInfo(info, mApp.getContext());
|
||||
LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
|
||||
si.bitmap = li.createShortcutIcon(info);
|
||||
li.recycle();
|
||||
mApp.getIconCache().getShortcutIcon(si, info);
|
||||
return si;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO;
|
||||
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
|
||||
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
@@ -118,7 +119,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
Log.d(TAG, "Launcher process started");
|
||||
}
|
||||
|
||||
@@ -157,6 +158,17 @@ public class LauncherProvider extends ContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized boolean updateCurrentOpenHelper() {
|
||||
final InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(getContext());
|
||||
if (TextUtils.equals(idp.dbFile, mOpenHelper.getDatabaseName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mOpenHelper.close();
|
||||
mOpenHelper = new DatabaseHelper(getContext());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection,
|
||||
String[] selectionArgs, String sortOrder) {
|
||||
@@ -210,7 +222,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
addModifiedTime(initialValues);
|
||||
final int rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
|
||||
if (rowId < 0) return null;
|
||||
mOpenHelper.onAddOrDeleteOp(db);
|
||||
onAddOrDeleteOp(db);
|
||||
|
||||
uri = ContentUris.withAppendedId(uri, rowId);
|
||||
reloadLauncherIfExternal();
|
||||
@@ -268,7 +280,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
mOpenHelper.onAddOrDeleteOp(db);
|
||||
onAddOrDeleteOp(db);
|
||||
t.commit();
|
||||
}
|
||||
|
||||
@@ -294,7 +306,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
results[i].count != null && results[i].count > 0;
|
||||
}
|
||||
if (isAddOrDelete) {
|
||||
mOpenHelper.onAddOrDeleteOp(t.getDb());
|
||||
onAddOrDeleteOp(t.getDb());
|
||||
}
|
||||
|
||||
t.commit();
|
||||
@@ -316,7 +328,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
}
|
||||
int count = db.delete(args.table, args.where, args.args);
|
||||
if (count > 0) {
|
||||
mOpenHelper.onAddOrDeleteOp(db);
|
||||
onAddOrDeleteOp(db);
|
||||
reloadLauncherIfExternal();
|
||||
}
|
||||
return count;
|
||||
@@ -360,12 +372,14 @@ public class LauncherProvider extends ContentProvider {
|
||||
}
|
||||
case LauncherSettings.Settings.METHOD_NEW_ITEM_ID: {
|
||||
Bundle result = new Bundle();
|
||||
result.putInt(LauncherSettings.Settings.EXTRA_VALUE, mOpenHelper.generateNewItemId());
|
||||
result.putInt(LauncherSettings.Settings.EXTRA_VALUE,
|
||||
mOpenHelper.generateNewItemId());
|
||||
return result;
|
||||
}
|
||||
case LauncherSettings.Settings.METHOD_NEW_SCREEN_ID: {
|
||||
Bundle result = new Bundle();
|
||||
result.putInt(LauncherSettings.Settings.EXTRA_VALUE, mOpenHelper.generateNewScreenId());
|
||||
result.putInt(LauncherSettings.Settings.EXTRA_VALUE,
|
||||
mOpenHelper.generateNewScreenId());
|
||||
return result;
|
||||
}
|
||||
case LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB: {
|
||||
@@ -387,8 +401,12 @@ public class LauncherProvider extends ContentProvider {
|
||||
return result;
|
||||
}
|
||||
case LauncherSettings.Settings.METHOD_REFRESH_BACKUP_TABLE: {
|
||||
mOpenHelper.mBackupTableExists =
|
||||
tableExists(mOpenHelper.getReadableDatabase(), Favorites.BACKUP_TABLE_NAME);
|
||||
// TODO(pinyaoting): Update the behavior here.
|
||||
if (!MULTI_DB_GRID_MIRATION_ALGO.get()) {
|
||||
mOpenHelper.mBackupTableExists =
|
||||
tableExists(mOpenHelper.getReadableDatabase(),
|
||||
Favorites.BACKUP_TABLE_NAME);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
case LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE: {
|
||||
@@ -399,10 +417,26 @@ public class LauncherProvider extends ContentProvider {
|
||||
TOKEN_RESTORE_BACKUP_TABLE, RESTORE_BACKUP_TABLE_DELAY);
|
||||
return null;
|
||||
}
|
||||
case LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER: {
|
||||
if (MULTI_DB_GRID_MIRATION_ALGO.get()) {
|
||||
Bundle result = new Bundle();
|
||||
result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
|
||||
updateCurrentOpenHelper());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void onAddOrDeleteOp(SQLiteDatabase db) {
|
||||
if (MULTI_DB_GRID_MIRATION_ALGO.get()) {
|
||||
// TODO(pingyaoting): Implement the behavior here.
|
||||
} else {
|
||||
mOpenHelper.onAddOrDeleteOp(db);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes any empty folder from the DB.
|
||||
* @return Ids of deleted folders.
|
||||
@@ -551,14 +585,16 @@ public class LauncherProvider extends ContentProvider {
|
||||
/**
|
||||
* The class is subclassed in tests to create an in-memory db.
|
||||
*/
|
||||
public static class DatabaseHelper extends NoLocaleSQLiteHelper implements LayoutParserCallback {
|
||||
public static class DatabaseHelper extends NoLocaleSQLiteHelper implements
|
||||
LayoutParserCallback {
|
||||
private final Context mContext;
|
||||
private int mMaxItemId = -1;
|
||||
private int mMaxScreenId = -1;
|
||||
private boolean mBackupTableExists;
|
||||
|
||||
DatabaseHelper(Context context) {
|
||||
this(context, LauncherFiles.LAUNCHER_DB);
|
||||
this(context, MULTI_DB_GRID_MIRATION_ALGO.get() ? InvariantDeviceProfile.INSTANCE.get(
|
||||
context).dbFile : LauncherFiles.LAUNCHER_DB);
|
||||
// Table creation sometimes fails silently, which leads to a crash loop.
|
||||
// This way, we will try to create a table every time after crash, so the device
|
||||
// would eventually be able to recover.
|
||||
@@ -567,7 +603,10 @@ public class LauncherProvider extends ContentProvider {
|
||||
// This operation is a no-op if the table already exists.
|
||||
addFavoritesTable(getWritableDatabase(), true);
|
||||
}
|
||||
mBackupTableExists = tableExists(getReadableDatabase(), Favorites.BACKUP_TABLE_NAME);
|
||||
if (!MULTI_DB_GRID_MIRATION_ALGO.get()) {
|
||||
mBackupTableExists = tableExists(getReadableDatabase(),
|
||||
Favorites.BACKUP_TABLE_NAME);
|
||||
}
|
||||
|
||||
initIds();
|
||||
}
|
||||
@@ -575,8 +614,8 @@ public class LauncherProvider extends ContentProvider {
|
||||
/**
|
||||
* Constructor used in tests and for restore.
|
||||
*/
|
||||
public DatabaseHelper(Context context, String tableName) {
|
||||
super(context, tableName, SCHEMA_VERSION);
|
||||
public DatabaseHelper(Context context, String dbName) {
|
||||
super(context, dbName, SCHEMA_VERSION);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@@ -606,7 +645,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
protected void onAddOrDeleteOp(SQLiteDatabase db) {
|
||||
if (mBackupTableExists) {
|
||||
if (!MULTI_DB_GRID_MIRATION_ALGO.get() && mBackupTableExists) {
|
||||
dropTable(db, Favorites.BACKUP_TABLE_NAME);
|
||||
mBackupTableExists = false;
|
||||
}
|
||||
|
||||
@@ -302,6 +302,8 @@ public class LauncherSettings {
|
||||
|
||||
public static final String METHOD_RESTORE_BACKUP_TABLE = "restore_backup_table";
|
||||
|
||||
public static final String METHOD_UPDATE_CURRENT_OPEN_HELPER = "update_current_open_helper";
|
||||
|
||||
public static final String EXTRA_VALUE = "value";
|
||||
|
||||
public static Bundle call(ContentResolver cr, String method) {
|
||||
|
||||
@@ -41,8 +41,10 @@ import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
|
||||
import static com.android.launcher3.testing.TestProtocol.QUICK_SWITCH_STATE_ORDINAL;
|
||||
import static com.android.launcher3.testing.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.allapps.AllAppsContainerView;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.states.HintState;
|
||||
import com.android.launcher3.states.SpringLoadedState;
|
||||
@@ -337,8 +339,13 @@ public abstract class LauncherState {
|
||||
hotseat.setScaleX(0.92f);
|
||||
hotseat.setScaleY(0.92f);
|
||||
if (ENABLE_OVERVIEW_ACTIONS.get()) {
|
||||
launcher.getAppsView().setScaleX(0.92f);
|
||||
launcher.getAppsView().setScaleY(0.92f);
|
||||
AllAppsContainerView qsbContainer = launcher.getAppsView();
|
||||
View qsb = qsbContainer.getSearchView();
|
||||
boolean qsbVisible = qsb.getVisibility() == VISIBLE && qsb.getAlpha() > 0;
|
||||
if (!qsbVisible) {
|
||||
qsbContainer.setScaleX(0.92f);
|
||||
qsbContainer.setScaleY(0.92f);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this == NORMAL && fromState == OVERVIEW_PEEK) {
|
||||
|
||||
@@ -1502,7 +1502,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
duration *= Settings.Global.getFloat(getContext().getContentResolver(),
|
||||
Settings.Global.WINDOW_ANIMATION_SCALE, 1);
|
||||
}
|
||||
|
||||
@@ -584,9 +584,8 @@ public final class Utilities {
|
||||
return new FixedSizeEmptyDrawable(iconSize);
|
||||
}
|
||||
ShortcutInfo si = (ShortcutInfo) obj;
|
||||
LauncherIcons li = LauncherIcons.obtain(appState.getContext());
|
||||
Bitmap badge = li.getShortcutInfoBadge(si, appState.getIconCache()).bitmap.icon;
|
||||
li.recycle();
|
||||
Bitmap badge = LauncherAppState.getInstance(appState.getContext())
|
||||
.getIconCache().getShortcutInfoBadge(si).icon;
|
||||
float badgeSize = LauncherIcons.getBadgeSizeForIconSize(iconSize);
|
||||
float insetFraction = (iconSize - badgeSize) / iconSize;
|
||||
return new InsetDrawable(new FastBitmapDrawable(badge),
|
||||
|
||||
@@ -1702,8 +1702,8 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);
|
||||
target.removeView(v);
|
||||
|
||||
FolderIcon fi = mLauncher.addFolder(target, sourceInfo, container, screenId,
|
||||
targetCell[0], targetCell[1]);
|
||||
FolderIcon fi = mLauncher.addFolder(target, container, screenId, targetCell[0],
|
||||
targetCell[1]);
|
||||
destInfo.cellX = -1;
|
||||
destInfo.cellY = -1;
|
||||
sourceInfo.cellX = -1;
|
||||
@@ -1722,6 +1722,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
fi.addItem(destInfo);
|
||||
fi.addItem(sourceInfo);
|
||||
}
|
||||
mLauncher.folderCreatedFromItem(fi.getFolder(), destInfo);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1857,7 +1858,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
CellLayout parentCell = getParentCellLayoutForView(cell);
|
||||
if (parentCell != null) {
|
||||
parentCell.removeView(cell);
|
||||
} else if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
} else if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
throw new NullPointerException("mDragInfo.cell has null parent");
|
||||
}
|
||||
addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1],
|
||||
@@ -2152,7 +2153,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
ItemInfo item = d.dragInfo;
|
||||
if (item == null) {
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
throw new NullPointerException("DragObject has null info");
|
||||
}
|
||||
return;
|
||||
@@ -2774,7 +2775,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
mDragInfo.container, mDragInfo.screenId);
|
||||
if (cellLayout != null) {
|
||||
cellLayout.onDropChild(mDragInfo.cell);
|
||||
} else if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
} else if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
throw new RuntimeException("Invalid state: cellLayout == null in "
|
||||
+ "Workspace#onDropCompleted. Please file a bug. ");
|
||||
}
|
||||
@@ -2793,7 +2794,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
CellLayout parentCell = getParentCellLayoutForView(v);
|
||||
if (parentCell != null) {
|
||||
parentCell.removeView(v);
|
||||
} else if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
} else if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
// When an app is uninstalled using the drop target, we wait until resume to remove
|
||||
// the icon. We also remove all the corresponding items from the workspace at
|
||||
// {@link Launcher#bindComponentsRemoved}. That call can come before or after
|
||||
|
||||
@@ -153,6 +153,11 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
return mMultiValueAlpha.getProperty(index);
|
||||
}
|
||||
|
||||
public WorkFooterContainer getWorkFooterContainer() {
|
||||
return mWorkFooterContainer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void setDampedScrollShift(float shift) {
|
||||
// Bound the shift amount to avoid content from drawing on top (Y-val) of the QSB.
|
||||
|
||||
@@ -11,7 +11,7 @@ import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRE
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
|
||||
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
|
||||
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
|
||||
import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -185,7 +185,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
|
||||
}
|
||||
|
||||
public Animator createSpringAnimation(float... progressValues) {
|
||||
if (QUICKSTEP_SPRINGS.get()) {
|
||||
if (UNSTABLE_SPRINGS.get()) {
|
||||
return new SpringObjectAnimator<>(this, ALL_APPS_PROGRESS, 1f / mShiftRange,
|
||||
SPRING_DAMPING_RATIO, SPRING_STIFFNESS, progressValues);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.android.launcher3.BuildConfig;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.uioverrides.DeviceFlag;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -42,7 +43,10 @@ public final class FeatureFlags {
|
||||
return Utilities.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context);
|
||||
}
|
||||
|
||||
public static final boolean IS_DOGFOOD_BUILD = BuildConfig.DEBUG;
|
||||
/**
|
||||
* True when the build has come from Android Studio and is being used for local debugging.
|
||||
*/
|
||||
public static final boolean IS_STUDIO_BUILD = BuildConfig.DEBUG;
|
||||
|
||||
/**
|
||||
* Enable moving the QSB on the 0th screen of the workspace. This is not a configuration feature
|
||||
@@ -90,13 +94,13 @@ public final class FeatureFlags {
|
||||
"FAKE_LANDSCAPE_UI", false, "Rotate launcher UI instead of using transposed layout");
|
||||
|
||||
public static final BooleanFlag FOLDER_NAME_SUGGEST = getDebugFlag(
|
||||
"FOLDER_NAME_SUGGEST", false, "Suggests folder names instead of blank text.");
|
||||
"FOLDER_NAME_SUGGEST", true, "Suggests folder names instead of blank text.");
|
||||
|
||||
public static final BooleanFlag APP_SEARCH_IMPROVEMENTS = new DeviceFlag(
|
||||
"APP_SEARCH_IMPROVEMENTS", false,
|
||||
"Adds localized title and keyword search and ranking");
|
||||
|
||||
public static final BooleanFlag ENABLE_PREDICTION_DISMISS = getDebugFlag(
|
||||
public static final BooleanFlag ENABLE_PREDICTION_DISMISS = new DeviceFlag(
|
||||
"ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
|
||||
|
||||
public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag(
|
||||
@@ -106,12 +110,15 @@ public final class FeatureFlags {
|
||||
"ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
|
||||
"Allow Launcher to handle nav bar gestures while Assistant is running over it");
|
||||
|
||||
public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = getDebugFlag(
|
||||
public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = new DeviceFlag(
|
||||
"ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps");
|
||||
|
||||
public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag(
|
||||
"ENABLE_DEEP_SHORTCUT_ICON_CACHE", true, "R/W deep shortcut in IconCache");
|
||||
|
||||
public static final BooleanFlag MULTI_DB_GRID_MIRATION_ALGO = getDebugFlag(
|
||||
"MULTI_DB_GRID_MIRATION_ALGO", false, "Use the multi-db grid migration algorithm");
|
||||
|
||||
public static final BooleanFlag ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER = getDebugFlag(
|
||||
"ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", false,
|
||||
"Show launcher preview in grid picker");
|
||||
@@ -142,6 +149,15 @@ public final class FeatureFlags {
|
||||
}
|
||||
}
|
||||
|
||||
public static void dump(PrintWriter pw) {
|
||||
pw.println("FeatureFlags:");
|
||||
synchronized (sDebugFlags) {
|
||||
for (DebugFlag flag : sDebugFlags) {
|
||||
pw.println(" " + flag.key + "=" + flag.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class BooleanFlag {
|
||||
|
||||
public final String key;
|
||||
|
||||
@@ -160,8 +160,8 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
|
||||
mOptions = options;
|
||||
if (mOptions.systemDndStartPoint != null) {
|
||||
mMotionDownX = mOptions.systemDndStartPoint.x;
|
||||
mMotionDownY = mOptions.systemDndStartPoint.y;
|
||||
mLastTouch[0] = mMotionDownX = mOptions.systemDndStartPoint.x;
|
||||
mLastTouch[1] = mMotionDownY = mOptions.systemDndStartPoint.y;
|
||||
}
|
||||
|
||||
final int registrationX = mMotionDownX - dragLayerX;
|
||||
|
||||
@@ -16,9 +16,23 @@
|
||||
|
||||
package com.android.launcher3.folder;
|
||||
|
||||
import static android.text.TextUtils.isEmpty;
|
||||
|
||||
import static androidx.core.util.Preconditions.checkNotNull;
|
||||
|
||||
import static com.android.launcher3.FolderInfo.FLAG_MANUAL_FOLDER_NAME;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
|
||||
import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_CUSTOM;
|
||||
import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_EMPTY;
|
||||
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 java.util.Arrays.asList;
|
||||
import static java.util.Arrays.stream;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -75,20 +89,24 @@ import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.dragndrop.DragOptions;
|
||||
import com.android.launcher3.logging.LoggerUtils;
|
||||
import com.android.launcher3.pageindicators.PageIndicatorDots;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import com.android.launcher3.userevent.LauncherLogProto.Action;
|
||||
import com.android.launcher3.userevent.LauncherLogProto.ContainerType;
|
||||
import com.android.launcher3.userevent.LauncherLogProto.ItemType;
|
||||
import com.android.launcher3.userevent.LauncherLogProto.LauncherEvent;
|
||||
import com.android.launcher3.userevent.LauncherLogProto.Target;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.views.ClipPathView;
|
||||
import com.android.launcher3.widget.PendingAddShortcutInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Represents a set of icons chosen by the user or generated by the system.
|
||||
@@ -186,6 +204,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
@Thunk int mScrollHintDir = SCROLL_NONE;
|
||||
@Thunk int mCurrentScrollDir = SCROLL_NONE;
|
||||
|
||||
private String mPreviousLabel;
|
||||
private boolean mIsPreviousLabelSuggested;
|
||||
|
||||
/**
|
||||
* Used to inflate the Workspace from XML.
|
||||
*
|
||||
@@ -300,13 +321,13 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
public void startEditingFolderName() {
|
||||
post(() -> {
|
||||
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
|
||||
if (TextUtils.isEmpty(mFolderName.getText())) {
|
||||
String[] suggestedNames =
|
||||
mInfo.suggestedFolderNames.getStringArrayExtra("suggest");
|
||||
mFolderName.setText(suggestedNames[0]);
|
||||
mFolderName.displayCompletions(Arrays.asList(suggestedNames).subList(1,
|
||||
suggestedNames.length));
|
||||
mFolderName.setEnteredCompose(false);
|
||||
if (isEmpty(mFolderName.getText())) {
|
||||
FolderNameInfo[] nameInfos =
|
||||
(FolderNameInfo[]) mInfo.suggestedFolderNames.getParcelableArrayExtra(
|
||||
FolderInfo.EXTRA_FOLDER_SUGGESTIONS);
|
||||
if (nameInfos != null) {
|
||||
showLabelSuggestion(nameInfos, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
mFolderName.setHint("");
|
||||
@@ -324,23 +345,16 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
|
||||
mInfo.title = newTitle;
|
||||
mInfo.setOption(FolderInfo.FLAG_MANUAL_FOLDER_NAME, mFolderName.isEnteredCompose(),
|
||||
mInfo.setOption(FLAG_MANUAL_FOLDER_NAME, mFolderName.isEnteredCompose(),
|
||||
mLauncher.getModelWriter());
|
||||
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("");
|
||||
if (TextUtils.isEmpty(mInfo.title)) {
|
||||
mFolderName.setHint(R.string.folder_hint_text);
|
||||
mFolderName.setText("");
|
||||
} else {
|
||||
if (TextUtils.isEmpty(mInfo.title)) {
|
||||
mFolderName.setHint(R.string.folder_hint_text);
|
||||
mFolderName.setText("");
|
||||
} else {
|
||||
mFolderName.setHint(null);
|
||||
}
|
||||
mFolderName.setHint(null);
|
||||
}
|
||||
|
||||
sendCustomAccessibilityEvent(
|
||||
@@ -423,8 +437,10 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
mItemsInvalidated = true;
|
||||
mInfo.addListener(this);
|
||||
|
||||
if (!TextUtils.isEmpty(mInfo.title)) {
|
||||
if (!isEmpty(mInfo.title)) {
|
||||
mFolderName.setText(mInfo.title);
|
||||
mPreviousLabel = mInfo.title.toString();
|
||||
mIsPreviousLabelSuggested = !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME);
|
||||
mFolderName.setHint(null);
|
||||
} else {
|
||||
mFolderName.setText("");
|
||||
@@ -443,26 +459,53 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
|
||||
/**
|
||||
* Show suggested folder title.
|
||||
* Show suggested folder title in FolderEditText, push InputMethodManager suggestions and save
|
||||
* the suggestedFolderNames.
|
||||
*/
|
||||
public void showSuggestedTitle(String[] suggestName) {
|
||||
public void showSuggestedTitle(FolderNameInfo[] nameInfos) {
|
||||
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
|
||||
mInfo.suggestedFolderNames = new Intent().putExtra("suggest", suggestName);
|
||||
if (TextUtils.isEmpty(mFolderName.getText().toString())
|
||||
&& !mInfo.hasOption(FolderInfo.FLAG_MANUAL_FOLDER_NAME)) {
|
||||
if (suggestName.length > 0 && !TextUtils.isEmpty(suggestName[0])) {
|
||||
mFolderName.setHint("");
|
||||
mFolderName.setText(suggestName[0]);
|
||||
mInfo.title = suggestName[0];
|
||||
animateOpen(mInfo.contents, 0, true);
|
||||
mFolderName.showKeyboard();
|
||||
mFolderName.displayCompletions(
|
||||
Arrays.asList(suggestName).subList(1, suggestName.length));
|
||||
}
|
||||
mInfo.suggestedFolderNames = new Intent().putExtra(FolderInfo.EXTRA_FOLDER_SUGGESTIONS,
|
||||
nameInfos);
|
||||
if (isEmpty(mFolderName.getText().toString())
|
||||
&& !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME)) {
|
||||
showLabelSuggestion(nameInfos, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show suggested folder title in FolderEditText if the first suggestion is non-empty, push
|
||||
* InputMethodManager suggestions.
|
||||
*/
|
||||
private void showLabelSuggestion(FolderNameInfo[] nameInfos, boolean animate) {
|
||||
if (nameInfos == null) {
|
||||
return;
|
||||
}
|
||||
// Open the Folder and Keyboard when the first or second suggestion is valid non-empty
|
||||
// string.
|
||||
boolean shouldOpen = nameInfos.length > 0 && nameInfos[0] != null && !isEmpty(
|
||||
nameInfos[0].getLabel())
|
||||
|| nameInfos.length > 1 && nameInfos[1] != null && !isEmpty(
|
||||
nameInfos[1].getLabel());
|
||||
CharSequence firstLabel = nameInfos[0].getLabel();
|
||||
|
||||
if (shouldOpen) {
|
||||
if (!isEmpty(firstLabel)) {
|
||||
mFolderName.setHint("");
|
||||
mFolderName.setText(firstLabel);
|
||||
}
|
||||
if (animate) {
|
||||
animateOpen(mInfo.contents, 0, true);
|
||||
}
|
||||
mFolderName.showKeyboard();
|
||||
mFolderName.displayCompletions(
|
||||
asList(nameInfos).subList(1, nameInfos.length).stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(s -> s.getLabel().toString())
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new UserFolder, inflated from R.layout.user_folder.
|
||||
*
|
||||
@@ -580,7 +623,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
dragLayer.addView(this);
|
||||
mDragController.addDropTarget(this);
|
||||
} else {
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
Log.e(TAG, "Opening folder (" + this + ") which already has a parent:"
|
||||
+ getParent());
|
||||
}
|
||||
@@ -608,9 +651,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
if (!skipUserEventLog) {
|
||||
mLauncher.getUserEventDispatcher().logActionOnItem(
|
||||
Touch.TAP,
|
||||
Direction.NONE,
|
||||
ItemType.FOLDER_ICON, mInfo.cellX, mInfo.cellY);
|
||||
LauncherLogProto.Action.Touch.TAP,
|
||||
LauncherLogProto.Action.Direction.NONE,
|
||||
LauncherLogProto.ItemType.FOLDER_ICON, mInfo.cellX, mInfo.cellY);
|
||||
}
|
||||
|
||||
|
||||
@@ -1109,13 +1152,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
int itemCount = getItemCount();
|
||||
if (itemCount <= 1) {
|
||||
View newIcon = null;
|
||||
WorkspaceItemInfo finalItem = null;
|
||||
|
||||
if (itemCount == 1) {
|
||||
// Move the item from the folder to the workspace, in the position of the
|
||||
// folder
|
||||
CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container,
|
||||
mInfo.screenId);
|
||||
WorkspaceItemInfo finalItem = mInfo.contents.remove(0);
|
||||
finalItem = mInfo.contents.remove(0);
|
||||
newIcon = mLauncher.createShortcut(cellLayout, finalItem);
|
||||
mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem,
|
||||
mInfo.container, mInfo.screenId, mInfo.cellX, mInfo.cellY);
|
||||
@@ -1136,6 +1180,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
// Focus the newly created child
|
||||
newIcon.requestFocus();
|
||||
}
|
||||
if (finalItem != null) {
|
||||
mLauncher.folderConvertedToItem(mFolderIcon.getFolder(), finalItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1388,6 +1435,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
if (hasFocus) {
|
||||
startEditingFolderName();
|
||||
} else {
|
||||
logEditFolderLabel();
|
||||
mFolderName.dispatchBackKey();
|
||||
}
|
||||
}
|
||||
@@ -1401,11 +1449,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
|
||||
public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
|
||||
LauncherLogProto.Target targetParent) {
|
||||
target.gridX = info.cellX;
|
||||
target.gridY = info.cellY;
|
||||
target.pageIndex = mContent.getCurrentPage();
|
||||
targetParent.containerType = ContainerType.FOLDER;
|
||||
targetParent.containerType = LauncherLogProto.ContainerType.FOLDER;
|
||||
}
|
||||
|
||||
private class OnScrollHintListener implements OnAlarmListener {
|
||||
@@ -1503,7 +1552,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
|
||||
@Override
|
||||
public int getLogContainerType() {
|
||||
return ContainerType.FOLDER;
|
||||
return LauncherLogProto.ContainerType.FOLDER;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1538,7 +1587,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
}
|
||||
} else {
|
||||
mLauncher.getUserEventDispatcher().logActionTapOutside(
|
||||
LoggerUtils.newContainerTarget(ContainerType.FOLDER));
|
||||
LoggerUtils.newContainerTarget(LauncherLogProto.ContainerType.FOLDER));
|
||||
close(true);
|
||||
return true;
|
||||
}
|
||||
@@ -1568,4 +1617,113 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
super.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
private void logEditFolderLabel() {
|
||||
LauncherEvent launcherEvent = LauncherEvent.newBuilder()
|
||||
.setAction(Action.newBuilder().setType(Action.Type.SOFT_KEYBOARD))
|
||||
.addSrcTarget(newEditTextTargetBuilder()
|
||||
.setFromFolderLabelState(getFromFolderLabelState())
|
||||
.setToFolderLabelState(getToFolderLabelState()))
|
||||
.addSrcTarget(newFolderTargetBuilder())
|
||||
.addSrcTarget(newParentContainerTarget())
|
||||
.build();
|
||||
mLauncher.getUserEventDispatcher().logLauncherEvent(launcherEvent);
|
||||
mPreviousLabel = mFolderName.getText().toString();
|
||||
mIsPreviousLabelSuggested = !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME);
|
||||
}
|
||||
|
||||
private Target.FromFolderLabelState getFromFolderLabelState() {
|
||||
return mPreviousLabel == null
|
||||
? FROM_FOLDER_LABEL_STATE_UNSPECIFIED
|
||||
: mPreviousLabel.isEmpty()
|
||||
? FROM_EMPTY
|
||||
: mIsPreviousLabelSuggested
|
||||
? FROM_SUGGESTED
|
||||
: FROM_CUSTOM;
|
||||
}
|
||||
|
||||
private Target.ToFolderLabelState getToFolderLabelState() {
|
||||
String newLabel =
|
||||
checkNotNull(mFolderName.getText().toString(),
|
||||
"Expected valid folder label, but found null");
|
||||
|
||||
Optional<String[]> suggestedLabels = Optional.ofNullable(
|
||||
(FolderNameInfo[]) mInfo.suggestedFolderNames
|
||||
.getParcelableArrayExtra(FolderInfo.EXTRA_FOLDER_SUGGESTIONS))
|
||||
.map(folderNameInfoArray ->
|
||||
stream(folderNameInfoArray)
|
||||
.filter(Objects::nonNull)
|
||||
.map(FolderNameInfo::getLabel)
|
||||
.map(CharSequence::toString)
|
||||
.toArray(String[]::new));
|
||||
|
||||
|
||||
int accepted_suggestion_index = suggestedLabels
|
||||
.map(folderNameInfoArray ->
|
||||
IntStream.range(0, folderNameInfoArray.length)
|
||||
.filter(index -> newLabel.equalsIgnoreCase(
|
||||
folderNameInfoArray[index]))
|
||||
.findFirst()
|
||||
.orElse(-1)
|
||||
).orElse(-1);
|
||||
|
||||
boolean hasValidPrimary = suggestedLabels
|
||||
.map(labels -> labels.length > 0 && !isEmpty(labels[0]))
|
||||
.orElse(false);
|
||||
String primarySuffix = hasValidPrimary
|
||||
? "_WITH_VALID_PRIMARY"
|
||||
: "_WITH_EMPTY_PRIMARY";
|
||||
|
||||
boolean isEmptySuggestions = suggestedLabels
|
||||
.map(labels -> stream(labels).allMatch(TextUtils::isEmpty))
|
||||
.orElse(true);
|
||||
boolean isSuggestionsEnabled = FeatureFlags.FOLDER_NAME_SUGGEST.get();
|
||||
String suggestionsSuffix = isSuggestionsEnabled
|
||||
? isEmptySuggestions
|
||||
? "_WITH_EMPTY_SUGGESTIONS"
|
||||
: "_WITH_VALID_SUGGESTIONS"
|
||||
: "_WITH_SUGGESTIONS_DISABLED";
|
||||
|
||||
return newLabel.equals(mPreviousLabel)
|
||||
? Target.ToFolderLabelState.UNCHANGED
|
||||
: newLabel.isEmpty()
|
||||
? Target.ToFolderLabelState.valueOf("TO_EMPTY" + suggestionsSuffix)
|
||||
: accepted_suggestion_index >= 0
|
||||
? Target.ToFolderLabelState.valueOf("TO_SUGGESTION"
|
||||
+ accepted_suggestion_index
|
||||
+ primarySuffix)
|
||||
: Target.ToFolderLabelState.valueOf("TO_CUSTOM" + suggestionsSuffix);
|
||||
}
|
||||
|
||||
|
||||
private Target.Builder newEditTextTargetBuilder() {
|
||||
return Target.newBuilder().setType(Target.Type.ITEM).setItemType(ItemType.EDITTEXT);
|
||||
}
|
||||
|
||||
private Target.Builder newFolderTargetBuilder() {
|
||||
return Target.newBuilder()
|
||||
.setType(Target.Type.CONTAINER)
|
||||
.setContainerType(ContainerType.FOLDER)
|
||||
.setPageIndex(mInfo.screenId)
|
||||
.setGridX(mInfo.cellX)
|
||||
.setGridY(mInfo.cellY)
|
||||
.setCardinality(mInfo.contents.size());
|
||||
}
|
||||
|
||||
private Target.Builder newParentContainerTarget() {
|
||||
Target.Builder builder = Target.newBuilder().setType(Target.Type.CONTAINER);
|
||||
|
||||
switch (mInfo.container) {
|
||||
case CONTAINER_HOTSEAT:
|
||||
return builder.setContainerType(ContainerType.HOTSEAT);
|
||||
case CONTAINER_DESKTOP:
|
||||
return builder.setContainerType(ContainerType.WORKSPACE);
|
||||
default:
|
||||
throw new AssertionError(String
|
||||
.format("Expected container to be either %s or %s but found %s.",
|
||||
CONTAINER_HOTSEAT,
|
||||
CONTAINER_DESKTOP,
|
||||
mInfo.container));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,15 +393,16 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||
if (!itemAdded) mPreviewItemManager.hidePreviewItem(index, true);
|
||||
final int finalIndex = index;
|
||||
|
||||
String[] suggestedNameOut = new String[FolderNameProvider.SUGGEST_MAX];
|
||||
FolderNameInfo[] nameInfos =
|
||||
new FolderNameInfo[FolderNameProvider.SUGGEST_MAX];
|
||||
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
|
||||
Executors.UI_HELPER_EXECUTOR.post(() -> {
|
||||
d.folderNameProvider.getSuggestedFolderName(
|
||||
getContext(), mInfo.contents, suggestedNameOut);
|
||||
showFinalView(finalIndex, item, suggestedNameOut);
|
||||
getContext(), mInfo.contents, nameInfos);
|
||||
showFinalView(finalIndex, item, nameInfos);
|
||||
});
|
||||
} else {
|
||||
showFinalView(finalIndex, item, suggestedNameOut);
|
||||
showFinalView(finalIndex, item, nameInfos);
|
||||
}
|
||||
} else {
|
||||
addItem(item);
|
||||
@@ -409,12 +410,12 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||
}
|
||||
|
||||
private void showFinalView(int finalIndex, final WorkspaceItemInfo item,
|
||||
String[] suggestedNameOut) {
|
||||
FolderNameInfo[] nameInfos) {
|
||||
postDelayed(() -> {
|
||||
mPreviewItemManager.hidePreviewItem(finalIndex, false);
|
||||
mFolder.showItem(item);
|
||||
invalidate();
|
||||
mFolder.showSuggestedTitle(suggestedNameOut);
|
||||
mFolder.showSuggestedTitle(nameInfos);
|
||||
}, DROP_IN_ANIMATION_DURATION);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -21,15 +21,21 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.FolderInfo;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.model.AllAppsList;
|
||||
import com.android.launcher3.model.BaseModelUpdateTask;
|
||||
import com.android.launcher3.model.BgDataModel;
|
||||
import com.android.launcher3.util.IntSparseArrayMap;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
@@ -49,6 +55,8 @@ public class FolderNameProvider implements ResourceBasedOverride {
|
||||
* name edit box can also be used to provide suggestion.
|
||||
*/
|
||||
public static final int SUGGEST_MAX = 4;
|
||||
protected IntSparseArrayMap<FolderInfo> mFolderInfos;
|
||||
protected List<AppInfo> mAppInfos;
|
||||
|
||||
/**
|
||||
* Retrieve instance of this object that can be overridden in runtime based on the build
|
||||
@@ -57,78 +65,113 @@ public class FolderNameProvider implements ResourceBasedOverride {
|
||||
public static FolderNameProvider newInstance(Context context) {
|
||||
FolderNameProvider fnp = Overrides.getObject(FolderNameProvider.class,
|
||||
context.getApplicationContext(), R.string.folder_name_provider_class);
|
||||
fnp.load(context);
|
||||
|
||||
return fnp;
|
||||
}
|
||||
|
||||
public CharSequence getSuggestedFolderName(Context context,
|
||||
ArrayList<WorkspaceItemInfo> workspaceItemInfos, CharSequence[] candidates) {
|
||||
public static FolderNameProvider newInstance(Context context, List<AppInfo> appInfos,
|
||||
IntSparseArrayMap<FolderInfo> folderInfos) {
|
||||
FolderNameProvider fnp = Overrides.getObject(FolderNameProvider.class,
|
||||
context.getApplicationContext(), R.string.folder_name_provider_class);
|
||||
fnp.load(appInfos, folderInfos);
|
||||
|
||||
return fnp;
|
||||
}
|
||||
|
||||
private void load(Context context) {
|
||||
LauncherAppState.getInstance(context).getModel().enqueueModelUpdateTask(
|
||||
new FolderNameWorker());
|
||||
}
|
||||
|
||||
private void load(List<AppInfo> appInfos, IntSparseArrayMap<FolderInfo> folderInfos) {
|
||||
mAppInfos = appInfos;
|
||||
mFolderInfos = folderInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and rank the suggested Folder names.
|
||||
*/
|
||||
public void getSuggestedFolderName(Context context,
|
||||
ArrayList<WorkspaceItemInfo> workspaceItemInfos,
|
||||
FolderNameInfo[] nameInfos) {
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(candidates));
|
||||
Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(nameInfos));
|
||||
}
|
||||
// If all the icons are from work profile,
|
||||
// Then, suggest "Work" as the folder name
|
||||
List<WorkspaceItemInfo> distinctItemInfos = workspaceItemInfos.stream()
|
||||
.filter(distinctByKey(p-> p.user))
|
||||
.filter(distinctByKey(p -> p.user))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (distinctItemInfos.size() == 1
|
||||
&& !distinctItemInfos.get(0).user.equals(Process.myUserHandle())) {
|
||||
// Place it as last viable suggestion
|
||||
setAsLastSuggestion(candidates,
|
||||
setAsLastSuggestion(nameInfos,
|
||||
context.getResources().getString(R.string.work_folder_name));
|
||||
}
|
||||
|
||||
// If all the icons are from same package (e.g., main icon, shortcut, shortcut)
|
||||
// Then, suggest the package's title as the folder name
|
||||
distinctItemInfos = workspaceItemInfos.stream()
|
||||
.filter(distinctByKey(p-> p.getTargetComponent() != null
|
||||
.filter(distinctByKey(p -> p.getTargetComponent() != null
|
||||
? p.getTargetComponent().getPackageName() : ""))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (distinctItemInfos.size() == 1) {
|
||||
Optional<AppInfo> info = LauncherAppState.getInstance(context).getModel()
|
||||
.getAppInfoByPackageName(distinctItemInfos.get(0).getTargetComponent()
|
||||
.getPackageName());
|
||||
Optional<AppInfo> info = getAppInfoByPackageName(
|
||||
distinctItemInfos.get(0).getTargetComponent().getPackageName());
|
||||
// Place it as first viable suggestion and shift everything else
|
||||
info.ifPresent(i -> setAsFirstSuggestion(candidates, i.title.toString()));
|
||||
info.ifPresent(i -> setAsFirstSuggestion(nameInfos, i.title.toString()));
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(candidates));
|
||||
Log.d(TAG, "getSuggestedFolderName:" + Arrays.toString(nameInfos));
|
||||
}
|
||||
return candidates[0];
|
||||
}
|
||||
|
||||
private void setAsFirstSuggestion(CharSequence[] candidatesOut, CharSequence candidate) {
|
||||
if (contains(candidatesOut, candidate)) {
|
||||
private Optional<AppInfo> getAppInfoByPackageName(String packageName) {
|
||||
if (mAppInfos == null || mAppInfos.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return mAppInfos.stream()
|
||||
.filter(info -> info.componentName.getPackageName().equals(packageName))
|
||||
.findAny();
|
||||
}
|
||||
|
||||
private void setAsFirstSuggestion(FolderNameInfo[] nameInfos, CharSequence label) {
|
||||
if (nameInfos.length == 0 || contains(nameInfos, label)) {
|
||||
return;
|
||||
}
|
||||
for (int i = candidatesOut.length - 1; i > 0; i--) {
|
||||
if (!TextUtils.isEmpty(candidatesOut[i - 1])) {
|
||||
candidatesOut[i] = candidatesOut[i - 1];
|
||||
for (int i = nameInfos.length - 1; i > 0; i--) {
|
||||
if (nameInfos[i - 1] != null && !TextUtils.isEmpty(nameInfos[i - 1].getLabel())) {
|
||||
nameInfos[i] = nameInfos[i - 1];
|
||||
}
|
||||
}
|
||||
candidatesOut[0] = candidate;
|
||||
nameInfos[0] = new FolderNameInfo(label, 1.0);
|
||||
}
|
||||
|
||||
private void setAsLastSuggestion(CharSequence[] candidatesOut, CharSequence candidate) {
|
||||
if (contains(candidatesOut, candidate)) {
|
||||
private void setAsLastSuggestion(FolderNameInfo[] nameInfos, CharSequence label) {
|
||||
if (nameInfos.length == 0 || contains(nameInfos, label)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < candidate.length(); i++) {
|
||||
if (TextUtils.isEmpty(candidatesOut[i])) {
|
||||
candidatesOut[i] = candidate;
|
||||
for (int i = 0; i < nameInfos.length; i++) {
|
||||
if (nameInfos[i] == null || TextUtils.isEmpty(nameInfos[i].getLabel())) {
|
||||
nameInfos[i] = new FolderNameInfo(label, 1.0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
candidatesOut[candidate.length() - 1] = candidate;
|
||||
// Overwrite the last suggestion.
|
||||
int lastIndex = nameInfos.length - 1;
|
||||
nameInfos[lastIndex] = new FolderNameInfo(label, 1.0);
|
||||
}
|
||||
|
||||
private boolean contains(CharSequence[] list, CharSequence key) {
|
||||
return Arrays.asList(list).stream()
|
||||
.filter(s -> s != null)
|
||||
.anyMatch(s -> s.toString().equalsIgnoreCase(key.toString()));
|
||||
private boolean contains(FolderNameInfo[] nameInfos, CharSequence label) {
|
||||
return Arrays.stream(nameInfos)
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(nameInfo -> nameInfo.getLabel().toString().equalsIgnoreCase(
|
||||
label.toString()));
|
||||
}
|
||||
|
||||
// This method can be moved to some Utility class location.
|
||||
@@ -136,4 +179,13 @@ public class FolderNameProvider implements ResourceBasedOverride {
|
||||
Map<Object, Boolean> map = new ConcurrentHashMap<>();
|
||||
return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
|
||||
}
|
||||
|
||||
private class FolderNameWorker extends BaseModelUpdateTask {
|
||||
@Override
|
||||
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
|
||||
mFolderInfos = dataModel.folders.clone();
|
||||
mAppInfos = Arrays.asList(apps.copyData());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ public class DragPreviewProvider {
|
||||
}
|
||||
|
||||
public final void generateDragOutline(Bitmap preview) {
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD && mOutlineGeneratorCallback != null) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD && mOutlineGeneratorCallback != null) {
|
||||
throw new RuntimeException("Drag outline generated twice");
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ public interface ComponentWithLabel {
|
||||
CharSequence getLabel(PackageManager pm);
|
||||
|
||||
|
||||
class ComponentCachingLogic implements CachingLogic<ComponentWithLabel> {
|
||||
class ComponentCachingLogic<T extends ComponentWithLabel> implements CachingLogic<T> {
|
||||
|
||||
private final PackageManager mPackageManager;
|
||||
private final boolean mAddToMemCache;
|
||||
@@ -42,22 +42,22 @@ public interface ComponentWithLabel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentName getComponent(ComponentWithLabel object) {
|
||||
public ComponentName getComponent(T object) {
|
||||
return object.getComponent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserHandle getUser(ComponentWithLabel object) {
|
||||
public UserHandle getUser(T object) {
|
||||
return object.getUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getLabel(ComponentWithLabel object) {
|
||||
public CharSequence getLabel(T object) {
|
||||
return object.getLabel(mPackageManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitmapInfo loadIcon(Context context, ComponentWithLabel object) {
|
||||
public BitmapInfo loadIcon(Context context, T object) {
|
||||
return BitmapInfo.LOW_RES_INFO;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.icons;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
|
||||
/**
|
||||
* Extension of ComponentWithLabel to also support loading icons
|
||||
*/
|
||||
public interface ComponentWithLabelAndIcon extends ComponentWithLabel {
|
||||
|
||||
/**
|
||||
* Provide an icon for this object
|
||||
*/
|
||||
Drawable getFullResIcon(IconCache cache);
|
||||
|
||||
class ComponentWithIconCachingLogic extends ComponentCachingLogic<ComponentWithLabelAndIcon> {
|
||||
|
||||
public ComponentWithIconCachingLogic(Context context, boolean addToMemCache) {
|
||||
super(context, addToMemCache);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public BitmapInfo loadIcon(Context context, ComponentWithLabelAndIcon object) {
|
||||
Drawable d = object.getFullResIcon(LauncherAppState.getInstance(context)
|
||||
.getIconCache());
|
||||
if (d == null) {
|
||||
return super.loadIcon(context, object);
|
||||
}
|
||||
try (LauncherIcons li = LauncherIcons.obtain(context)) {
|
||||
return li.createBadgedIconBitmap(d, object.getUser(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.android.launcher3.icons;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@@ -56,6 +57,7 @@ import com.android.launcher3.util.InstantAppResolver;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
@@ -65,6 +67,9 @@ public class IconCache extends BaseIconCache {
|
||||
|
||||
private static final String TAG = "Launcher.IconCache";
|
||||
|
||||
private final Predicate<ItemInfoWithIcon> mIsUsingFallbackIconCheck = w -> w.bitmap != null
|
||||
&& w.bitmap.isNullOrLowRes() && !isDefaultIcon(w.bitmap, w.user);
|
||||
|
||||
private final CachingLogic<ComponentWithLabel> mComponentWithLabelCachingLogic;
|
||||
private final CachingLogic<LauncherActivityInfo> mLauncherActivityInfoCachingLogic;
|
||||
private final CachingLogic<ShortcutInfo> mShortcutCachingLogic;
|
||||
@@ -179,6 +184,77 @@ public class IconCache extends BaseIconCache {
|
||||
getTitleAndIcon(info, () -> activityInfo, false, useLowResIcon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in {@param info} with the icon for {@param si}
|
||||
*/
|
||||
public void getShortcutIcon(ItemInfoWithIcon info, ShortcutInfo si) {
|
||||
getShortcutIcon(info, si, true, mIsUsingFallbackIconCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in {@param info} with an unbadged icon for {@param si}
|
||||
*/
|
||||
public void getUnbadgedShortcutIcon(ItemInfoWithIcon info, ShortcutInfo si) {
|
||||
getShortcutIcon(info, si, false, mIsUsingFallbackIconCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in {@param info} with the icon and label for {@param si}. If the icon is not
|
||||
* available, and fallback check returns true, it keeps the old icon.
|
||||
*/
|
||||
public <T extends ItemInfoWithIcon> void getShortcutIcon(T info, ShortcutInfo si,
|
||||
@NonNull Predicate<T> fallbackIconCheck) {
|
||||
getShortcutIcon(info, si, true /* use badged */, fallbackIconCheck);
|
||||
}
|
||||
|
||||
private synchronized <T extends ItemInfoWithIcon> void getShortcutIcon(T info, ShortcutInfo si,
|
||||
boolean useBadged, @NonNull Predicate<T> fallbackIconCheck) {
|
||||
BitmapInfo bitmapInfo;
|
||||
if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
|
||||
bitmapInfo = cacheLocked(ShortcutKey.fromInfo(si).componentName, si.getUserHandle(),
|
||||
() -> si, mShortcutCachingLogic, false, false).bitmap;
|
||||
} else {
|
||||
// If caching is disabled, load the full icon
|
||||
bitmapInfo = mShortcutCachingLogic.loadIcon(mContext, si);
|
||||
}
|
||||
if (bitmapInfo.isNullOrLowRes()) {
|
||||
bitmapInfo = getDefaultIcon(si.getUserHandle());
|
||||
}
|
||||
|
||||
if (isDefaultIcon(bitmapInfo, si.getUserHandle()) && fallbackIconCheck.test(info)) {
|
||||
return;
|
||||
}
|
||||
info.bitmap = bitmapInfo;
|
||||
if (useBadged) {
|
||||
BitmapInfo badgeInfo = getShortcutInfoBadge(si);
|
||||
try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
|
||||
info.bitmap = li.badgeBitmap(info.bitmap.icon, badgeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the badging info for the shortcut
|
||||
*/
|
||||
public BitmapInfo getShortcutInfoBadge(ShortcutInfo shortcutInfo) {
|
||||
ComponentName cn = shortcutInfo.getActivity();
|
||||
if (cn != null) {
|
||||
// Get the app info for the source activity.
|
||||
AppInfo appInfo = new AppInfo();
|
||||
appInfo.user = shortcutInfo.getUserHandle();
|
||||
appInfo.componentName = cn;
|
||||
appInfo.intent = new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
.setComponent(cn);
|
||||
getTitleAndIcon(appInfo, false);
|
||||
return appInfo.bitmap;
|
||||
} else {
|
||||
PackageItemInfo pkgInfo = new PackageItemInfo(shortcutInfo.getPackage());
|
||||
getTitleAndIconForApp(pkgInfo, false);
|
||||
return pkgInfo.bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in info with the icon and label for deep shortcut.
|
||||
*/
|
||||
|
||||
@@ -16,28 +16,11 @@
|
||||
|
||||
package com.android.launcher3.icons;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Process;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.FastBitmapDrawable;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
import com.android.launcher3.model.PackageItemInfo;
|
||||
import com.android.launcher3.util.Themes;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
|
||||
@@ -111,114 +94,4 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
|
||||
public void close() {
|
||||
recycle();
|
||||
}
|
||||
|
||||
// below methods should also migrate to BaseIconFactory
|
||||
public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo) {
|
||||
return createShortcutIcon(shortcutInfo, true /* badged */);
|
||||
}
|
||||
|
||||
public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged) {
|
||||
return createShortcutIcon(shortcutInfo, badged, null);
|
||||
}
|
||||
|
||||
public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged,
|
||||
@Nullable Supplier<ItemInfoWithIcon> fallbackIconProvider) {
|
||||
if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
|
||||
return createShortcutIconCached(shortcutInfo, badged, true, fallbackIconProvider);
|
||||
} else {
|
||||
return createShortcutIconLegacy(shortcutInfo, badged, fallbackIconProvider);
|
||||
}
|
||||
}
|
||||
|
||||
public BitmapInfo createShortcutIconLegacy(ShortcutInfo shortcutInfo, boolean badged,
|
||||
@Nullable Supplier<ItemInfoWithIcon> fallbackIconProvider) {
|
||||
Drawable unbadgedDrawable = ShortcutCachingLogic.getIcon(
|
||||
mContext, shortcutInfo, mFillResIconDpi);
|
||||
IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
|
||||
final Bitmap unbadgedBitmap;
|
||||
if (unbadgedDrawable != null) {
|
||||
unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0);
|
||||
} else {
|
||||
if (fallbackIconProvider != null) {
|
||||
// Fallback icons are already badged and with appropriate shadow
|
||||
ItemInfoWithIcon fullIcon = fallbackIconProvider.get();
|
||||
if (fullIcon != null && fullIcon.bitmap != null) {
|
||||
return fullIcon.bitmap;
|
||||
}
|
||||
}
|
||||
unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
|
||||
}
|
||||
|
||||
if (!badged) {
|
||||
return BitmapInfo.of(unbadgedBitmap, Themes.getColorAccent(mContext));
|
||||
}
|
||||
|
||||
final Bitmap unbadgedfinal = unbadgedBitmap;
|
||||
final ItemInfoWithIcon badge = getShortcutInfoBadge(shortcutInfo, cache);
|
||||
|
||||
Bitmap icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> {
|
||||
getShadowGenerator().recreateIcon(unbadgedfinal, c);
|
||||
badgeWithDrawable(c, new FastBitmapDrawable(badge.bitmap));
|
||||
});
|
||||
return BitmapInfo.of(icon, badge.bitmap.color);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public BitmapInfo createShortcutIconCached(ShortcutInfo shortcutInfo, boolean badged,
|
||||
boolean useCache, @Nullable Supplier<ItemInfoWithIcon> fallbackIconProvider) {
|
||||
IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
|
||||
final BitmapInfo bitmapInfo;
|
||||
if (useCache) {
|
||||
bitmapInfo = cache.getDeepShortcutTitleAndIcon(shortcutInfo).bitmap;
|
||||
} else {
|
||||
bitmapInfo = new ShortcutCachingLogic().loadIcon(mContext, shortcutInfo);
|
||||
}
|
||||
final Bitmap unbadgedBitmap;
|
||||
if (bitmapInfo.icon != null) {
|
||||
unbadgedBitmap = bitmapInfo.icon;
|
||||
} else {
|
||||
if (fallbackIconProvider != null) {
|
||||
// Fallback icons are already badged and with appropriate shadow
|
||||
ItemInfoWithIcon fullIcon = fallbackIconProvider.get();
|
||||
if (fullIcon != null && fullIcon.bitmap != null) {
|
||||
return fullIcon.bitmap;
|
||||
}
|
||||
}
|
||||
unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
|
||||
}
|
||||
|
||||
if (!badged) {
|
||||
return BitmapInfo.of(unbadgedBitmap, Themes.getColorAccent(mContext));
|
||||
}
|
||||
|
||||
final Bitmap unbadgedfinal = unbadgedBitmap;
|
||||
final ItemInfoWithIcon badge = getShortcutInfoBadge(shortcutInfo, cache);
|
||||
|
||||
Bitmap icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> {
|
||||
getShadowGenerator().recreateIcon(unbadgedfinal, c);
|
||||
badgeWithDrawable(c, new FastBitmapDrawable(badge.bitmap));
|
||||
});
|
||||
return BitmapInfo.of(icon, badge.bitmap.color);
|
||||
}
|
||||
|
||||
public ItemInfoWithIcon getShortcutInfoBadge(ShortcutInfo shortcutInfo, IconCache cache) {
|
||||
ComponentName cn = shortcutInfo.getActivity();
|
||||
String badgePkg = shortcutInfo.getPackage();
|
||||
boolean hasBadgePkgSet = !badgePkg.equals(shortcutInfo.getPackage());
|
||||
if (cn != null && !hasBadgePkgSet) {
|
||||
// Get the app info for the source activity.
|
||||
AppInfo appInfo = new AppInfo();
|
||||
appInfo.user = shortcutInfo.getUserHandle();
|
||||
appInfo.componentName = cn;
|
||||
appInfo.intent = new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
.setComponent(cn);
|
||||
cache.getTitleAndIcon(appInfo, false);
|
||||
return appInfo;
|
||||
} else {
|
||||
PackageItemInfo pkgInfo = new PackageItemInfo(badgePkg);
|
||||
cache.getTitleAndIconForApp(pkgInfo, false);
|
||||
return pkgInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -57,6 +58,12 @@ public class ShortcutCachingLogic implements CachingLogic<ShortcutInfo> {
|
||||
return info.getShortLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getDescription(ShortcutInfo object, CharSequence fallback) {
|
||||
CharSequence label = object.getLongLabel();
|
||||
return TextUtils.isEmpty(label) ? fallback : label;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public BitmapInfo loadIcon(Context context, ShortcutInfo info) {
|
||||
|
||||
@@ -42,7 +42,7 @@ public final class FileLog {
|
||||
private static Handler sHandler = null;
|
||||
private static File sLogsDirectory = null;
|
||||
|
||||
private static final int LOG_DAYS = 2;
|
||||
public static final int LOG_DAYS = 4;
|
||||
|
||||
public static void setDir(File logsDir) {
|
||||
if (ENABLED) {
|
||||
|
||||
@@ -69,8 +69,7 @@ import java.util.UUID;
|
||||
public class UserEventDispatcher implements ResourceBasedOverride {
|
||||
|
||||
private static final String TAG = "UserEvent";
|
||||
private static final boolean IS_VERBOSE =
|
||||
FeatureFlags.IS_DOGFOOD_BUILD && Utilities.isPropertyEnabled(LogConfig.USEREVENT);
|
||||
private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.USEREVENT);
|
||||
private static final String UUID_STORAGE = "uuid";
|
||||
|
||||
public static UserEventDispatcher newInstance(Context context,
|
||||
@@ -372,6 +371,25 @@ public class UserEventDispatcher implements ResourceBasedOverride {
|
||||
dispatchUserEvent(event, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs proto lite version of LauncherEvent object to clearcut.
|
||||
*/
|
||||
public void logLauncherEvent(
|
||||
com.android.launcher3.userevent.LauncherLogProto.LauncherEvent launcherEvent) {
|
||||
|
||||
if (mPreviousHomeGesture) {
|
||||
mPreviousHomeGesture = false;
|
||||
}
|
||||
mAppOrTaskLaunch = false;
|
||||
launcherEvent.toBuilder()
|
||||
.setElapsedContainerMillis(SystemClock.uptimeMillis() - mElapsedContainerMillis)
|
||||
.setElapsedSessionMillis(SystemClock.uptimeMillis() - mElapsedSessionMillis).build();
|
||||
if (!IS_VERBOSE) {
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, launcherEvent.toString());
|
||||
}
|
||||
|
||||
public void logDeepShortcutsOpen(View icon) {
|
||||
LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(icon);
|
||||
if (icon == null || !(icon.getTag() instanceof ItemInfo || provider == null)) {
|
||||
|
||||
@@ -273,7 +273,7 @@ public class BgDataModel {
|
||||
switch (item.itemType) {
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
|
||||
folders.remove(item.id);
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
for (ItemInfo info : itemsIdMap) {
|
||||
if (info.container == item.id) {
|
||||
// We are deleting a folder which still contains items that
|
||||
|
||||
@@ -74,8 +74,8 @@ public class GridBackupTable {
|
||||
@IntDef({STATE_NOT_FOUND, STATE_RAW, STATE_SANITIZED})
|
||||
private @interface BackupState { }
|
||||
|
||||
public GridBackupTable(Context context, SQLiteDatabase db,
|
||||
int hotseatSize, int gridX, int gridY) {
|
||||
public GridBackupTable(Context context, SQLiteDatabase db, int hotseatSize, int gridX,
|
||||
int gridY) {
|
||||
mContext = context;
|
||||
mDb = db;
|
||||
|
||||
@@ -105,7 +105,7 @@ public class GridBackupTable {
|
||||
}
|
||||
long userSerial = UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
|
||||
Process.myUserHandle());
|
||||
copyTable(BACKUP_TABLE_NAME, Favorites.TABLE_NAME, userSerial);
|
||||
copyTable(mDb, BACKUP_TABLE_NAME, Favorites.TABLE_NAME, userSerial);
|
||||
Log.d(TAG, "Backup table found");
|
||||
return true;
|
||||
}
|
||||
@@ -118,10 +118,10 @@ public class GridBackupTable {
|
||||
/**
|
||||
* Copy valid grid entries from one table to another.
|
||||
*/
|
||||
private void copyTable(String from, String to, long userSerial) {
|
||||
dropTable(mDb, to);
|
||||
Favorites.addTableToDb(mDb, userSerial, false, to);
|
||||
mDb.execSQL("INSERT INTO " + to + " SELECT * FROM " + from + " where _id > " + ID_PROPERTY);
|
||||
private static void copyTable(SQLiteDatabase db, String from, String to, long userSerial) {
|
||||
dropTable(db, to);
|
||||
Favorites.addTableToDb(db, userSerial, false, to);
|
||||
db.execSQL("INSERT INTO " + to + " SELECT * FROM " + from + " where _id > " + ID_PROPERTY);
|
||||
}
|
||||
|
||||
private void encodeDBProperties(int options) {
|
||||
@@ -174,7 +174,7 @@ public class GridBackupTable {
|
||||
// skip restore if dimensions in backup table differs from current setup.
|
||||
return false;
|
||||
}
|
||||
copyTable(Favorites.BACKUP_TABLE_NAME, Favorites.TABLE_NAME, oldProfileId);
|
||||
copyTable(mDb, Favorites.BACKUP_TABLE_NAME, Favorites.TABLE_NAME, oldProfileId);
|
||||
Log.d(TAG, "Backup restored");
|
||||
return true;
|
||||
}
|
||||
@@ -183,7 +183,7 @@ public class GridBackupTable {
|
||||
* Performs a backup on the workspace layout.
|
||||
*/
|
||||
public void doBackup(long profileId, int options) {
|
||||
copyTable(Favorites.TABLE_NAME, Favorites.BACKUP_TABLE_NAME, profileId);
|
||||
copyTable(mDb, Favorites.TABLE_NAME, Favorites.BACKUP_TABLE_NAME, profileId);
|
||||
encodeDBProperties(options);
|
||||
}
|
||||
|
||||
|
||||
+15
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
* 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.
|
||||
@@ -13,25 +13,28 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.uioverrides;
|
||||
|
||||
package com.android.launcher3.model;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.OrientationEventListener;
|
||||
|
||||
/**
|
||||
* Utility class for listening for rotation changes
|
||||
* This class takes care of shrinking the workspace (by maximum of one row and one column), as a
|
||||
* result of restoring from a larger device or device density change.
|
||||
*/
|
||||
public class DisplayRotationListener extends OrientationEventListener {
|
||||
public class GridSizeMigrationTaskV2 {
|
||||
|
||||
private final Runnable mCallback;
|
||||
private GridSizeMigrationTaskV2(Context context) {
|
||||
|
||||
public DisplayRotationListener(Context context, Runnable callback) {
|
||||
super(context);
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOrientationChanged(int i) {
|
||||
mCallback.run();
|
||||
/**
|
||||
* Migrates the workspace and hotseat in case their sizes changed.
|
||||
*
|
||||
* @return false if the migration failed.
|
||||
*/
|
||||
public static boolean migrateGridIfNeeded(Context context) {
|
||||
// To be implemented.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.launcher3.model;
|
||||
|
||||
import static android.graphics.BitmapFactory.decodeByteArray;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
@@ -26,7 +28,6 @@ import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.database.CursorWrapper;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.BaseColumns;
|
||||
import android.text.TextUtils;
|
||||
@@ -166,37 +167,30 @@ public class LoaderCursor extends CursorWrapper {
|
||||
*/
|
||||
protected boolean loadIcon(WorkspaceItemInfo info) {
|
||||
try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
|
||||
return loadIcon(info, li);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the icon from the cursor and updates the {@param info} if the icon is an app resource.
|
||||
*/
|
||||
protected boolean loadIcon(WorkspaceItemInfo info, LauncherIcons li) {
|
||||
if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
|
||||
String packageName = getString(iconPackageIndex);
|
||||
String resourceName = getString(iconResourceIndex);
|
||||
if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) {
|
||||
info.iconResource = new ShortcutIconResource();
|
||||
info.iconResource.packageName = packageName;
|
||||
info.iconResource.resourceName = resourceName;
|
||||
BitmapInfo iconInfo = li.createIconBitmap(info.iconResource);
|
||||
if (iconInfo != null) {
|
||||
info.bitmap = iconInfo;
|
||||
return true;
|
||||
if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
|
||||
String packageName = getString(iconPackageIndex);
|
||||
String resourceName = getString(iconResourceIndex);
|
||||
if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) {
|
||||
info.iconResource = new ShortcutIconResource();
|
||||
info.iconResource.packageName = packageName;
|
||||
info.iconResource.resourceName = resourceName;
|
||||
BitmapInfo iconInfo = li.createIconBitmap(info.iconResource);
|
||||
if (iconInfo != null) {
|
||||
info.bitmap = iconInfo;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to load from resource, try loading from DB.
|
||||
byte[] data = getBlob(iconIndex);
|
||||
try {
|
||||
info.bitmap = li.createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to decode byte array for info " + info, e);
|
||||
return false;
|
||||
// Failed to load from resource, try loading from DB.
|
||||
byte[] data = getBlob(iconIndex);
|
||||
try {
|
||||
info.bitmap = li.createIconBitmap(decodeByteArray(data, 0, data.length));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to decode byte array for info " + info, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.launcher3.model;
|
||||
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
|
||||
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
|
||||
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
|
||||
import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO;
|
||||
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
|
||||
@@ -35,7 +36,6 @@ import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageInstaller.SessionInfo;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.text.TextUtils;
|
||||
@@ -50,7 +50,6 @@ import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.FolderInfo;
|
||||
import com.android.launcher3.InstallShortcutReceiver;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
@@ -60,12 +59,12 @@ import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.folder.Folder;
|
||||
import com.android.launcher3.folder.FolderGridOrganizer;
|
||||
import com.android.launcher3.folder.FolderNameInfo;
|
||||
import com.android.launcher3.folder.FolderNameProvider;
|
||||
import com.android.launcher3.icons.ComponentWithLabel;
|
||||
import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
|
||||
import com.android.launcher3.icons.ComponentWithLabelAndIcon;
|
||||
import com.android.launcher3.icons.ComponentWithLabelAndIcon.ComponentWithIconCachingLogic;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.icons.LauncherActivityCachingLogic;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.icons.ShortcutCachingLogic;
|
||||
import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
@@ -94,7 +93,6 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Runnable for the thread that loads the contents of the launcher:
|
||||
@@ -170,32 +168,15 @@ public class LoaderTask implements Runnable {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
|
||||
"LoaderTask1 " + this);
|
||||
}
|
||||
synchronized (this) {
|
||||
// Skip fast if we are already stopped.
|
||||
if (mStopped) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
|
||||
"LoaderTask2 " + this);
|
||||
}
|
||||
|
||||
Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
|
||||
TimingLogger logger = TestProtocol.sDebugTracing ?
|
||||
new TimingLogger(TAG, "run") {
|
||||
@Override
|
||||
public void addSplit(String splitLabel) {
|
||||
super.addSplit(splitLabel);
|
||||
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
|
||||
"LoaderTask.addSplit " + splitLabel);
|
||||
}
|
||||
}
|
||||
: new TimingLogger(TAG, "run");
|
||||
TimingLogger logger = new TimingLogger(TAG, "run");
|
||||
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
|
||||
List<ShortcutInfo> allShortcuts = new ArrayList<>();
|
||||
loadWorkspace(allShortcuts);
|
||||
@@ -263,7 +244,8 @@ public class LoaderTask implements Runnable {
|
||||
verifyNotStopped();
|
||||
|
||||
// fourth step
|
||||
List<ComponentWithLabel> allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null);
|
||||
List<ComponentWithLabelAndIcon> allWidgetsList =
|
||||
mBgDataModel.widgetsModel.update(mApp, null);
|
||||
logger.addSplit("load widgets");
|
||||
|
||||
verifyNotStopped();
|
||||
@@ -271,8 +253,9 @@ public class LoaderTask implements Runnable {
|
||||
logger.addSplit("bindWidgets");
|
||||
verifyNotStopped();
|
||||
|
||||
updateHandler.updateIcons(allWidgetsList, new ComponentCachingLogic(
|
||||
mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated);
|
||||
updateHandler.updateIcons(allWidgetsList,
|
||||
new ComponentWithIconCachingLogic(mApp.getContext(), true),
|
||||
mApp.getModel()::onWidgetLabelsUpdated);
|
||||
logger.addSplit("save widgets in icon cache");
|
||||
|
||||
// fifth step
|
||||
@@ -284,10 +267,6 @@ public class LoaderTask implements Runnable {
|
||||
updateHandler.finish();
|
||||
logger.addSplit("finish icon update");
|
||||
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
|
||||
"LoaderTask3 " + this);
|
||||
}
|
||||
transaction.commit();
|
||||
} catch (CancellationException e) {
|
||||
// Loader stopped, ignore
|
||||
@@ -320,7 +299,9 @@ public class LoaderTask implements Runnable {
|
||||
clearDb = true;
|
||||
}
|
||||
|
||||
if (!clearDb && !GridSizeMigrationTask.migrateGridIfNeeded(context)) {
|
||||
if (!clearDb && (MULTI_DB_GRID_MIRATION_ALGO.get()
|
||||
? !GridSizeMigrationTaskV2.migrateGridIfNeeded(context)
|
||||
: !GridSizeMigrationTask.migrateGridIfNeeded(context))) {
|
||||
// Migration failed. Clear workspace.
|
||||
clearDb = true;
|
||||
}
|
||||
@@ -544,17 +525,10 @@ public class LoaderTask implements Runnable {
|
||||
continue;
|
||||
}
|
||||
info = new WorkspaceItemInfo(pinnedShortcut, context);
|
||||
final WorkspaceItemInfo finalInfo = info;
|
||||
|
||||
LauncherIcons li = LauncherIcons.obtain(context);
|
||||
// If the pinned deep shortcut is no longer published,
|
||||
// use the last saved icon instead of the default.
|
||||
Supplier<ItemInfoWithIcon> fallbackIconProvider = () ->
|
||||
c.loadIcon(finalInfo, li) ? finalInfo : null;
|
||||
info.bitmap = li.createShortcutIcon(
|
||||
pinnedShortcut, true /* badged */,
|
||||
fallbackIconProvider);
|
||||
li.recycle();
|
||||
mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon);
|
||||
|
||||
if (pmHelper.isAppSuspended(
|
||||
pinnedShortcut.getPackage(), info.user)) {
|
||||
info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
|
||||
@@ -854,23 +828,23 @@ public class LoaderTask implements Runnable {
|
||||
|
||||
private void setIgnorePackages(IconCacheUpdateHandler updateHandler) {
|
||||
// Ignore packages which have a promise icon.
|
||||
HashSet<String> packagesToIgnore = new HashSet<>();
|
||||
synchronized (mBgDataModel) {
|
||||
for (ItemInfo info : mBgDataModel.itemsIdMap) {
|
||||
if (info instanceof WorkspaceItemInfo) {
|
||||
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
|
||||
if (si.isPromise() && si.getTargetComponent() != null) {
|
||||
packagesToIgnore.add(si.getTargetComponent().getPackageName());
|
||||
updateHandler.addPackagesToIgnore(
|
||||
si.user, si.getTargetComponent().getPackageName());
|
||||
}
|
||||
} else if (info instanceof LauncherAppWidgetInfo) {
|
||||
LauncherAppWidgetInfo lawi = (LauncherAppWidgetInfo) info;
|
||||
if (lawi.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
|
||||
packagesToIgnore.add(lawi.providerName.getPackageName());
|
||||
updateHandler.addPackagesToIgnore(
|
||||
lawi.user, lawi.providerName.getPackageName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
updateHandler.setPackagesToIgnore(Process.myUserHandle(), packagesToIgnore);
|
||||
}
|
||||
|
||||
private List<LauncherActivityInfo> loadAllApps() {
|
||||
@@ -927,15 +901,18 @@ public class LoaderTask implements Runnable {
|
||||
}
|
||||
|
||||
private void loadFolderNames() {
|
||||
FolderNameProvider provider = FolderNameProvider.newInstance(mApp.getContext());
|
||||
FolderNameProvider provider = FolderNameProvider.newInstance(mApp.getContext(),
|
||||
mBgAllAppsList.data, mBgDataModel.folders);
|
||||
|
||||
synchronized (mBgDataModel) {
|
||||
for (int i = 0; i < mBgDataModel.folders.size(); i++) {
|
||||
String[] suggestedOut = new String[FolderNameProvider.SUGGEST_MAX];
|
||||
FolderNameInfo[] suggestionInfos =
|
||||
new FolderNameInfo[FolderNameProvider.SUGGEST_MAX];
|
||||
FolderInfo info = mBgDataModel.folders.valueAt(i);
|
||||
if (info.suggestedFolderNames == null) {
|
||||
provider.getSuggestedFolderName(mApp.getContext(), info.contents, suggestedOut);
|
||||
info.suggestedFolderNames = new Intent().putExtra("suggest", suggestedOut);
|
||||
provider.getSuggestedFolderName(mApp.getContext(), info.contents,
|
||||
suggestionInfos);
|
||||
info.suggestedFolderNames = new Intent().putExtra("suggest", suggestionInfos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public class ModelUtils {
|
||||
return Integer.compare(lhs.screenId, rhs.screenId);
|
||||
}
|
||||
default:
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (FeatureFlags.IS_STUDIO_BUILD) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected container type when sorting workspace items.");
|
||||
}
|
||||
|
||||
@@ -115,8 +115,9 @@ public class ModelWriter {
|
||||
ItemInfo modelItem = mBgDataModel.itemsIdMap.get(itemId);
|
||||
if (modelItem != null && item != modelItem) {
|
||||
// check all the data is consistent
|
||||
if (!Utilities.IS_DEBUG_DEVICE && !FeatureFlags.IS_DOGFOOD_BUILD &&
|
||||
modelItem instanceof WorkspaceItemInfo && item instanceof WorkspaceItemInfo) {
|
||||
if (!Utilities.IS_DEBUG_DEVICE && !FeatureFlags.IS_STUDIO_BUILD
|
||||
&& modelItem instanceof WorkspaceItemInfo
|
||||
&& item instanceof WorkspaceItemInfo) {
|
||||
if (modelItem.title.toString().equals(item.title.toString()) &&
|
||||
modelItem.getIntent().filterEquals(item.getIntent()) &&
|
||||
modelItem.id == item.id &&
|
||||
@@ -320,7 +321,7 @@ public class ModelWriter {
|
||||
*/
|
||||
public void prepareToUndoDelete() {
|
||||
if (!mPreparingToUndo) {
|
||||
if (!mDeleteRunnables.isEmpty() && FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
if (!mDeleteRunnables.isEmpty() && FeatureFlags.IS_STUDIO_BUILD) {
|
||||
throw new IllegalStateException("There are still uncommitted delete operations!");
|
||||
}
|
||||
mDeleteRunnables.clear();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user