diff options
70 files changed, 613 insertions, 264 deletions
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml index 5318a12ed..8db875be9 100644 --- a/AndroidManifest-common.xml +++ b/AndroidManifest-common.xml @@ -43,6 +43,7 @@ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" /> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <!-- diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java b/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java index 1ccd7d79a..66aec4050 100644 --- a/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java +++ b/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java @@ -64,7 +64,7 @@ public final class LandscapeStatesTouchController extends PortraitStatesTouchCon } @Override - protected int getLogContainerTypeForNormalState() { + protected int getLogContainerTypeForNormalState(MotionEvent ev) { return LauncherLogProto.ContainerType.WORKSPACE; } } diff --git a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java index 1e449108d..ee113dfeb 100644 --- a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java +++ b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java @@ -25,6 +25,7 @@ import android.os.Bundle; import android.os.UserHandle; import com.android.launcher3.ItemInfo; +import com.android.launcher3.notification.NotificationKeyData; import java.util.Collections; import java.util.List; @@ -48,10 +49,6 @@ public class DeepShortcutManager { private DeepShortcutManager(Context context) { } - public static boolean supportsShortcuts(ItemInfo info) { - return false; - } - public boolean wasLastCallSuccess() { return false; } diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java index d84633d56..36d1c3ecc 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java @@ -36,12 +36,16 @@ import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Handler; +import android.os.LocaleList; import android.os.Looper; import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.BitmapRenderer; @@ -57,8 +61,6 @@ import java.util.Map; import java.util.Set; import java.util.function.Supplier; -import androidx.annotation.NonNull; - public abstract class BaseIconCache { private static final String TAG = "BaseIconCache"; @@ -84,6 +86,7 @@ public abstract class BaseIconCache { protected int mIconDpi; protected IconDB mIconDb; + protected LocaleList mLocaleList = LocaleList.getEmptyLocaleList(); protected String mSystemState = ""; private final String mDbFileName; @@ -227,12 +230,12 @@ public abstract class BaseIconCache { /** * Refreshes the system state definition used to check the validity of the cache. It - * incorporates all the properties that can affect the cache like locale and system-version. + * incorporates all the properties that can affect the cache like the list of enabled locale + * and system-version. */ private void updateSystemState() { - final String locale = - mContext.getResources().getConfiguration().getLocales().toLanguageTags(); - mSystemState = locale + "," + Build.VERSION.SDK_INT; + mLocaleList = mContext.getResources().getConfiguration().getLocales(); + mSystemState = mLocaleList.toLanguageTags() + "," + Build.VERSION.SDK_INT; } protected String getIconSystemState(String packageName) { @@ -269,7 +272,7 @@ public abstract class BaseIconCache { mCache.put(key, entry); ContentValues values = newContentValues(entry, entry.title.toString(), - componentName.getPackageName()); + componentName.getPackageName(), cachingLogic.getKeywords(object, mLocaleList)); addIconToDB(values, componentName, info, userSerial); } @@ -445,7 +448,7 @@ public abstract class BaseIconCache { // Add the icon in the DB here, since these do not get written during // package updates. ContentValues values = newContentValues( - iconInfo, entry.title.toString(), packageName); + iconInfo, entry.title.toString(), packageName, null); addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user)); } catch (NameNotFoundException e) { @@ -504,23 +507,35 @@ public abstract class BaseIconCache { return false; } - static final class IconDB extends SQLiteCacheHelper { - private final static int RELEASE_VERSION = 26; - - public final static String TABLE_NAME = "icons"; - public final static String COLUMN_ROWID = "rowid"; - public final static String COLUMN_COMPONENT = "componentName"; - public final static String COLUMN_USER = "profileId"; - public final static String COLUMN_LAST_UPDATED = "lastUpdated"; - public final static String COLUMN_VERSION = "version"; - public final static String COLUMN_ICON = "icon"; - public final static String COLUMN_ICON_COLOR = "icon_color"; - public final static String COLUMN_LABEL = "label"; - public final static String COLUMN_SYSTEM_STATE = "system_state"; - - public final static String[] COLUMNS_HIGH_RES = new String[] { + /** + * Returns a cursor for an arbitrary query to the cache db + */ + public synchronized Cursor queryCacheDb(String[] columns, String selection, + String[] selectionArgs) { + return mIconDb.query(columns, selection, selectionArgs); + } + + /** + * Cache class to store the actual entries on disk + */ + public static final class IconDB extends SQLiteCacheHelper { + private static final int RELEASE_VERSION = 27; + + public static final String TABLE_NAME = "icons"; + public static final String COLUMN_ROWID = "rowid"; + public static final String COLUMN_COMPONENT = "componentName"; + public static final String COLUMN_USER = "profileId"; + public static final String COLUMN_LAST_UPDATED = "lastUpdated"; + public static final String COLUMN_VERSION = "version"; + public static final String COLUMN_ICON = "icon"; + public static final String COLUMN_ICON_COLOR = "icon_color"; + public static final String COLUMN_LABEL = "label"; + public static final String COLUMN_SYSTEM_STATE = "system_state"; + public static final String COLUMN_KEYWORDS = "keywords"; + + public static final String[] COLUMNS_HIGH_RES = new String[] { IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL, IconDB.COLUMN_ICON }; - public final static String[] COLUMNS_LOW_RES = new String[] { + public static final String[] COLUMNS_LOW_RES = new String[] { IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL }; public IconDB(Context context, String dbFileName, int iconPixelSize) { @@ -529,21 +544,23 @@ public abstract class BaseIconCache { @Override protected void onCreateTable(SQLiteDatabase db) { - db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + - COLUMN_COMPONENT + " TEXT NOT NULL, " + - COLUMN_USER + " INTEGER NOT NULL, " + - COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " + - COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " + - COLUMN_ICON + " BLOB, " + - COLUMN_ICON_COLOR + " INTEGER NOT NULL DEFAULT 0, " + - COLUMN_LABEL + " TEXT, " + - COLUMN_SYSTEM_STATE + " TEXT, " + - "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " + - ");"); + db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + + COLUMN_COMPONENT + " TEXT NOT NULL, " + + COLUMN_USER + " INTEGER NOT NULL, " + + COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_ICON + " BLOB, " + + COLUMN_ICON_COLOR + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_LABEL + " TEXT, " + + COLUMN_SYSTEM_STATE + " TEXT, " + + COLUMN_KEYWORDS + " TEXT, " + + "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " + + ");"); } } - private ContentValues newContentValues(BitmapInfo bitmapInfo, String label, String packageName) { + private ContentValues newContentValues(BitmapInfo bitmapInfo, String label, + String packageName, @Nullable String keywords) { ContentValues values = new ContentValues(); values.put(IconDB.COLUMN_ICON, bitmapInfo.isLowRes() ? null : GraphicsUtils.flattenBitmap(bitmapInfo.icon)); @@ -551,7 +568,7 @@ public abstract class BaseIconCache { values.put(IconDB.COLUMN_LABEL, label); values.put(IconDB.COLUMN_SYSTEM_STATE, getIconSystemState(packageName)); - + values.put(IconDB.COLUMN_KEYWORDS, keywords); return values; } diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java index addb51fa7..09f59b84c 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java @@ -17,8 +17,11 @@ package com.android.launcher3.icons.cache; import android.content.ComponentName; import android.content.Context; +import android.os.LocaleList; import android.os.UserHandle; +import androidx.annotation.Nullable; + import com.android.launcher3.icons.BitmapInfo; public interface CachingLogic<T> { @@ -30,4 +33,12 @@ public interface CachingLogic<T> { CharSequence getLabel(T object); void loadIcon(Context context, T object, BitmapInfo target); + + /** + * Provides a option list of keywords to associate with this object + */ + @Nullable + default String getKeywords(T object, LocaleList localeList) { + return null; + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java index 73f328bc1..90911684e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java @@ -75,7 +75,7 @@ public class OverviewToAllAppsTouchController extends PortraitStatesTouchControl } @Override - protected int getLogContainerTypeForNormalState() { + protected int getLogContainerTypeForNormalState(MotionEvent ev) { return LauncherLogProto.ContainerType.WORKSPACE; } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java index 18b8af4fa..eb571f607 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java @@ -154,7 +154,7 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll } @Override - protected int getLogContainerTypeForNormalState() { + protected int getLogContainerTypeForNormalState(MotionEvent ev) { return LauncherLogProto.ContainerType.NAVBAR; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java index 5e77e0ade..5ebefa337 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -81,6 +81,7 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> imple }); factory.onRemoteAnimationReceived(null); factory.createActivityController(RECENTS_LAUNCH_DURATION); + factory.setRecentsAttachedToAppWindow(true, false); mActivity = activity; mRecentsView = mActivity.getOverviewPanel(); return false; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java index 6533c63ef..a94f25d2b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java @@ -99,6 +99,7 @@ public class OverviewCommandHelper { @Override protected void onTransitionComplete() { + // TODO(b/138729100) This doesn't execute first time launcher is run if (mTriggeredFromAltTab) { RecentsView rv = (RecentsView) mHelper.getVisibleRecentsView(); if (rv == null) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java index b90f6c2b1..17457aace 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java @@ -16,6 +16,8 @@ package com.android.quickstep; +import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; + import android.graphics.Matrix; import android.view.View; @@ -47,8 +49,7 @@ public class TaskOverlayFactory implements ResourceBasedOverride { }; public static final MainThreadInitializedObject<TaskOverlayFactory> INSTANCE = - new MainThreadInitializedObject<>(c -> Overrides.getObject(TaskOverlayFactory.class, - c, R.string.task_overlay_factory_class)); + forOverride(TaskOverlayFactory.class, R.string.task_overlay_factory_class); public List<TaskSystemShortcut> getEnabledShortcuts(TaskView taskView) { final ArrayList<TaskSystemShortcut> shortcuts = new ArrayList<>(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 9b157d163..1bf77f53c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -97,6 +97,7 @@ import com.android.launcher3.graphics.RotationMode; 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; +import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.OverScroller; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.Themes; @@ -1051,9 +1052,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl if (task != null) { ActivityManagerWrapper.getInstance().removeTask(task.key.id); if (shouldLog) { + ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key); mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( - onEndListener.logAction, Direction.UP, index, - TaskUtils.getLaunchComponentKeyForTask(task.key)); + onEndListener.logAction, Direction.UP, index, componentKey); + mActivity.getStatsLogManager().logTaskDismiss(this, componentKey); } } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java b/quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java new file mode 100644 index 000000000..e42508814 --- /dev/null +++ b/quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 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.provider.DeviceConfig; +import com.android.launcher3.config.BaseFlags.BaseTogglableFlag; + +public class TogglableFlag extends BaseTogglableFlag { + + public TogglableFlag(String key, boolean defaultValue, String description) { + super(key, defaultValue, description); + } + + @Override + public boolean getInitialValue(boolean value) { + return DeviceConfig.getBoolean("launcher", getKey(), value); + } +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index 97cd38a11..c02df9386 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -32,9 +32,11 @@ import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.app.Activity; +import android.app.Person; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ShortcutInfo; import android.os.Bundle; import android.os.CancellationSignal; import android.util.Base64; @@ -244,4 +246,9 @@ public class UiFactory extends RecentsUiFactory { } return new ScaleAndTranslation(1.1f, 0f, 0f); } + + public static Person[] getPersons(ShortcutInfo si) { + Person[] persons = si.getPersons(); + return persons == null ? Utilities.EMPTY_PERSON_ARRAY : persons; + } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java index 0605953dc..bb72315d3 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java @@ -46,7 +46,7 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro } @Override - protected int getLogContainerTypeForNormalState() { + protected int getLogContainerTypeForNormalState(MotionEvent ev) { return LauncherLogProto.ContainerType.NAVBAR; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index a55f36b78..b81edfa4c 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -147,8 +147,8 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr } @Override - protected int getLogContainerTypeForNormalState() { - return ContainerType.HOTSEAT; + protected int getLogContainerTypeForNormalState(MotionEvent ev) { + return isTouchOverHotseat(mLauncher, ev) ? ContainerType.HOTSEAT : ContainerType.WORKSPACE; } private AnimatorSetBuilder getNormalToOverviewAnimation() { diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index 9f1248458..dfab43459 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -16,15 +16,12 @@ package com.android.quickstep; import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS; import android.annotation.TargetApi; import android.app.ActivityManager; import android.content.ComponentCallbacks2; import android.content.Context; import android.os.Build; -import android.os.Bundle; import android.os.HandlerThread; import android.os.Process; import android.os.RemoteException; @@ -35,7 +32,6 @@ import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.TaskStackChangeListener; import java.util.ArrayList; @@ -52,7 +48,7 @@ public class RecentsModel extends TaskStackChangeListener { // We do not need any synchronization for this variable as its only written on UI thread. public static final MainThreadInitializedObject<RecentsModel> INSTANCE = - new MainThreadInitializedObject<>(c -> new RecentsModel(c)); + new MainThreadInitializedObject<>(RecentsModel::new); private final List<TaskThumbnailChangeListener> mThumbnailChangeListeners = new ArrayList<>(); private final Context mContext; diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 2f411efc7..13a8dc26a 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -25,6 +25,7 @@ import static android.stats.launcher.nano.Launcher.ALLAPPS; import static android.stats.launcher.nano.Launcher.HOME; import static android.stats.launcher.nano.Launcher.LAUNCH_APP; import static android.stats.launcher.nano.Launcher.LAUNCH_TASK; +import static android.stats.launcher.nano.Launcher.DISMISS_TASK; import static android.stats.launcher.nano.Launcher.BACKGROUND; import static android.stats.launcher.nano.Launcher.OVERVIEW; @@ -74,6 +75,16 @@ public class StatsLogCompatManager extends StatsLogManager { MessageNano.toByteArray(ext), true); } + @Override + public void logTaskDismiss(View v, ComponentKey componentKey) { + LauncherExtension ext = new LauncherExtension(); + ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH]; + int srcState = OVERVIEW; + fillInLauncherExtension(v, ext); + StatsLogCompat.write(DISMISS_TASK, srcState, BACKGROUND /* dstState */, + MessageNano.toByteArray(ext), true); + } + public static boolean fillInLauncherExtension(View v, LauncherExtension extension) { StatsLogUtils.LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v); if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) { diff --git a/quickstep/tests/OWNERS b/quickstep/tests/OWNERS index 046d87116..02e8ebcab 100644 --- a/quickstep/tests/OWNERS +++ b/quickstep/tests/OWNERS @@ -1 +1,4 @@ vadimt@google.com +sunnygoyal@google.com +winsonc@google.com +hyunyoungs@google.com diff --git a/res/values/config.xml b/res/values/config.xml index 638a411be..038718473 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -72,6 +72,7 @@ <string name="system_shortcut_factory_class" translatable="false"></string> <string name="app_launch_tracker_class" translatable="false"></string> <string name="test_information_handler_class" translatable="false"></string> + <string name="launcher_activity_logic_class" translatable="false"></string> <!-- Package name of the default wallpaper picker. --> <string name="wallpaper_picker_package" translatable="false"></string> diff --git a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java index 92bcc6434..a3d121676 100644 --- a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java +++ b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java @@ -1,6 +1,8 @@ package com.android.launcher3.config; +import com.android.launcher3.config.BaseFlags.BaseTogglableFlag; +import com.android.launcher3.uioverrides.TogglableFlag; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; @@ -70,7 +72,7 @@ public final class FlagOverrideRule implements TestRule { }; } - private void override(BaseFlags.TogglableFlag flag, boolean newValue) { + private void override(BaseTogglableFlag flag, boolean newValue) { if (!ruleInProgress) { throw new IllegalStateException( "Rule isn't in progress. Did you remember to mark it with @Rule?"); @@ -93,7 +95,7 @@ public final class FlagOverrideRule implements TestRule { private void applyAnnotation(FlagOverride flagOverride) { boolean found = false; - for (BaseFlags.TogglableFlag flag : FeatureFlags.getTogglableFlags()) { + for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) { if (flag.getKey().equals(flagOverride.key())) { override(flag, flagOverride.value()); found = true; @@ -109,7 +111,7 @@ public final class FlagOverrideRule implements TestRule { * Resets all flags to their default values. */ private void clearOverrides() { - for (BaseFlags.TogglableFlag flag : FeatureFlags.getTogglableFlags()) { + for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) { flag.setForTests(flag.getDefaultValue()); } } diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java index e1ef9548c..0f006f7c1 100644 --- a/src/com/android/launcher3/IconProvider.java +++ b/src/com/android/launcher3/IconProvider.java @@ -1,16 +1,17 @@ package com.android.launcher3; -import android.content.Context; +import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; + import android.content.pm.LauncherActivityInfo; import android.graphics.drawable.Drawable; +import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.ResourceBasedOverride; public class IconProvider implements ResourceBasedOverride { - public static IconProvider newInstance(Context context) { - return Overrides.getObject(IconProvider.class, context, R.string.icon_provider_class); - } + public static MainThreadInitializedObject<IconProvider> INSTANCE = + forOverride(IconProvider.class, R.string.icon_provider_class); public IconProvider() { } diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java index 134e11606..3f723d17f 100644 --- a/src/com/android/launcher3/ItemInfo.java +++ b/src/com/android/launcher3/ItemInfo.java @@ -22,6 +22,8 @@ import android.content.Intent; import android.os.Process; import android.os.UserHandle; +import androidx.annotation.Nullable; + import com.android.launcher3.util.ContentWriter; /** @@ -134,6 +136,7 @@ public class ItemInfo { return null; } + @Nullable public ComponentName getTargetComponent() { Intent intent = getIntent(); if (intent != null) { diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 5b38261a4..d79230f8b 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -127,6 +127,7 @@ import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.PendingRequestArgs; import com.android.launcher3.util.RaceConditionTracker; +import com.android.launcher3.util.ShortcutUtil; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; import com.android.launcher3.util.Thunk; @@ -873,9 +874,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, if (mLauncherCallbacks != null) { mLauncherCallbacks.onStop(); } - - getUserEventDispatcher().logActionCommand(Action.Command.STOP, - mStateManager.getState().containerType, -1); + logStopAndResume(Action.Command.STOP); mAppWidgetHost.setListenIfResumed(false); @@ -901,8 +900,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, private void handleDeferredResume() { if (hasBeenResumed() && !mStateManager.getState().disableInteraction) { - getUserEventDispatcher().logActionCommand(Action.Command.RESUME, - mStateManager.getState().containerType, -1); + logStopAndResume(Action.Command.RESUME); getUserEventDispatcher().startSession(); UiFactory.onLauncherStateOrResumeChanged(this); @@ -929,6 +927,17 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, } } + private void logStopAndResume(int command) { + int containerType = mStateManager.getState().containerType; + if (containerType == ContainerType.WORKSPACE && mWorkspace != null) { + getUserEventDispatcher().logActionCommand(command, + containerType, -1, mWorkspace.isOverlayShown() ? -1 : 0); + } else { + getUserEventDispatcher().logActionCommand(command, containerType, -1); + } + + } + protected void onStateSet(LauncherState state) { getAppWidgetHost().setResumed(state == LauncherState.NORMAL); if (mDeferredResumePending) { @@ -2494,7 +2503,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, KeyEvent.KEYCODE_O, KeyEvent.META_CTRL_ON)); } if (currentFocus.getTag() instanceof ItemInfo - && DeepShortcutManager.supportsShortcuts((ItemInfo) currentFocus.getTag())) { + && ShortcutUtil.supportsShortcuts((ItemInfo) currentFocus.getTag())) { shortcutInfos.add(new KeyboardShortcutInfo( getString(R.string.shortcuts_menu_with_notifications_description), KeyEvent.KEYCODE_S, KeyEvent.META_CTRL_ON)); diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index d07638a5c..2a801d6ef 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -19,14 +19,12 @@ package com.android.launcher3; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS; import static com.android.launcher3.util.SecureSettingsObserver.newNotificationSettingsObserver; -import android.app.KeyguardManager; import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; -import android.os.Process; import android.util.Log; import com.android.launcher3.compat.LauncherAppsCompat; @@ -46,7 +44,7 @@ public class LauncherAppState { // We do not need any synchronization for this variable as its only written on UI thread. private static final MainThreadInitializedObject<LauncherAppState> INSTANCE = - new MainThreadInitializedObject<>((c) -> new LauncherAppState(c)); + new MainThreadInitializedObject<>(LauncherAppState::new); private final Context mContext; private final LauncherModel mModel; diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index d2b8d4e30..bbb3915b5 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1562,12 +1562,20 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou final boolean pagesFlipped = isPageOrderFlipped(); info.setScrollable(getPageCount() > 1); if (getCurrentPage() < getPageCount() - 1) { - info.addAction(pagesFlipped ? AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD - : AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + info.addAction(pagesFlipped ? + AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD + : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); + info.addAction(mIsRtl ? + AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT + : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT); } if (getCurrentPage() > 0) { - info.addAction(pagesFlipped ? AccessibilityNodeInfo.ACTION_SCROLL_FORWARD - : AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + info.addAction(pagesFlipped ? + AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD + : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); + info.addAction(mIsRtl ? + AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT + : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT); } // Accessibility-wise, PagedView doesn't support long click, so disabling it. @@ -1607,8 +1615,21 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou if (pagesFlipped ? scrollRight() : scrollLeft()) { return true; } + } break; + case android.R.id.accessibilityActionPageRight: { + if (!mIsRtl) { + return scrollRight(); + } else { + return scrollLeft(); + } + } + case android.R.id.accessibilityActionPageLeft: { + if (!mIsRtl) { + return scrollLeft(); + } else { + return scrollRight(); + } } - break; } return false; } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index fc5cd8a88..3bef5986d 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -21,6 +21,7 @@ import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.app.ActivityManager; +import android.app.Person; import android.app.WallpaperManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -109,6 +110,9 @@ public final class Utilities { private static final Matrix sMatrix = new Matrix(); private static final Matrix sInverseMatrix = new Matrix(); + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + public static final Person[] EMPTY_PERSON_ARRAY = new Person[0]; + public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; public static final boolean ATLEAST_P = diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 269a59111..3be91d410 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -85,6 +85,7 @@ import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.pageindicators.WorkspacePageIndicator; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.WorkspaceTouchListener; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -420,6 +421,9 @@ public class Workspace extends PagedView<WorkspacePageIndicator> } // Always enter the spring loaded mode + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "Switching to SPRING_LOADED"); + } mLauncher.getStateManager().goToState(SPRING_LOADED); } @@ -1741,6 +1745,9 @@ public class Workspace extends PagedView<WorkspacePageIndicator> public void prepareAccessibilityDrop() { } public void onDrop(final DragObject d, DragOptions options) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "Workspace.onDrop"); + } mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter); CellLayout dropTargetLayout = mDropToLayout; @@ -2418,6 +2425,9 @@ public class Workspace extends PagedView<WorkspacePageIndicator> * to add an item to one of the workspace screens. */ private void onDropExternal(final int[] touchXY, final CellLayout cellLayout, DragObject d) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "Workspace.onDropExternal"); + } if (d.dragInfo instanceof PendingAddShortcutInfo) { WorkspaceItemInfo si = ((PendingAddShortcutInfo) d.dragInfo) .activityInfo.createWorkspaceItemInfo(); @@ -3251,6 +3261,10 @@ public class Workspace extends PagedView<WorkspacePageIndicator> } } + public boolean isOverlayShown() { + return mOverlayShown; + } + void moveToDefaultScreen() { int page = DEFAULT_PAGE; if (!workspaceInModalState() && getNextPage() != page) { diff --git a/src/com/android/launcher3/WorkspaceItemInfo.java b/src/com/android/launcher3/WorkspaceItemInfo.java index 5a2373b99..b72866c26 100644 --- a/src/com/android/launcher3/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/WorkspaceItemInfo.java @@ -16,17 +16,23 @@ package com.android.launcher3; +import android.app.Person; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.text.TextUtils; +import androidx.annotation.NonNull; + import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.icons.IconCache; import com.android.launcher3.shortcuts.ShortcutKey; +import com.android.launcher3.uioverrides.UiFactory; import com.android.launcher3.util.ContentWriter; +import java.util.Arrays; + /** * Represents a launchable icon on the workspaces and in folders. */ @@ -83,10 +89,17 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { public int status; /** + * A set of person's Id associated with the WorkspaceItemInfo, this is only used if the item + * represents a deep shortcut. + */ + @NonNull private String[] personKeys = Utilities.EMPTY_STRING_ARRAY; + + /** * The installation progress [0-100] of the package that this shortcut represents. */ private int mInstallProgress; + public WorkspaceItemInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; } @@ -98,6 +111,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { iconResource = info.iconResource; status = info.status; mInstallProgress = info.mInstallProgress; + personKeys = info.personKeys.clone(); } /** TODO: Remove this. It's only called by ApplicationInfo.makeWorkspaceItem. */ @@ -175,6 +189,10 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { runtimeStatusFlags |= FLAG_DISABLED_BY_PUBLISHER; } disabledMessage = shortcutInfo.getDisabledMessage(); + + Person[] persons = UiFactory.getPersons(shortcutInfo); + personKeys = persons.length == 0 ? Utilities.EMPTY_STRING_ARRAY + : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new); } /** Returns the WorkspaceItemInfo id associated with the deep shortcut. */ @@ -183,6 +201,11 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { getIntent().getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID) : null; } + @NonNull + public String[] getPersonKeys() { + return personKeys; + } + @Override public ComponentName getTargetComponent() { ComponentName cn = super.getTargetComponent(); diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index fd4df5247..0c1303b64 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -40,6 +40,7 @@ import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.util.IntArray; +import com.android.launcher3.util.ShortcutUtil; import com.android.launcher3.util.Thunk; import com.android.launcher3.widget.LauncherAppWidgetHostView; @@ -115,7 +116,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme // If the request came from keyboard, do not add custom shortcuts as that is already // exposed as a direct shortcut - if (!fromKeyboard && DeepShortcutManager.supportsShortcuts(item)) { + if (!fromKeyboard && ShortcutUtil.supportsShortcuts(item)) { info.addAction(mActions.get(NotificationListener.getInstanceIfConnected() != null ? SHORTCUTS_AND_NOTIFICATIONS : DEEP_SHORTCUTS)); } diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index 54efcb786..23edcd25f 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -18,20 +18,16 @@ package com.android.launcher3.config; import static androidx.core.util.Preconditions.checkNotNull; -import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; -import android.database.ContentObserver; -import android.os.Handler; -import android.os.Looper; -import android.provider.Settings; import androidx.annotation.GuardedBy; import androidx.annotation.Keep; -import androidx.annotation.VisibleForTesting; +import androidx.annotation.VisibleForTesting; import com.android.launcher3.Utilities; +import com.android.launcher3.uioverrides.TogglableFlag; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; @@ -41,11 +37,9 @@ import java.util.TreeMap; * Defines a set of flags used to control various launcher behaviors. * * <p>All the flags should be defined here with appropriate default values. - * - * <p>This class is kept package-private to prevent direct access. */ @Keep -abstract class BaseFlags { +public abstract class BaseFlags { private static final Object sLock = new Object(); @GuardedBy("sLock") @@ -112,11 +106,15 @@ abstract class BaseFlags { "FAKE_LANDSCAPE_UI", false, "Rotate launcher UI instead of using transposed layout"); + public static final TogglableFlag APP_SEARCH_IMPROVEMENTS = new TogglableFlag( + "APP_SEARCH_IMPROVEMENTS", false, + "Adds localized title and keyword search and ranking"); + public static void initialize(Context context) { // Avoid the disk read for user builds if (Utilities.IS_DEBUG_DEVICE) { synchronized (sLock) { - for (TogglableFlag flag : sFlags) { + for (BaseTogglableFlag flag : sFlags) { flag.initialize(context); } } @@ -132,27 +130,27 @@ abstract class BaseFlags { SortedMap<String, TogglableFlag> flagsByKey = new TreeMap<>(); synchronized (sLock) { for (TogglableFlag flag : sFlags) { - flagsByKey.put(flag.key, flag); + flagsByKey.put(((BaseTogglableFlag) flag).getKey(), flag); } } return new ArrayList<>(flagsByKey.values()); } - public static class TogglableFlag { + public static abstract class BaseTogglableFlag { private final String key; private final boolean defaultValue; private final String description; private boolean currentValue; - TogglableFlag( + public BaseTogglableFlag( String key, boolean defaultValue, String description) { this.key = checkNotNull(key); - this.currentValue = this.defaultValue = defaultValue; + this.currentValue = this.defaultValue = getInitialValue(defaultValue); this.description = checkNotNull(description); synchronized (sLock) { - sFlags.add(this); + sFlags.add((TogglableFlag)this); } } @@ -162,14 +160,16 @@ abstract class BaseFlags { currentValue = value; } - @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public String getKey() { return key; } + void initialize(Context context) { currentValue = getFromStorage(context, defaultValue); } + protected abstract boolean getInitialValue(boolean value); + public void updateStorage(Context context, boolean value) { SharedPreferences.Editor editor = context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE).edit(); @@ -213,7 +213,7 @@ abstract class BaseFlags { return true; } if (o instanceof TogglableFlag) { - TogglableFlag that = (TogglableFlag) o; + BaseTogglableFlag that = (BaseTogglableFlag) o; return (this.key.equals(that.getKey())) && (this.defaultValue == that.getDefaultValue()) && (this.description.equals(that.getDescription())); @@ -233,48 +233,4 @@ abstract class BaseFlags { return h$; } } - - /** - * Stores the FeatureFlag's value in Settings.Global instead of our SharedPrefs. - * This is useful if we want to be able to control this flag from another process. - */ - public static final class ToggleableGlobalSettingsFlag extends TogglableFlag { - private ContentResolver contentResolver; - - ToggleableGlobalSettingsFlag(String key, boolean defaultValue, String description) { - super(key, defaultValue, description); - } - - @Override - public void initialize(Context context) { - contentResolver = context.getContentResolver(); - contentResolver.registerContentObserver(Settings.Global.getUriFor(getKey()), true, - new ContentObserver(new Handler(Looper.getMainLooper())) { - @Override - public void onChange(boolean selfChange) { - superInitialize(context); - }}); - superInitialize(context); - } - - private void superInitialize(Context context) { - super.initialize(context); - } - - @Override - public void updateStorage(Context context, boolean value) { - if (contentResolver == null) { - return; - } - Settings.Global.putInt(contentResolver, getKey(), value ? 1 : 0); - } - - @Override - boolean getFromStorage(Context context, boolean defaultValue) { - if (contentResolver == null) { - return defaultValue; - } - return Settings.Global.getInt(contentResolver, getKey(), defaultValue ? 1 : 0) == 1; - } - } } diff --git a/src/com/android/launcher3/config/FlagTogglerPrefUi.java b/src/com/android/launcher3/config/FlagTogglerPrefUi.java index 5ecb18650..54e5322bd 100644 --- a/src/com/android/launcher3/config/FlagTogglerPrefUi.java +++ b/src/com/android/launcher3/config/FlagTogglerPrefUi.java @@ -26,12 +26,13 @@ import android.view.MenuItem; import android.widget.Toast; import com.android.launcher3.R; -import com.android.launcher3.config.BaseFlags.TogglableFlag; import androidx.preference.PreferenceDataStore; import androidx.preference.PreferenceFragment; import androidx.preference.PreferenceGroup; import androidx.preference.SwitchPreference; +import com.android.launcher3.config.BaseFlags.BaseTogglableFlag; +import com.android.launcher3.uioverrides.TogglableFlag; /** * Dev-build only UI allowing developers to toggle flag settings. See {@link FeatureFlags}. @@ -62,7 +63,7 @@ public final class FlagTogglerPrefUi { @Override public boolean getBoolean(String key, boolean defaultValue) { - for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) { + for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) { if (flag.getKey().equals(key)) { return flag.getFromStorage(mContext, defaultValue); } @@ -83,7 +84,7 @@ public final class FlagTogglerPrefUi { // flag with a different value than the default. That way, when we flip flags in // future, engineers will pick up the new value immediately. To accomplish this, we use a // custom preference data store. - for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) { + for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) { SwitchPreference switchPreference = new SwitchPreference(mContext); switchPreference.setKey(flag.getKey()); switchPreference.setDefaultValue(flag.getDefaultValue()); @@ -99,7 +100,7 @@ public final class FlagTogglerPrefUi { /** * Updates the summary to show the description and whether the flag overrides the default value. */ - private void updateSummary(SwitchPreference switchPreference, TogglableFlag flag) { + private void updateSummary(SwitchPreference switchPreference, BaseTogglableFlag flag) { String onWarning = flag.getDefaultValue() ? "" : "<b>OVERRIDDEN</b><br>"; String offWarning = flag.getDefaultValue() ? "<b>OVERRIDDEN</b><br>" : ""; switchPreference.setSummaryOn(Html.fromHtml(onWarning + flag.getDescription())); @@ -134,7 +135,7 @@ public final class FlagTogglerPrefUi { } } - private boolean getFlagStateFromSharedPrefs(TogglableFlag flag) { + private boolean getFlagStateFromSharedPrefs(BaseTogglableFlag flag) { return mDataStore.getBoolean(flag.getKey(), flag.getDefaultValue()); } diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index d32dd2eb9..b72fd988a 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -579,6 +579,9 @@ public class DragController implements DragDriver.EventListener, TouchController } private void drop(DropTarget dropTarget, Runnable flingAnimation) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "DragController.drop"); + } final int[] coordinates = mCoordinatesTemp; mDragObject.x = coordinates[0]; mDragObject.y = coordinates[1]; diff --git a/src/com/android/launcher3/dragndrop/DragDriver.java b/src/com/android/launcher3/dragndrop/DragDriver.java index 84fc94dd2..bd2a03b6c 100644 --- a/src/com/android/launcher3/dragndrop/DragDriver.java +++ b/src/com/android/launcher3/dragndrop/DragDriver.java @@ -17,10 +17,12 @@ package com.android.launcher3.dragndrop; import android.content.Context; +import android.util.Log; import android.view.DragEvent; import android.view.MotionEvent; import com.android.launcher3.DropTarget.DragObject; +import com.android.launcher3.testing.TestProtocol; /** * Base class for driving a drag/drop operation. @@ -52,6 +54,9 @@ public abstract class DragDriver { mEventListener.onDriverDragMove(ev.getX(), ev.getY()); break; case MotionEvent.ACTION_UP: + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "DragDriver.ACTION_UP"); + } mEventListener.onDriverDragMove(ev.getX(), ev.getY()); mEventListener.onDriverDragEnd(ev.getX(), ev.getY()); break; diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java index c9566cb14..288749fa7 100644 --- a/src/com/android/launcher3/graphics/DrawableFactory.java +++ b/src/com/android/launcher3/graphics/DrawableFactory.java @@ -17,6 +17,7 @@ package com.android.launcher3.graphics; import static com.android.launcher3.graphics.IconShape.getShapePath; +import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; import android.content.Context; import android.content.pm.ActivityInfo; @@ -31,6 +32,8 @@ import android.os.Process; import android.os.UserHandle; import android.util.ArrayMap; +import androidx.annotation.UiThread; + import com.android.launcher3.FastBitmapDrawable; import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.R; @@ -38,16 +41,13 @@ import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.ResourceBasedOverride; -import androidx.annotation.UiThread; - /** * Factory for creating new drawables. */ public class DrawableFactory implements ResourceBasedOverride { public static final MainThreadInitializedObject<DrawableFactory> INSTANCE = - new MainThreadInitializedObject<>(c -> Overrides.getObject(DrawableFactory.class, - c.getApplicationContext(), R.string.drawable_factory_class)); + forOverride(DrawableFactory.class, R.string.drawable_factory_class); protected final UserHandle mMyUser = Process.myUserHandle(); protected final ArrayMap<UserHandle, Bitmap> mUserBadges = new ArrayMap<>(); diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 648445e40..55d58b9c0 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -29,6 +29,8 @@ import android.os.Process; import android.os.UserHandle; import android.util.Log; +import androidx.annotation.NonNull; + import com.android.launcher3.AppInfo; import com.android.launcher3.IconProvider; import com.android.launcher3.InvariantDeviceProfile; @@ -36,8 +38,8 @@ import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.LauncherFiles; import com.android.launcher3.LauncherModel; import com.android.launcher3.MainThreadExecutor; -import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.Utilities; +import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; @@ -50,8 +52,6 @@ import com.android.launcher3.util.Preconditions; import java.util.function.Supplier; -import androidx.annotation.NonNull; - /** * Cache of application icons. Icons can be made from any thread. */ @@ -75,11 +75,11 @@ public class IconCache extends BaseIconCache { super(context, LauncherFiles.APP_ICONS_DB, LauncherModel.getWorkerLooper(), inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */); mComponentWithLabelCachingLogic = new ComponentCachingLogic(context); - mLauncherActivityInfoCachingLogic = new LauncherActivtiyCachingLogic(this); + mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context); mLauncherApps = LauncherAppsCompat.getInstance(mContext); mUserManager = UserManagerCompat.getInstance(mContext); mInstantAppResolver = InstantAppResolver.newInstance(mContext); - mIconProvider = IconProvider.newInstance(context); + mIconProvider = IconProvider.INSTANCE.get(context); } @Override diff --git a/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java index 7c996339b..f9a94daf5 100644 --- a/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java +++ b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java @@ -20,14 +20,23 @@ import android.content.Context; import android.content.pm.LauncherActivityInfo; import android.os.UserHandle; +import com.android.launcher3.IconProvider; +import com.android.launcher3.R; import com.android.launcher3.icons.cache.CachingLogic; +import com.android.launcher3.util.ResourceBasedOverride; -public class LauncherActivtiyCachingLogic implements CachingLogic<LauncherActivityInfo> { - - private final IconCache mCache; +/** + * Caching logic for LauncherActivityInfo. + */ +public class LauncherActivityCachingLogic + implements CachingLogic<LauncherActivityInfo>, ResourceBasedOverride { - public LauncherActivtiyCachingLogic(IconCache cache) { - mCache = cache; + /** + * Creates and returns a new instance + */ + public static LauncherActivityCachingLogic newInstance(Context context) { + return Overrides.getObject(LauncherActivityCachingLogic.class, context, + R.string.launcher_activity_logic_class); } @Override @@ -49,8 +58,10 @@ public class LauncherActivtiyCachingLogic implements CachingLogic<LauncherActivi public void loadIcon(Context context, LauncherActivityInfo object, BitmapInfo target) { LauncherIcons li = LauncherIcons.obtain(context); - li.createBadgedIconBitmap(mCache.getFullResIcon(object), + li.createBadgedIconBitmap( + IconProvider.INSTANCE.get(context) + .getIcon(object, li.mFillResIconDpi, true /* flattenDrawable */), object.getUser(), object.getApplicationInfo().targetSdkVersion).applyTo(target); li.recycle(); } -}
\ No newline at end of file +} diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 9b9543ec3..d11d434df 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -40,5 +40,6 @@ public class StatsLogManager implements ResourceBasedOverride { public void logAppLaunch(View v, Intent intent) { } public void logTaskLaunch(View v, ComponentKey key) { } + public void logTaskDismiss(View v, ComponentKey key) { } public void verify() {} // TODO: should move into robo tests } diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java index d81020ef3..c72b07a7f 100644 --- a/src/com/android/launcher3/logging/UserEventDispatcher.java +++ b/src/com/android/launcher3/logging/UserEventDispatcher.java @@ -187,6 +187,14 @@ public class UserEventDispatcher implements ResourceBasedOverride { dstContainerType >=0 ? newContainerTarget(dstContainerType) : null); } + public void logActionCommand(int command, int srcContainerType, int dstContainerType, + int pageIndex) { + Target srcTarget = newContainerTarget(srcContainerType); + srcTarget.pageIndex = pageIndex; + logActionCommand(command, srcTarget, + dstContainerType >=0 ? newContainerTarget(dstContainerType) : null); + } + public void logActionCommand(int command, Target srcTarget, Target dstTarget) { LauncherEvent event = newLauncherEvent(newCommandAction(command), srcTarget); if (command == Action.Command.STOP) { diff --git a/src/com/android/launcher3/model/AppLaunchTracker.java b/src/com/android/launcher3/model/AppLaunchTracker.java index 1613d47b9..29a46cfa5 100644 --- a/src/com/android/launcher3/model/AppLaunchTracker.java +++ b/src/com/android/launcher3/model/AppLaunchTracker.java @@ -15,18 +15,18 @@ */ package com.android.launcher3.model; -import static com.android.launcher3.util.ResourceBasedOverride.Overrides.getObject; +import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; import android.content.ComponentName; import android.os.UserHandle; +import androidx.annotation.Nullable; + import com.android.launcher3.R; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.ResourceBasedOverride; -import androidx.annotation.Nullable; - /** * Callback for receiving various app launch events */ @@ -43,8 +43,7 @@ public class AppLaunchTracker implements ResourceBasedOverride { public static final MainThreadInitializedObject<AppLaunchTracker> INSTANCE = - new MainThreadInitializedObject<>(c -> - getObject(AppLaunchTracker.class, c, R.string.app_launch_tracker_class)); + forOverride(AppLaunchTracker.class, R.string.app_launch_tracker_class); public void onStartShortcut(String packageName, String shortcutId, UserHandle user, @Nullable String container) { } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 0138572d0..4b01b5ed1 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -49,8 +49,8 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.Utilities; +import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.PackageInstallerCompat; @@ -61,7 +61,7 @@ import com.android.launcher3.folder.FolderIconPreviewVerifier; import com.android.launcher3.icons.ComponentWithLabel; import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; import com.android.launcher3.icons.IconCache; -import com.android.launcher3.icons.LauncherActivtiyCachingLogic; +import com.android.launcher3.icons.LauncherActivityCachingLogic; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.icons.cache.IconCacheUpdateHandler; import com.android.launcher3.logging.FileLog; @@ -196,7 +196,7 @@ public class LoaderTask implements Runnable { IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler(); setIgnorePackages(updateHandler); updateHandler.updateIcons(allActivityList, - new LauncherActivtiyCachingLogic(mApp.getIconCache()), + LauncherActivityCachingLogic.newInstance(mApp.getContext()), mApp.getModel()::onPackageIconsUpdated); // Take a break diff --git a/src/com/android/launcher3/notification/NotificationKeyData.java b/src/com/android/launcher3/notification/NotificationKeyData.java index 5050457b9..bfa4ba9ab 100644 --- a/src/com/android/launcher3/notification/NotificationKeyData.java +++ b/src/com/android/launcher3/notification/NotificationKeyData.java @@ -17,12 +17,18 @@ package com.android.launcher3.notification; import android.app.Notification; +import android.app.Person; import android.service.notification.StatusBarNotification; +import com.android.launcher3.Utilities; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * The key data associated with the notification, used to determine what to include @@ -34,19 +40,25 @@ public class NotificationKeyData { public final String notificationKey; public final String shortcutId; public int count; + @NonNull public final String[] personKeysFromNotification; - private NotificationKeyData(String notificationKey, String shortcutId, int count) { + private NotificationKeyData(String notificationKey, String shortcutId, int count, + String[] personKeysFromNotification) { this.notificationKey = notificationKey; this.shortcutId = shortcutId; this.count = Math.max(1, count); + this.personKeysFromNotification = personKeysFromNotification; } public static NotificationKeyData fromNotification(StatusBarNotification sbn) { Notification notif = sbn.getNotification(); - return new NotificationKeyData(sbn.getKey(), notif.getShortcutId(), notif.number); + return new NotificationKeyData(sbn.getKey(), notif.getShortcutId(), notif.number, + extractPersonKeyOnly(notif.extras.getParcelableArrayList( + Notification.EXTRA_PEOPLE_LIST))); } - public static List<String> extractKeysOnly(@NonNull List<NotificationKeyData> notificationKeys) { + public static List<String> extractKeysOnly( + @NonNull List<NotificationKeyData> notificationKeys) { List<String> keysOnly = new ArrayList<>(notificationKeys.size()); for (NotificationKeyData notificationKeyData : notificationKeys) { keysOnly.add(notificationKeyData.notificationKey); @@ -54,6 +66,13 @@ public class NotificationKeyData { return keysOnly; } + private static String[] extractPersonKeyOnly(@Nullable ArrayList<Person> people) { + if (people == null || people.isEmpty()) { + return Utilities.EMPTY_STRING_ARRAY; + } + return people.stream().map(Person::getKey).sorted().toArray(String[]::new); + } + @Override public boolean equals(Object obj) { if (!(obj instanceof NotificationKeyData)) { diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 25d9f7976..baaad6573 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -72,6 +72,7 @@ import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.util.PackageUserKey; +import com.android.launcher3.util.ShortcutUtil; import com.android.launcher3.views.BaseDragLayer; import java.util.ArrayList; @@ -201,7 +202,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, return null; } ItemInfo itemInfo = (ItemInfo) icon.getTag(); - if (!DeepShortcutManager.supportsShortcuts(itemInfo)) { + if (!ShortcutUtil.supportsShortcuts(itemInfo)) { return null; } diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java index 2d301ac00..4612b2a47 100644 --- a/src/com/android/launcher3/popup/PopupDataProvider.java +++ b/src/com/android/launcher3/popup/PopupDataProvider.java @@ -29,17 +29,22 @@ import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; +import com.android.launcher3.util.ShortcutUtil; import com.android.launcher3.widget.WidgetListRowEntry; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Collectors; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * Provides data for the popup menu that appears after long-clicking on apps. @@ -129,7 +134,8 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan for (PackageUserKey packageUserKey : mPackageUserToDotInfos.keySet()) { DotInfo prevDot = updatedDots.get(packageUserKey); DotInfo newDot = mPackageUserToDotInfos.get(packageUserKey); - if (prevDot == null) { + if (prevDot == null + || prevDot.getNotificationCount() != newDot.getNotificationCount()) { updatedDots.put(packageUserKey, newDot); } else { // No need to update the dot if it already existed (no visual change). @@ -155,7 +161,7 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan } public int getShortcutCountForItem(ItemInfo info) { - if (!DeepShortcutManager.supportsShortcuts(info)) { + if (!ShortcutUtil.supportsDeepShortcuts(info)) { return 0; } ComponentName component = info.getTargetComponent(); @@ -167,17 +173,26 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan return count == null ? 0 : count; } - public DotInfo getDotInfoForItem(ItemInfo info) { - if (!DeepShortcutManager.supportsShortcuts(info)) { + public @Nullable DotInfo getDotInfoForItem(@NonNull ItemInfo info) { + if (!ShortcutUtil.supportsShortcuts(info)) { return null; } - - return mPackageUserToDotInfos.get(PackageUserKey.fromItemInfo(info)); + DotInfo dotInfo = mPackageUserToDotInfos.get(PackageUserKey.fromItemInfo(info)); + if (dotInfo == null) { + return null; + } + List<NotificationKeyData> notifications = getNotificationsForItem( + info, dotInfo.getNotificationKeys()); + if (notifications.isEmpty()) { + return null; + } + return dotInfo; } public @NonNull List<NotificationKeyData> getNotificationKeysForItem(ItemInfo info) { DotInfo dotInfo = getDotInfoForItem(info); - return dotInfo == null ? Collections.EMPTY_LIST : dotInfo.getNotificationKeys(); + return dotInfo == null ? Collections.EMPTY_LIST + : getNotificationsForItem(info, dotInfo.getNotificationKeys()); } /** This makes a potentially expensive binder call and should be run on a background thread. */ @@ -226,6 +241,27 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan return null; } + /** + * Returns a list of notifications that are relevant to given ItemInfo. + */ + public static @NonNull List<NotificationKeyData> getNotificationsForItem( + @NonNull ItemInfo info, @NonNull List<NotificationKeyData> notifications) { + String shortcutId = ShortcutUtil.getShortcutIdIfPinnedShortcut(info); + if (shortcutId == null) { + return notifications; + } + String[] personKeys = ShortcutUtil.getPersonKeysIfPinnedShortcut(info); + return notifications.stream().filter((NotificationKeyData notification) -> { + if (notification.shortcutId != null) { + return notification.shortcutId.equals(shortcutId); + } + if (notification.personKeysFromNotification.length != 0) { + return Arrays.equals(notification.personKeysFromNotification, personKeys); + } + return false; + }).collect(Collectors.toList()); + } + public interface PopupDataChangeListener { PopupDataChangeListener INSTANCE = new PopupDataChangeListener() { }; diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java index 41ab4df7b..5a5fbabac 100644 --- a/src/com/android/launcher3/popup/RemoteActionShortcut.java +++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java @@ -29,11 +29,12 @@ import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.ItemInfo; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.userevent.nano.LauncherLogProto; public class RemoteActionShortcut extends SystemShortcut<BaseDraggingActivity> { private static final String TAG = "RemoteActionShortcut"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = Utilities.IS_DEBUG_DEVICE; private final RemoteAction mAction; diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 563f3b3c6..78bd81b46 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -131,6 +131,7 @@ public abstract class SystemShortcut<T extends BaseDraggingActivity> extends Ite @Override public View.OnClickListener getOnClickListener(final Launcher launcher, final ItemInfo itemInfo) { + if (itemInfo.getTargetComponent() == null) return null; final List<WidgetItem> widgets = launcher.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey( itemInfo.getTargetComponent().getPackageName(), itemInfo.user)); diff --git a/src/com/android/launcher3/popup/SystemShortcutFactory.java b/src/com/android/launcher3/popup/SystemShortcutFactory.java index 516fafad5..37a209289 100644 --- a/src/com/android/launcher3/popup/SystemShortcutFactory.java +++ b/src/com/android/launcher3/popup/SystemShortcutFactory.java @@ -15,6 +15,10 @@ */ package com.android.launcher3.popup; +import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; + +import androidx.annotation.NonNull; + import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.R; @@ -24,13 +28,10 @@ import com.android.launcher3.util.ResourceBasedOverride; import java.util.ArrayList; import java.util.List; -import androidx.annotation.NonNull; - public class SystemShortcutFactory implements ResourceBasedOverride { public static final MainThreadInitializedObject<SystemShortcutFactory> INSTANCE = - new MainThreadInitializedObject<>(c -> Overrides.getObject( - SystemShortcutFactory.class, c, R.string.system_shortcut_factory_class)); + forOverride(SystemShortcutFactory.class, R.string.system_shortcut_factory_class); /** Note that these are in order of priority. */ private final SystemShortcut[] mAllShortcuts; diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index bab454f07..4fd0f884d 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -112,6 +112,13 @@ public class TestInformationHandler implements ResourceBasedOverride { } break; } + + case TestProtocol.REQUEST_ALLOCATED_MEMORY: { + final Runtime runtime = Runtime.getRuntime(); + response.putLong(TestProtocol.TEST_INFO_RESPONSE_FIELD, + runtime.totalMemory() - runtime.freeMemory()); + break; + } } return response; } diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index 9846a0427..f9f5dc42a 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -73,10 +73,12 @@ public final class TestProtocol { public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags"; public static final String REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN = "overview-left-margin"; public static final String REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN = "overview-right-margin"; + public static final String REQUEST_ALLOCATED_MEMORY = "allocated-memory"; public static boolean sDebugTracing = false; public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing"; public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing"; public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824"; + public static final String NO_DRAG_TO_WORKSPACE = "b/138729456"; } diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 054534417..c5ba5bab6 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -69,6 +69,7 @@ public abstract class AbstractStateChangeTouchController protected final SwipeDetector.Direction mSwipeDirection; private boolean mNoIntercept; + private boolean mIsLogContainerSet; protected int mStartContainerType; protected LauncherState mStartState; @@ -180,7 +181,7 @@ public abstract class AbstractStateChangeTouchController /** * Returns the container that the touch started from when leaving NORMAL state. */ - protected abstract int getLogContainerTypeForNormalState(); + protected abstract int getLogContainerTypeForNormalState(MotionEvent ev); private boolean reinitCurrentAnimation(boolean reachedToState, boolean isDragTowardPositive) { LauncherState newFromState = mFromState == null ? mLauncher.getStateManager().getState() @@ -231,13 +232,7 @@ public abstract class AbstractStateChangeTouchController @Override public void onDragStart(boolean start) { mStartState = mLauncher.getStateManager().getState(); - if (mStartState == ALL_APPS) { - mStartContainerType = LauncherLogProto.ContainerType.ALLAPPS; - } else if (mStartState == NORMAL) { - mStartContainerType = getLogContainerTypeForNormalState(); - } else if (mStartState == OVERVIEW){ - mStartContainerType = LauncherLogProto.ContainerType.TASKSWITCHER; - } + mIsLogContainerSet = false; if (mCurrentAnimation == null) { mFromState = mStartState; mToState = null; @@ -285,6 +280,21 @@ public abstract class AbstractStateChangeTouchController return true; } + @Override + public boolean onDrag(float displacement, MotionEvent ev) { + if (!mIsLogContainerSet) { + if (mStartState == ALL_APPS) { + mStartContainerType = LauncherLogProto.ContainerType.ALLAPPS; + } else if (mStartState == NORMAL) { + mStartContainerType = getLogContainerTypeForNormalState(ev); + } else if (mStartState == OVERVIEW) { + mStartContainerType = LauncherLogProto.ContainerType.TASKSWITCHER; + } + mIsLogContainerSet = true; + } + return onDrag(displacement); + } + protected void updateProgress(float fraction) { mCurrentAnimation.setPlayFraction(fraction); if (mAtomicComponentsController != null) { diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java index 2ee032859..e185a3199 100644 --- a/src/com/android/launcher3/util/MainThreadInitializedObject.java +++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java @@ -18,12 +18,13 @@ package com.android.launcher3.util; import android.content.Context; import android.os.Looper; +import androidx.annotation.VisibleForTesting; + import com.android.launcher3.MainThreadExecutor; +import com.android.launcher3.util.ResourceBasedOverride.Overrides; import java.util.concurrent.ExecutionException; -import androidx.annotation.VisibleForTesting; - /** * Utility class for defining singletons which are initiated on main thread. */ @@ -60,6 +61,14 @@ public class MainThreadInitializedObject<T> { mValue = value; } + /** + * Initializes a provider based on resource overrides + */ + public static <T extends ResourceBasedOverride> MainThreadInitializedObject<T> forOverride( + Class<T> clazz, int resourceId) { + return new MainThreadInitializedObject<>(c -> Overrides.getObject(clazz, c, resourceId)); + } + public interface ObjectProvider<T> { T get(Context context); diff --git a/src/com/android/launcher3/util/PackageUserKey.java b/src/com/android/launcher3/util/PackageUserKey.java index 1ce282210..8dc45f547 100644 --- a/src/com/android/launcher3/util/PackageUserKey.java +++ b/src/com/android/launcher3/util/PackageUserKey.java @@ -3,6 +3,8 @@ package com.android.launcher3.util; import android.os.UserHandle; import android.service.notification.StatusBarNotification; +import androidx.annotation.Nullable; + import com.android.launcher3.ItemInfo; import com.android.launcher3.shortcuts.DeepShortcutManager; @@ -15,7 +17,9 @@ public class PackageUserKey { public UserHandle mUser; private int mHashCode; + @Nullable public static PackageUserKey fromItemInfo(ItemInfo info) { + if (info.getTargetComponent() == null) return null; return new PackageUserKey(info.getTargetComponent().getPackageName(), info.user); } @@ -38,7 +42,8 @@ public class PackageUserKey { * @return Whether this PackageUserKey was successfully updated - it shouldn't be used if not. */ public boolean updateFromItemInfo(ItemInfo info) { - if (DeepShortcutManager.supportsShortcuts(info)) { + if (info.getTargetComponent() == null) return false; + if (ShortcutUtil.supportsShortcuts(info)) { update(info.getTargetComponent().getPackageName(), info.user); return true; } diff --git a/src/com/android/launcher3/util/ShortcutUtil.java b/src/com/android/launcher3/util/ShortcutUtil.java new file mode 100644 index 000000000..792d69fc3 --- /dev/null +++ b/src/com/android/launcher3/util/ShortcutUtil.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 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.util; + +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.Utilities; +import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.shortcuts.ShortcutKey; + +public class ShortcutUtil { + public static boolean supportsShortcuts(ItemInfo info) { + return isActive(info) && (isApp(info) || isPinnedShortcut(info)); + } + + public static boolean supportsDeepShortcuts(ItemInfo info) { + return isActive(info) && isApp(info); + } + + public static String getShortcutIdIfPinnedShortcut(ItemInfo info) { + return isActive(info) && isPinnedShortcut(info) ? + ShortcutKey.fromItemInfo(info).getId() : null; + } + + public static String[] getPersonKeysIfPinnedShortcut(ItemInfo info) { + return isActive(info) && isPinnedShortcut(info) ? + ((WorkspaceItemInfo) info).getPersonKeys() : Utilities.EMPTY_STRING_ARRAY; + } + + private static boolean isActive(ItemInfo info) { + boolean isLoading = info instanceof WorkspaceItemInfo + && ((WorkspaceItemInfo) info).hasPromiseIconUi(); + return !isLoading && !info.isDisabled() && !FeatureFlags.GO_DISABLE_WIDGETS; + } + + private static boolean isApp(ItemInfo info) { + return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; + } + + private static boolean isPinnedShortcut(ItemInfo info) { + return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT + && info.container != ItemInfo.NO_ID + && info instanceof WorkspaceItemInfo; + } +}
\ No newline at end of file diff --git a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java index 6b6f70d7b..09b189049 100644 --- a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java +++ b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java @@ -27,9 +27,7 @@ import android.os.Bundle; import android.os.UserHandle; import android.util.Log; -import com.android.launcher3.ItemInfo; -import com.android.launcher3.LauncherSettings; -import com.android.launcher3.WorkspaceItemInfo; +import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -63,13 +61,6 @@ public class DeepShortcutManager { mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); } - public static boolean supportsShortcuts(ItemInfo info) { - boolean isItemPromise = info instanceof WorkspaceItemInfo - && ((WorkspaceItemInfo) info).hasPromiseIconUi(); - return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION - && !info.isDisabled() && !isItemPromise; - } - public boolean wasLastCallSuccess() { return mWasLastCallSuccess; } @@ -89,8 +80,9 @@ public class DeepShortcutManager { * Gets all the manifest and dynamic shortcuts associated with the given package and user, * to be displayed in the shortcuts container on long press. */ - public List<ShortcutInfo> queryForShortcutsContainer(ComponentName activity, + public List<ShortcutInfo> queryForShortcutsContainer(@Nullable ComponentName activity, UserHandle user) { + if (activity == null) return Collections.EMPTY_LIST; return query(ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_DYNAMIC, activity.getPackageName(), activity, null, user); } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java index e9dc800e3..bd6ea502e 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java @@ -57,7 +57,7 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { } @Override - protected int getLogContainerTypeForNormalState() { + protected int getLogContainerTypeForNormalState(MotionEvent ev) { return mLauncher.getDragLayer().isEventOverView(mLauncher.getHotseat(), mTouchDownEvent) ? ContainerType.HOTSEAT : ContainerType.WORKSPACE; } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java b/src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java new file mode 100644 index 000000000..e875a3c46 --- /dev/null +++ b/src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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 com.android.launcher3.config.BaseFlags.BaseTogglableFlag; + +public class TogglableFlag extends BaseTogglableFlag { + + public TogglableFlag(String key, boolean defaultValue, String description) { + super(key, defaultValue, description); + } + + @Override + public boolean getInitialValue(boolean value) { + return value; + } +} diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index 5cc64dc9a..467ae02d5 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -17,9 +17,11 @@ package com.android.launcher3.uioverrides; import android.app.Activity; +import android.app.Person; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ShortcutInfo; import android.os.Bundle; import android.os.CancellationSignal; @@ -27,6 +29,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.LauncherStateManager.StateHandler; +import com.android.launcher3.Utilities; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.util.TouchController; @@ -95,4 +98,7 @@ public class UiFactory { public static void clearSwipeSharedState(boolean finishAnimation) {} + public static Person[] getPersons(ShortcutInfo si) { + return Utilities.EMPTY_PERSON_ARRAY; + } } diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml index 61c7306e5..c6f55a717 100644 --- a/tests/AndroidManifest-common.xml +++ b/tests/AndroidManifest-common.xml @@ -20,6 +20,9 @@ <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/> + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/> + <uses-permission android:name="android.permission.READ_LOGS"/> + <application android:debuggable="true"> <uses-library android:name="android.test.runner"/> diff --git a/tests/OWNERS b/tests/OWNERS index 046d87116..02e8ebcab 100644 --- a/tests/OWNERS +++ b/tests/OWNERS @@ -1 +1,4 @@ vadimt@google.com +sunnygoyal@google.com +winsonc@google.com +hyunyoungs@google.com diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 8dc8cea40..fc19baace 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -38,6 +38,7 @@ import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.Until; @@ -330,30 +331,27 @@ public abstract class AbstractLauncherUiTest { } protected void startAppFast(String packageName) { - final Instrumentation instrumentation = getInstrumentation(); - final Intent intent = instrumentation.getContext().getPackageManager(). - getLaunchIntentForPackage(packageName); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - instrumentation.getTargetContext().startActivity(intent); - assertTrue(packageName + " didn't start", - mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), DEFAULT_UI_TIMEOUT)); + startIntent( + getInstrumentation().getContext().getPackageManager().getLaunchIntentForPackage( + packageName), + By.pkg(packageName).depth(0)); } protected void startTestActivity(int activityNumber) { final String packageName = getAppPackageName(); - final Instrumentation instrumentation = getInstrumentation(); - final Intent intent = instrumentation.getContext().getPackageManager(). + final Intent intent = getInstrumentation().getContext().getPackageManager(). getLaunchIntentForPackage(packageName); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setComponent(new ComponentName(packageName, "com.android.launcher3.tests.Activity" + activityNumber)); - instrumentation.getTargetContext().startActivity(intent); - assertTrue(packageName + " didn't start", - mDevice.wait( - Until.hasObject(By.pkg(packageName).text("TestActivity" + activityNumber)), - DEFAULT_UI_TIMEOUT)); + startIntent(intent, By.pkg(packageName).text("TestActivity" + activityNumber)); + } + + private void startIntent(Intent intent, BySelector selector) { + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + getInstrumentation().getTargetContext().startActivity(intent); + assertTrue("App didn't start: " + selector, + mDevice.wait(Until.hasObject(selector), DEFAULT_UI_TIMEOUT)); } public static String resolveSystemApp(String category) { diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java index 4dab44fad..0c87ab908 100644 --- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java @@ -173,6 +173,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @Test public void testWorkspace() throws Exception { + mLauncher.enableDebugTracing(); final Workspace workspace = mLauncher.getWorkspace(); // Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there. @@ -190,7 +191,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { launcher -> assertTrue("ensureScrollable didn't make workspace scrollable", isWorkspaceScrollable(launcher))); assertNotNull("ensureScrollable didn't add Chrome app", - workspace.tryGetWorkspaceAppIcon("Chrome")); + workspace.getWorkspaceAppIcon("Chrome")); // Test flinging workspace. workspace.flingBackward(); @@ -206,8 +207,9 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL)); // Test starting a workspace app. - final AppIcon app = workspace.tryGetWorkspaceAppIcon("Chrome"); + final AppIcon app = workspace.getWorkspaceAppIcon("Chrome"); assertNotNull("No Chrome app in workspace", app); + mLauncher.disableDebugTracing(); } public static void runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) { @@ -298,6 +300,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @Test @PortraitLandscape public void testDragAppIcon() throws Throwable { + mLauncher.enableDebugTracing(); // 1. Open all apps and wait for load complete. // 2. Drag icon to homescreen. // 3. Verify that the icon works on homescreen. @@ -314,11 +317,13 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { "Launcher activity is the top activity; expecting another activity to be the top " + "one", isInBackground(launcher))); + mLauncher.disableDebugTracing(); } @Test @PortraitLandscape public void testDragShortcut() throws Throwable { + mLauncher.enableDebugTracing(); // 1. Open all apps and wait for load complete. // 2. Find the app and long press it to show shortcuts. // 3. Press icon center until shortcuts appear @@ -338,6 +343,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { } finally { allApps.unfreeze(); } + mLauncher.disableDebugTracing(); } public static String getAppPackageName() { diff --git a/tests/src/com/android/launcher3/util/Wait.java b/tests/src/com/android/launcher3/util/Wait.java index 593cce832..899686bd6 100644 --- a/tests/src/com/android/launcher3/util/Wait.java +++ b/tests/src/com/android/launcher3/util/Wait.java @@ -1,6 +1,7 @@ package com.android.launcher3.util; import android.os.SystemClock; +import android.util.Log; import org.junit.Assert; @@ -16,7 +17,9 @@ public class Wait { } public static void atMost(String message, Condition condition, long timeout, long sleepMillis) { - long endTime = SystemClock.uptimeMillis() + timeout; + final long startTime = SystemClock.uptimeMillis(); + long endTime = startTime + timeout; + Log.d("Wait", "atMost: " + startTime + " - " + endTime); while (SystemClock.uptimeMillis() < endTime) { try { if (condition.isTrue()) { @@ -36,6 +39,7 @@ public class Wait { } catch (Throwable t) { throw new RuntimeException(t); } + Log.d("Wait", "atMost: timed out: " + SystemClock.uptimeMillis()); Assert.fail(message); } } diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java index eef2f24ba..e7a2bcab6 100644 --- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java +++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java @@ -15,7 +15,6 @@ import java.io.IOException; public class FailureWatcher extends TestWatcher { private static final String TAG = "FailureWatcher"; - private static int sScreenshotCount = 0; final private UiDevice mDevice; public FailureWatcher(UiDevice device) { @@ -40,7 +39,8 @@ public class FailureWatcher extends TestWatcher { protected void failed(Throwable e, Description description) { if (mDevice == null) return; final String pathname = getInstrumentation().getTargetContext(). - getFilesDir().getPath() + "/TaplTestScreenshot" + sScreenshotCount++ + ".png"; + getFilesDir().getPath() + "/TestScreenshot-" + description.getMethodName() + + ".png"; Log.e(TAG, "Failed test " + description.getMethodName() + ", screenshot will be saved to " + pathname + ", track trace is below, UI object dump is further below:\n" + diff --git a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java index 204240324..62fe26d13 100644 --- a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java +++ b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java @@ -19,6 +19,7 @@ import android.app.Activity; import android.app.Application; import android.app.Application.ActivityLifecycleCallbacks; import android.os.Bundle; + import androidx.test.InstrumentationRegistry; import com.android.launcher3.Launcher; @@ -84,19 +85,27 @@ public class LauncherActivityRule implements TestRule { } @Override - public void onActivityStarted(Activity activity) { } + public void onActivityStarted(Activity activity) { + if (activity instanceof Launcher) { + mActivity.getRotationHelper().forceAllowRotationForTesting(true); + } + } @Override - public void onActivityResumed(Activity activity) { } + public void onActivityResumed(Activity activity) { + } @Override - public void onActivityPaused(Activity activity) { } + public void onActivityPaused(Activity activity) { + } @Override - public void onActivityStopped(Activity activity) { } + public void onActivityStopped(Activity activity) { + } @Override - public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } + public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { + } @Override public void onActivityDestroyed(Activity activity) { diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index 9ff354a7e..f070280ea 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -120,7 +120,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { mLauncher.assertTrue("Unable to scroll to a clickable icon: " + appName, hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)); - final UiObject2 appIcon = mLauncher.getObjectInContainer(appListRecycler, + final UiObject2 appIcon = mLauncher.waitForObjectInContainer(appListRecycler, appIconSelector); return new AppIcon(mLauncher, appIcon); } diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java index bbd2c29e3..25e6e8c8f 100644 --- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java +++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java @@ -74,7 +74,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { flingForward(); } - mLauncher.getObjectInContainer(verifyActiveContainer(), clearAllSelector).click(); + mLauncher.waitForObjectInContainer(verifyActiveContainer(), clearAllSelector).click(); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( "dismissed all tasks")) { return new Workspace(mLauncher); diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java index 82af7b03a..df80a51fd 100644 --- a/tests/tapl/com/android/launcher3/tapl/Launchable.java +++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java @@ -16,6 +16,8 @@ package com.android.launcher3.tapl; +import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; + import android.graphics.Point; import androidx.test.uiautomator.By; @@ -23,13 +25,10 @@ import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.UiObject2; import androidx.test.uiautomator.Until; -import com.android.launcher3.testing.TestProtocol; - /** * Ancestor for AppIcon and AppMenuItem. */ abstract class Launchable { - private static final int WAIT_TIME_MS = 60000; protected final LauncherInstrumentation mLauncher; protected final UiObject2 mObject; @@ -53,9 +52,12 @@ abstract class Launchable { private Background launch(BySelector selector) { LauncherInstrumentation.log("Launchable.launch before click " + mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds()); - mLauncher.assertTrue( - "Launching an app didn't open a new window: " + mObject.getText(), - mObject.clickAndWait(Until.newWindow(), WAIT_TIME_MS)); + + mLauncher.executeAndWaitForEvent( + () -> mObject.click(), + event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED, + "Launching an app didn't open a new window: " + mObject.getText()); + mLauncher.assertTrue( "App didn't start: " + selector, mLauncher.getDevice().wait(Until.hasObject(selector), diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index fe7401ca6..9d433527d 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -124,7 +124,7 @@ public final class LauncherInstrumentation { private static final String APPS_RES_ID = "apps_view"; private static final String OVERVIEW_RES_ID = "overview_panel"; private static final String WIDGETS_RES_ID = "widgets_list_view"; - public static final int WAIT_TIME_MS = 60000; + public static final int WAIT_TIME_MS = 10000; private static final String SYSTEMUI_PACKAGE = "com.android.systemui"; private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null); @@ -178,6 +178,7 @@ public final class LauncherInstrumentation { PackageManager pm = getContext().getPackageManager(); ProviderInfo pi = pm.resolveContentProvider( testProviderAuthority, MATCH_ALL | MATCH_DISABLED_COMPONENTS); + assertNotNull("Cannot find content provider for " + testProviderAuthority, pi); ComponentName cn = new ComponentName(pi.packageName, pi.name); if (pm.getComponentEnabledSetting(cn) != COMPONENT_ENABLED_STATE_ENABLED) { @@ -678,13 +679,6 @@ public final class LauncherInstrumentation { } @NonNull - UiObject2 getObjectInContainer(UiObject2 container, BySelector selector) { - final UiObject2 object = container.findObject(selector); - assertNotNull("Can't find an object with selector: " + selector, object); - return object; - } - - @NonNull List<UiObject2> getObjectsInContainer(UiObject2 container, String resName) { return container.findObjects(getLauncherObjectSelector(resName)); } @@ -888,6 +882,7 @@ public final class LauncherInstrumentation { } long movePointer(long downTime, long startTime, long duration, Point from, Point to) { + log("movePointer: " + from + " to " + to); final Point point = new Point(); long steps = duration / GESTURE_STEP_MS; long currentTime = startTime; @@ -962,4 +957,9 @@ public final class LauncherInstrumentation { public void disableDebugTracing() { getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING); } + + public long getAllocatedMemory() { + return getTestInfo(TestProtocol.REQUEST_ALLOCATED_MEMORY). + getLong(TestProtocol.TEST_INFO_RESPONSE_FIELD); + } }
\ No newline at end of file diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java index 6e3332260..91f0fc4c8 100644 --- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java +++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java @@ -16,18 +16,16 @@ package com.android.launcher3.tapl; +import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; + import android.graphics.Rect; import androidx.test.uiautomator.UiObject2; -import androidx.test.uiautomator.Until; - -import com.android.launcher3.testing.TestProtocol; /** * A recent task in the overview panel carousel. */ public final class OverviewTask { - private static final long WAIT_TIME_MS = 60000; private final LauncherInstrumentation mLauncher; private final UiObject2 mTask; private final BaseOverview mOverview; @@ -66,9 +64,11 @@ public final class OverviewTask { verifyActiveContainer(); try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "clicking an overview task")) { - mLauncher.assertTrue("Launching task didn't open a new window: " + - mTask.getParent().getContentDescription(), - mTask.clickAndWait(Until.newWindow(), WAIT_TIME_MS)); + mLauncher.executeAndWaitForEvent( + () -> mTask.click(), + event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED, + "Launching task didn't open a new window: " + + mTask.getParent().getContentDescription()); } return new Background(mLauncher); } diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java index 399c59d36..a089a527e 100644 --- a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java +++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java @@ -109,7 +109,7 @@ public class TestHelpers { DropBoxManager.Entry entry; StringBuilder errorDetails = new StringBuilder(); while (null != (entry = dropbox.getNextEntry(label, timestamp))) { - if (errorDetails.length() != 0) errorDetails.append("------------------------------"); + errorDetails.append("------------------------------\n"); timestamp = entry.getTimeMillis(); errorDetails.append(new Date(timestamp)); errorDetails.append(": "); diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index 07f8b6443..639902fa0 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -108,10 +108,13 @@ public final class Workspace extends Home { */ @NonNull public AppIcon getWorkspaceAppIcon(String appName) { - return new AppIcon(mLauncher, - mLauncher.getObjectInContainer( - verifyActiveContainer(), - AppIcon.getAppIconSelector(appName, mLauncher))); + try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( + "want to get a workspace icon")) { + return new AppIcon(mLauncher, + mLauncher.waitForObjectInContainer( + verifyActiveContainer(), + AppIcon.getAppIconSelector(appName, mLauncher))); + } } /** @@ -142,13 +145,13 @@ public final class Workspace extends Home { @NonNull public AppIcon getHotseatAppIcon(String appName) { - return new AppIcon(mLauncher, mLauncher.getObjectInContainer( + return new AppIcon(mLauncher, mLauncher.waitForObjectInContainer( mHotseat, AppIcon.getAppIconSelector(appName, mLauncher))); } @NonNull public Folder getHotseatFolder(String appName) { - return new Folder(mLauncher, mLauncher.getObjectInContainer( + return new Folder(mLauncher, mLauncher.waitForObjectInContainer( mHotseat, Folder.getSelector(appName, mLauncher))); } |