Merge "Merge stage-aosp-master to aosp-master - DO NOT MERGE"
This commit is contained in:
+4
-12
@@ -23,12 +23,7 @@ include $(CLEAR_VARS)
|
||||
LOCAL_USE_AAPT2 := true
|
||||
LOCAL_AAPT2_ONLY := true
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
ifneq (,$(wildcard frameworks/base))
|
||||
LOCAL_STATIC_JAVA_LIBRARIES:= PluginCoreLib
|
||||
else
|
||||
LOCAL_STATIC_JAVA_LIBRARIES:= libPluginCore
|
||||
endif
|
||||
LOCAL_STATIC_JAVA_LIBRARIES:= PluginCoreLib
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src_plugins)
|
||||
@@ -151,11 +146,10 @@ LOCAL_USE_AAPT2 := true
|
||||
LOCAL_AAPT2_ONLY := true
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano
|
||||
ifneq (,$(wildcard frameworks/base))
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano
|
||||
LOCAL_PRIVATE_PLATFORM_APIS := true
|
||||
else
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := libSharedSystemUI libLauncherProtos
|
||||
LOCAL_SDK_VERSION := system_current
|
||||
LOCAL_MIN_SDK_VERSION := 26
|
||||
endif
|
||||
@@ -224,11 +218,10 @@ include $(CLEAR_VARS)
|
||||
LOCAL_USE_AAPT2 := true
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano
|
||||
ifneq (,$(wildcard frameworks/base))
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano
|
||||
LOCAL_PRIVATE_PLATFORM_APIS := true
|
||||
else
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := libSharedSystemUI libLauncherProtos
|
||||
LOCAL_SDK_VERSION := system_current
|
||||
LOCAL_MIN_SDK_VERSION := 26
|
||||
endif
|
||||
@@ -271,11 +264,10 @@ include $(CLEAR_VARS)
|
||||
LOCAL_USE_AAPT2 := true
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano
|
||||
ifneq (,$(wildcard frameworks/base))
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano
|
||||
LOCAL_PRIVATE_PLATFORM_APIS := true
|
||||
else
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := libSharedSystemUI libLauncherProtos
|
||||
LOCAL_SDK_VERSION := system_current
|
||||
LOCAL_MIN_SDK_VERSION := 26
|
||||
endif
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
<activity
|
||||
android:name="com.android.launcher3.settings.SettingsActivity"
|
||||
android:label="@string/settings_button_text"
|
||||
android:theme="@android:style/Theme.DeviceDefault.Settings"
|
||||
android:theme="@style/HomeSettingsTheme"
|
||||
android:autoRemoveFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[Hook Scripts]
|
||||
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
|
||||
@@ -21,5 +21,5 @@
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="couldnt_launch" msgid="7873588052226763866">"تعذَّر تشغيل النشاط."</string>
|
||||
<string name="add_app_shortcut" msgid="2756755330707509435">"إضافة اختصار التطبيق"</string>
|
||||
<string name="set_wallpaper" msgid="6475195450505435904">"تعيين الخلفية"</string>
|
||||
<string name="set_wallpaper" msgid="6475195450505435904">"ضبط الخلفية"</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="couldnt_launch" msgid="7873588052226763866">"Couldn\'t launch the activity"</string>
|
||||
<string name="add_app_shortcut" msgid="2756755330707509435">"Add app shortcut"</string>
|
||||
<string name="set_wallpaper" msgid="6475195450505435904">"Set wallpaper"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="couldnt_launch" msgid="7873588052226763866">"Couldn\'t launch the activity"</string>
|
||||
<string name="add_app_shortcut" msgid="2756755330707509435">"Add app shortcut"</string>
|
||||
<string name="set_wallpaper" msgid="6475195450505435904">"Set wallpaper"</string>
|
||||
</resources>
|
||||
@@ -22,5 +22,7 @@
|
||||
<string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
|
||||
|
||||
<string name="main_process_initializer_class" translatable="false">com.android.quickstep.QuickstepProcessInitializer</string>
|
||||
|
||||
<string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherExtension</string>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper
|
||||
.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
@@ -25,7 +25,6 @@ import android.os.SystemClock;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
|
||||
@@ -43,7 +42,6 @@ public class OverviewCommandHelper {
|
||||
private final Context mContext;
|
||||
private final ActivityManagerWrapper mAM;
|
||||
private final RecentsModel mRecentsModel;
|
||||
private final MainThreadExecutor mMainThreadExecutor;
|
||||
private final OverviewComponentObserver mOverviewComponentObserver;
|
||||
|
||||
private long mLastToggleTime;
|
||||
@@ -51,7 +49,6 @@ public class OverviewCommandHelper {
|
||||
public OverviewCommandHelper(Context context, OverviewComponentObserver observer) {
|
||||
mContext = context;
|
||||
mAM = ActivityManagerWrapper.getInstance();
|
||||
mMainThreadExecutor = new MainThreadExecutor();
|
||||
mRecentsModel = RecentsModel.INSTANCE.get(mContext);
|
||||
mOverviewComponentObserver = observer;
|
||||
}
|
||||
@@ -63,19 +60,19 @@ public class OverviewCommandHelper {
|
||||
}
|
||||
|
||||
mAM.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
||||
mMainThreadExecutor.execute(new RecentsActivityCommand<>());
|
||||
MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());
|
||||
}
|
||||
|
||||
public void onOverviewShown(boolean triggeredFromAltTab) {
|
||||
mMainThreadExecutor.execute(new ShowRecentsCommand());
|
||||
MAIN_EXECUTOR.execute(new ShowRecentsCommand());
|
||||
}
|
||||
|
||||
public void onOverviewHidden() {
|
||||
mMainThreadExecutor.execute(new HideRecentsCommand());
|
||||
MAIN_EXECUTOR.execute(new HideRecentsCommand());
|
||||
}
|
||||
|
||||
public void onTip(int actionType, int viewType) {
|
||||
mMainThreadExecutor.execute(() ->
|
||||
MAIN_EXECUTOR.execute(() ->
|
||||
UserEventDispatcher.newInstance(mContext).logActionTip(actionType, viewType));
|
||||
}
|
||||
|
||||
@@ -161,7 +158,7 @@ public class OverviewCommandHelper {
|
||||
// Otherwise, start overview.
|
||||
mListener = mHelper.createActivityInitListener(provider::onActivityReady);
|
||||
mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(),
|
||||
provider, mContext, mMainThreadExecutor.getHandler(),
|
||||
provider, mContext, MAIN_EXECUTOR.getHandler(),
|
||||
provider.getRecentsLaunchDuration());
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@ import android.view.MotionEvent;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
import com.android.systemui.shared.recents.IOverviewProxy;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
|
||||
@@ -139,9 +137,6 @@ public class TouchInteractionService extends Service {
|
||||
return sConnected;
|
||||
}
|
||||
|
||||
public static final LooperExecutor BACKGROUND_EXECUTOR =
|
||||
new LooperExecutor(UiThreadHelper.getBackgroundLooper());
|
||||
|
||||
private RecentsModel mRecentsModel;
|
||||
private OverviewComponentObserver mOverviewComponentObserver;
|
||||
private OverviewCommandHelper mOverviewCommandHelper;
|
||||
|
||||
@@ -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.quickstep.util;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
|
||||
/** Empty class, only exists so that l3goWithQuickstepIconRecentsDebug compiles. */
|
||||
public class ShelfPeekAnim {
|
||||
public ShelfPeekAnim(Launcher launcher) {
|
||||
}
|
||||
|
||||
public enum ShelfAnimState {
|
||||
}
|
||||
|
||||
public boolean isPeeking() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,8 @@
|
||||
|
||||
package com.android.launcher3.model;
|
||||
|
||||
import com.android.launcher3.AllAppsList;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherModel.Callbacks;
|
||||
import com.android.launcher3.model.BgDataModel.Callbacks;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
|
||||
@@ -27,34 +27,23 @@ import android.os.UserHandle;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.notification.NotificationKeyData;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
|
||||
*/
|
||||
public class DeepShortcutManager {
|
||||
private static DeepShortcutManager sInstance;
|
||||
private static final Object sInstanceLock = new Object();
|
||||
|
||||
private static final DeepShortcutManager sInstance = new DeepShortcutManager();
|
||||
|
||||
public static DeepShortcutManager getInstance(Context context) {
|
||||
synchronized (sInstanceLock) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new DeepShortcutManager(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private DeepShortcutManager(Context context) {
|
||||
}
|
||||
private final QueryResult mFailure = new QueryResult();
|
||||
|
||||
public boolean wasLastCallSuccess() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onShortcutsChanged(List<ShortcutInfo> shortcuts) {
|
||||
}
|
||||
private DeepShortcutManager() { }
|
||||
|
||||
/**
|
||||
* Queries for the shortcuts with the package name and provided ids.
|
||||
@@ -62,18 +51,18 @@ public class DeepShortcutManager {
|
||||
* This method is intended to get the full details for shortcuts when they are added or updated,
|
||||
* because we only get "key" fields in onShortcutsChanged().
|
||||
*/
|
||||
public List<ShortcutInfo> queryForFullDetails(String packageName,
|
||||
public QueryResult queryForFullDetails(String packageName,
|
||||
List<String> shortcutIds, UserHandle user) {
|
||||
return Collections.emptyList();
|
||||
return mFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 QueryResult queryForShortcutsContainer(ComponentName activity,
|
||||
UserHandle user) {
|
||||
return Collections.emptyList();
|
||||
return mFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,20 +92,28 @@ public class DeepShortcutManager {
|
||||
*
|
||||
* If packageName is null, returns all pinned shortcuts regardless of package.
|
||||
*/
|
||||
public List<ShortcutInfo> queryForPinnedShortcuts(String packageName, UserHandle user) {
|
||||
return Collections.emptyList();
|
||||
public QueryResult queryForPinnedShortcuts(String packageName, UserHandle user) {
|
||||
return mFailure;
|
||||
}
|
||||
|
||||
public List<ShortcutInfo> queryForPinnedShortcuts(String packageName,
|
||||
public QueryResult queryForPinnedShortcuts(String packageName,
|
||||
List<String> shortcutIds, UserHandle user) {
|
||||
return Collections.emptyList();
|
||||
return mFailure;
|
||||
}
|
||||
|
||||
public List<ShortcutInfo> queryForAllShortcuts(UserHandle user) {
|
||||
return Collections.emptyList();
|
||||
public QueryResult queryForAllShortcuts(UserHandle user) {
|
||||
return mFailure;
|
||||
}
|
||||
|
||||
public boolean hasHostPermission() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static class QueryResult extends ArrayList<ShortcutInfo> {
|
||||
|
||||
public boolean wasSuccess() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
@@ -35,6 +36,8 @@ public class BaseIconFactory implements AutoCloseable {
|
||||
static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
|
||||
static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
|
||||
|
||||
private static final float ICON_BADGE_SCALE = 0.444f;
|
||||
|
||||
private final Rect mOldBounds = new Rect();
|
||||
protected final Context mContext;
|
||||
private final Canvas mCanvas;
|
||||
@@ -251,7 +254,7 @@ public class BaseIconFactory implements AutoCloseable {
|
||||
* Adds the {@param badge} on top of {@param target} using the badge dimensions.
|
||||
*/
|
||||
public void badgeWithDrawable(Canvas target, Drawable badge) {
|
||||
int badgeSize = mContext.getResources().getDimensionPixelSize(R.dimen.profile_badge_size);
|
||||
int badgeSize = getBadgeSizeForIconSize(mIconBitmapSize);
|
||||
badge.setBounds(mIconBitmapSize - badgeSize, mIconBitmapSize - badgeSize,
|
||||
mIconBitmapSize, mIconBitmapSize);
|
||||
badge.draw(target);
|
||||
@@ -331,6 +334,13 @@ public class BaseIconFactory implements AutoCloseable {
|
||||
iconDpi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correct badge size given an icon size
|
||||
*/
|
||||
public static int getBadgeSizeForIconSize(int iconSize) {
|
||||
return (int) (ICON_BADGE_SCALE * iconSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size.
|
||||
* This allows the badging to be done based on the action bitmap size rather than
|
||||
|
||||
@@ -267,9 +267,13 @@ public abstract class BaseIconCache {
|
||||
entry = new CacheEntry();
|
||||
cachingLogic.loadIcon(mContext, object, entry);
|
||||
}
|
||||
// Icon can't be loaded from cachingLogic, which implies alternative icon was loaded
|
||||
// (e.g. fallback icon, default icon). So we drop here since there's no point in caching
|
||||
// an empty entry.
|
||||
if (entry.icon == null) return;
|
||||
entry.title = cachingLogic.getLabel(object);
|
||||
entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user);
|
||||
mCache.put(key, entry);
|
||||
if (cachingLogic.addToMemCache()) mCache.put(key, entry);
|
||||
|
||||
ContentValues values = newContentValues(entry, entry.title.toString(),
|
||||
componentName.getPackageName(), cachingLogic.getKeywords(object, mLocaleList));
|
||||
@@ -308,20 +312,12 @@ public abstract class BaseIconCache {
|
||||
@NonNull ComponentName componentName, @NonNull UserHandle user,
|
||||
@NonNull Supplier<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
|
||||
boolean usePackageIcon, boolean useLowResIcon) {
|
||||
return cacheLocked(componentName, user, infoProvider, cachingLogic, usePackageIcon,
|
||||
useLowResIcon, true);
|
||||
}
|
||||
|
||||
protected <T> CacheEntry cacheLocked(
|
||||
@NonNull ComponentName componentName, @NonNull UserHandle user,
|
||||
@NonNull Supplier<T> infoProvider, @NonNull CachingLogic<T> cachingLogic,
|
||||
boolean usePackageIcon, boolean useLowResIcon, boolean addToMemCache) {
|
||||
assertWorkerThread();
|
||||
ComponentKey cacheKey = new ComponentKey(componentName, user);
|
||||
CacheEntry entry = mCache.get(cacheKey);
|
||||
if (entry == null || (entry.isLowRes() && !useLowResIcon)) {
|
||||
entry = new CacheEntry();
|
||||
if (addToMemCache) {
|
||||
if (cachingLogic.addToMemCache()) {
|
||||
mCache.put(cacheKey, entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,4 +41,11 @@ public interface CachingLogic<T> {
|
||||
default String getKeywords(T object, LocaleList localeList) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true the object should be added to mem cache; otherwise returns false.
|
||||
*/
|
||||
default boolean addToMemCache() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -171,8 +171,8 @@ public class IconCacheUpdateHandler {
|
||||
long updateTime = c.getLong(indexLastUpdate);
|
||||
int version = c.getInt(indexVersion);
|
||||
T app = componentMap.remove(component);
|
||||
if (version == info.versionCode && updateTime == info.lastUpdateTime &&
|
||||
TextUtils.equals(c.getString(systemStateIndex),
|
||||
if (version == info.versionCode && updateTime == info.lastUpdateTime
|
||||
&& TextUtils.equals(c.getString(systemStateIndex),
|
||||
mIconCache.getIconSystemState(info.packageName))) {
|
||||
|
||||
if (mFilterMode == MODE_CLEAR_VALID_ITEMS) {
|
||||
|
||||
@@ -118,6 +118,7 @@ enum ControlType {
|
||||
APP_USAGE_SETTINGS = 18;
|
||||
BACK_GESTURE = 19;
|
||||
UNDO = 20;
|
||||
DISMISS_PREDICTION = 21;
|
||||
}
|
||||
|
||||
enum TipType {
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
<activity android:name="com.android.quickstep.LockScreenRecentsActivity"
|
||||
android:theme="@android:style/Theme.NoDisplay"
|
||||
android:showOnLockScreen="true"
|
||||
android:taskAffinity="${packageName}.locktask"
|
||||
android:directBootAware="true" />
|
||||
|
||||
</application>
|
||||
|
||||
@@ -24,5 +24,7 @@
|
||||
<string name="app_launch_tracker_class" translatable="false">com.android.launcher3.appprediction.PredictionAppTracker</string>
|
||||
|
||||
<string name="main_process_initializer_class" translatable="false">com.android.quickstep.QuickstepProcessInitializer</string>
|
||||
|
||||
<string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherAppPredictionExtension</string>
|
||||
</resources>
|
||||
|
||||
|
||||
+66
-6
@@ -17,9 +17,19 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
|
||||
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
|
||||
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
|
||||
import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator;
|
||||
|
||||
@@ -27,10 +37,17 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.LauncherState.ScaleAndTranslation;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.SpringAnimationBuilder;
|
||||
import com.android.quickstep.util.ClipAnimationHelper;
|
||||
@@ -38,9 +55,6 @@ import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A {@link QuickstepAppTransitionManagerImpl} that also implements recents transitions from
|
||||
* {@link RecentsView}.
|
||||
@@ -50,6 +64,9 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
|
||||
public static final int INDEX_SHELF_ANIM = 0;
|
||||
public static final int INDEX_RECENTS_FADE_ANIM = 1;
|
||||
public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = 2;
|
||||
public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM = 3;
|
||||
|
||||
public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300;
|
||||
|
||||
public LauncherAppTransitionManagerImpl(Context context) {
|
||||
super(context);
|
||||
@@ -138,14 +155,43 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
|
||||
|
||||
@Override
|
||||
public int getStateElementAnimationsCount() {
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator createStateElementAnimation(int index, float... values) {
|
||||
switch (index) {
|
||||
case INDEX_SHELF_ANIM:
|
||||
return mLauncher.getAllAppsController().createSpringAnimation(values);
|
||||
case INDEX_SHELF_ANIM: {
|
||||
AllAppsTransitionController aatc = mLauncher.getAllAppsController();
|
||||
Animator springAnim = aatc.createSpringAnimation(values);
|
||||
|
||||
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
|
||||
// Translate hotseat with the shelf until reaching overview.
|
||||
float overviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
|
||||
ScaleAndTranslation sat = OVERVIEW.getHotseatScaleAndTranslation(mLauncher);
|
||||
float shiftRange = aatc.getShiftRange();
|
||||
if (values.length == 1) {
|
||||
values = new float[] {aatc.getProgress(), values[0]};
|
||||
}
|
||||
ValueAnimator hotseatAnim = ValueAnimator.ofFloat(values);
|
||||
hotseatAnim.addUpdateListener(anim -> {
|
||||
float progress = (Float) anim.getAnimatedValue();
|
||||
if (progress >= overviewProgress || mLauncher.isInState(BACKGROUND_APP)) {
|
||||
float hotseatShift = (progress - overviewProgress) * shiftRange;
|
||||
mLauncher.getHotseat().setTranslationY(hotseatShift + sat.translationY);
|
||||
}
|
||||
});
|
||||
hotseatAnim.setInterpolator(LINEAR);
|
||||
hotseatAnim.setDuration(springAnim.getDuration());
|
||||
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
anim.play(hotseatAnim);
|
||||
anim.play(springAnim);
|
||||
return anim;
|
||||
}
|
||||
|
||||
return springAnim;
|
||||
}
|
||||
case INDEX_RECENTS_FADE_ANIM:
|
||||
return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
|
||||
RecentsView.CONTENT_ALPHA, values);
|
||||
@@ -155,6 +201,20 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
|
||||
.setStiffness(250)
|
||||
.setValues(values)
|
||||
.build(mLauncher);
|
||||
case INDEX_PAUSE_TO_OVERVIEW_ANIM: {
|
||||
AnimatorSetBuilder builder = new AnimatorSetBuilder();
|
||||
builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
|
||||
builder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3);
|
||||
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
|
||||
builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
|
||||
builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
|
||||
}
|
||||
LauncherStateManager stateManager = mLauncher.getStateManager();
|
||||
return stateManager.createAtomicAnimation(
|
||||
stateManager.getCurrentStableState(), OVERVIEW, builder,
|
||||
ANIM_ALL, ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW);
|
||||
}
|
||||
|
||||
default:
|
||||
return super.createStateElementAnimation(index, values);
|
||||
}
|
||||
|
||||
+8
-7
@@ -17,6 +17,8 @@ package com.android.launcher3.appprediction;
|
||||
|
||||
import static android.content.pm.PackageManager.MATCH_INSTANT;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@@ -30,8 +32,12 @@ import android.os.Message;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
@@ -45,11 +51,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
/**
|
||||
* Utility class which loads and caches predicted items like instant apps and shortcuts, before
|
||||
* they can be displayed on the UI
|
||||
@@ -77,7 +78,7 @@ public class DynamicItemCache {
|
||||
|
||||
public DynamicItemCache(Context context, Runnable onUpdateCallback) {
|
||||
mContext = context;
|
||||
mWorker = new Handler(LauncherModel.getWorkerLooper(), this::handleWorkerMessage);
|
||||
mWorker = new Handler(MODEL_EXECUTOR.getLooper(), this::handleWorkerMessage);
|
||||
mUiHandler = new Handler(Looper.getMainLooper(), this::handleUiMessage);
|
||||
mInstantAppResolver = InstantAppResolver.newInstance(context);
|
||||
mOnUpdateCallback = onUpdateCallback;
|
||||
|
||||
+93
-20
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.launcher3.appprediction;
|
||||
|
||||
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.prediction.AppPredictionContext;
|
||||
@@ -34,19 +35,25 @@ import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||
import com.android.launcher3.model.AppLaunchTracker;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.systemui.plugins.AppLaunchEventsPlugin;
|
||||
import com.android.systemui.plugins.PluginListener;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Subclass of app tracker which publishes the data to the prediction engine and gets back results.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.Q)
|
||||
public class PredictionAppTracker extends AppLaunchTracker {
|
||||
public class PredictionAppTracker extends AppLaunchTracker
|
||||
implements PluginListener<AppLaunchEventsPlugin> {
|
||||
|
||||
private static final String TAG = "PredictionAppTracker";
|
||||
private static final boolean DBG = false;
|
||||
@@ -58,6 +65,7 @@ public class PredictionAppTracker extends AppLaunchTracker {
|
||||
|
||||
protected final Context mContext;
|
||||
private final Handler mMessageHandler;
|
||||
private final List<AppLaunchEventsPlugin> mAppLaunchEventsPluginsList;
|
||||
|
||||
// Accessed only on worker thread
|
||||
private AppPredictor mHomeAppPredictor;
|
||||
@@ -65,10 +73,14 @@ public class PredictionAppTracker extends AppLaunchTracker {
|
||||
|
||||
public PredictionAppTracker(Context context) {
|
||||
mContext = context;
|
||||
mMessageHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleMessage);
|
||||
mMessageHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleMessage);
|
||||
InvariantDeviceProfile.INSTANCE.get(mContext).addOnChangeListener(this::onIdpChanged);
|
||||
|
||||
mMessageHandler.sendEmptyMessage(MSG_INIT);
|
||||
|
||||
mAppLaunchEventsPluginsList = new ArrayList<>();
|
||||
PluginManagerWrapper.INSTANCE.get(context)
|
||||
.addPluginListener(this, AppLaunchEventsPlugin.class, true);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@@ -96,7 +108,7 @@ public class PredictionAppTracker extends AppLaunchTracker {
|
||||
AppPredictionManager apm = mContext.getSystemService(AppPredictionManager.class);
|
||||
|
||||
if (apm == null) {
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
AppPredictor predictor = apm.createAppPredictionSession(
|
||||
@@ -116,7 +128,7 @@ public class PredictionAppTracker extends AppLaunchTracker {
|
||||
*/
|
||||
@WorkerThread
|
||||
@Nullable
|
||||
public Bundle getAppPredictionContextExtras(Client client){
|
||||
public Bundle getAppPredictionContextExtras(Client client) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -128,7 +140,7 @@ public class PredictionAppTracker extends AppLaunchTracker {
|
||||
destroy();
|
||||
|
||||
// Initialize the clients
|
||||
int count = InvariantDeviceProfile.INSTANCE.get(mContext).numColumns;
|
||||
int count = InvariantDeviceProfile.INSTANCE.get(mContext).numAllAppsColumns;
|
||||
mHomeAppPredictor = createPredictor(Client.HOME, count);
|
||||
mRecentsOverviewPredictor = createPredictor(Client.OVERVIEW, count);
|
||||
return true;
|
||||
@@ -167,37 +179,98 @@ public class PredictionAppTracker extends AppLaunchTracker {
|
||||
if (DBG) {
|
||||
Log.d(TAG, String.format("Sent immediate message to update %s", client));
|
||||
}
|
||||
|
||||
// Relay onReturnedToHome to every plugin.
|
||||
mAppLaunchEventsPluginsList.forEach(AppLaunchEventsPlugin::onReturnedToHome);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void onStartShortcut(String packageName, String shortcutId, UserHandle user,
|
||||
String container) {
|
||||
String container) {
|
||||
// TODO: Use the full shortcut info
|
||||
AppTarget target = new AppTarget
|
||||
.Builder(new AppTargetId("shortcut:" + shortcutId), packageName, user)
|
||||
.setClassName(shortcutId)
|
||||
.build();
|
||||
AppTarget target = new AppTarget.Builder(
|
||||
new AppTargetId("shortcut:" + shortcutId), packageName, user)
|
||||
.setClassName(shortcutId)
|
||||
.build();
|
||||
|
||||
sendLaunch(target, container);
|
||||
|
||||
// Relay onStartShortcut info to every connected plugin.
|
||||
mAppLaunchEventsPluginsList
|
||||
.forEach(plugin -> plugin.onStartShortcut(
|
||||
packageName,
|
||||
shortcutId,
|
||||
user,
|
||||
container != null ? container : CONTAINER_DEFAULT)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void onStartApp(ComponentName cn, UserHandle user, String container) {
|
||||
if (cn != null) {
|
||||
AppTarget target = new AppTarget
|
||||
.Builder(new AppTargetId("app:" + cn), cn.getPackageName(), user)
|
||||
.setClassName(cn.getClassName())
|
||||
.build();
|
||||
AppTarget target = new AppTarget.Builder(
|
||||
new AppTargetId("app:" + cn), cn.getPackageName(), user)
|
||||
.setClassName(cn.getClassName())
|
||||
.build();
|
||||
sendLaunch(target, container);
|
||||
|
||||
// Relay onStartApp to every connected plugin.
|
||||
mAppLaunchEventsPluginsList
|
||||
.forEach(plugin -> plugin.onStartApp(
|
||||
cn,
|
||||
user,
|
||||
container != null ? container : CONTAINER_DEFAULT)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
private void sendLaunch(AppTarget target, String container) {
|
||||
AppTargetEvent event = new AppTargetEvent.Builder(target, AppTargetEvent.ACTION_LAUNCH)
|
||||
public void onDismissApp(ComponentName cn, UserHandle user, String container) {
|
||||
if (cn == null) return;
|
||||
AppTarget target = new AppTarget.Builder(
|
||||
new AppTargetId("app: " + cn), cn.getPackageName(), user)
|
||||
.setClassName(cn.getClassName())
|
||||
.build();
|
||||
sendDismiss(target, container);
|
||||
|
||||
// Relay onDismissApp to every connected plugin.
|
||||
mAppLaunchEventsPluginsList
|
||||
.forEach(plugin -> plugin.onDismissApp(
|
||||
cn,
|
||||
user,
|
||||
container != null ? container : CONTAINER_DEFAULT)
|
||||
);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void sendEvent(AppTarget target, String container, int eventId) {
|
||||
AppTargetEvent event = new AppTargetEvent.Builder(target, eventId)
|
||||
.setLaunchLocation(container == null ? CONTAINER_DEFAULT : container)
|
||||
.build();
|
||||
Message.obtain(mMessageHandler, MSG_LAUNCH, event).sendToTarget();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void sendLaunch(AppTarget target, String container) {
|
||||
sendEvent(target, container, AppTargetEvent.ACTION_LAUNCH);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void sendDismiss(AppTarget target, String container) {
|
||||
sendEvent(target, container, AppTargetEvent.ACTION_DISMISS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginConnected(AppLaunchEventsPlugin appLaunchEventsPlugin, Context context) {
|
||||
mAppLaunchEventsPluginsList.add(appLaunchEventsPlugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginDisconnected(AppLaunchEventsPlugin appLaunchEventsPlugin) {
|
||||
mAppLaunchEventsPluginsList.remove(appLaunchEventsPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-5
@@ -43,6 +43,7 @@ import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.allapps.AllAppsStore;
|
||||
@@ -92,7 +93,7 @@ public class PredictionRowView extends LinearLayout implements
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final PredictionUiStateManager mPredictionUiStateManager;
|
||||
private final int mNumPredictedAppsPerRow;
|
||||
private int mNumPredictedAppsPerRow;
|
||||
|
||||
// The set of predicted app component names
|
||||
private final List<ComponentKeyMapper> mPredictedAppComponents = new ArrayList<>();
|
||||
@@ -128,7 +129,7 @@ public class PredictionRowView extends LinearLayout implements
|
||||
|
||||
mFocusHelper = new SimpleFocusIndicatorHelper(this);
|
||||
|
||||
mNumPredictedAppsPerRow = LauncherAppState.getIDP(context).numColumns;
|
||||
mNumPredictedAppsPerRow = LauncherAppState.getIDP(context).numAllAppsColumns;
|
||||
mLauncher = Launcher.getLauncher(context);
|
||||
mLauncher.addOnDeviceProfileChangeListener(this);
|
||||
|
||||
@@ -226,6 +227,7 @@ public class PredictionRowView extends LinearLayout implements
|
||||
|
||||
@Override
|
||||
public void onDeviceProfileChanged(DeviceProfile dp) {
|
||||
mNumPredictedAppsPerRow = dp.inv.numAllAppsColumns;
|
||||
removeAllViews();
|
||||
applyPredictionApps();
|
||||
}
|
||||
@@ -274,14 +276,14 @@ public class PredictionRowView extends LinearLayout implements
|
||||
boolean predictionsEnabled = predictionCount > 0;
|
||||
if (predictionsEnabled != mPredictionsEnabled) {
|
||||
mPredictionsEnabled = predictionsEnabled;
|
||||
mLauncher.reapplyUi();
|
||||
mLauncher.reapplyUi(false /* cancelCurrentAnimation */);
|
||||
updateVisibility();
|
||||
}
|
||||
mParent.onHeightUpdated();
|
||||
}
|
||||
|
||||
private List<ItemInfoWithIcon> processPredictedAppComponents(List<ComponentKeyMapper> components) {
|
||||
if (getAppsStore().getApps().isEmpty()) {
|
||||
if (getAppsStore().getApps().length == 0) {
|
||||
// Apps have not been bound yet.
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -290,7 +292,9 @@ public class PredictionRowView extends LinearLayout implements
|
||||
for (ComponentKeyMapper mapper : components) {
|
||||
ItemInfoWithIcon info = mapper.getApp(getAppsStore());
|
||||
if (info != null) {
|
||||
predictedApps.add(info);
|
||||
ItemInfoWithIcon predictedApp = info.clone();
|
||||
predictedApp.container = LauncherSettings.Favorites.CONTAINER_PREDICTION;
|
||||
predictedApps.add(predictedApp);
|
||||
} else {
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
Log.e(TAG, "Predicted app not found: " + mapper);
|
||||
|
||||
+30
@@ -25,12 +25,16 @@ import android.app.prediction.AppTarget;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager.StateListener;
|
||||
import com.android.launcher3.Utilities;
|
||||
@@ -39,12 +43,14 @@ import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Handler responsible to updating the UI due to predicted apps changes. Operations:
|
||||
@@ -322,6 +328,30 @@ public class PredictionUiStateManager implements StateListener, ItemInfoUpdateRe
|
||||
return mCurrentState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in predicted_rank field based on app prediction.
|
||||
* Only applicable when {@link ItemInfo#itemType} is one of the followings:
|
||||
* {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
|
||||
* {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
|
||||
* {@link LauncherSettings.Favorites#ITEM_TYPE_DEEP_SHORTCUT}
|
||||
*/
|
||||
public static void fillInPredictedRank(
|
||||
@NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) {
|
||||
final PredictionUiStateManager manager = PredictionUiStateManager.INSTANCE.getNoCreate();
|
||||
if (manager == null || itemInfo.getTargetComponent() == null || itemInfo.user == null
|
||||
|| (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
|
||||
&& itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
|
||||
&& itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)) {
|
||||
return;
|
||||
}
|
||||
final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);
|
||||
final List<ComponentKeyMapper> predictedApps = manager.getCurrentState().apps;
|
||||
IntStream.range(0, predictedApps.size())
|
||||
.filter((i) -> k.equals(predictedApps.get(i).getComponentKey()))
|
||||
.findFirst()
|
||||
.ifPresent((rank) -> target.predictedRank = rank);
|
||||
}
|
||||
|
||||
public static class PredictionState {
|
||||
|
||||
public boolean isEnabled;
|
||||
|
||||
+3
-3
@@ -28,17 +28,17 @@ import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager.StateHandler;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.NoButtonQuickSwitchTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.OverviewToAllAppsTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
@@ -145,7 +145,7 @@ public abstract class RecentsUiFactory {
|
||||
ArrayList<TouchController> list = new ArrayList<>();
|
||||
list.add(launcher.getDragController());
|
||||
if (mode == NO_BUTTON) {
|
||||
list.add(new QuickSwitchTouchController(launcher));
|
||||
list.add(new NoButtonQuickSwitchTouchController(launcher));
|
||||
list.add(new NavBarToHomeTouchController(launcher));
|
||||
list.add(new FlingAndHoldTouchController(launcher));
|
||||
} else {
|
||||
|
||||
+11
-4
@@ -19,7 +19,6 @@ import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
@@ -69,8 +68,16 @@ public class BackgroundAppState extends OverviewState {
|
||||
if (taskCount == 0) {
|
||||
return super.getOverviewScaleAndTranslation(launcher);
|
||||
}
|
||||
TaskView dummyTask = recentsView.getTaskViewAt(Utilities.boundToRange(
|
||||
recentsView.getCurrentPage(), 0, taskCount - 1));
|
||||
TaskView dummyTask;
|
||||
if (recentsView.getCurrentPage() >= 0) {
|
||||
if (recentsView.getCurrentPage() <= taskCount - 1) {
|
||||
dummyTask = recentsView.getCurrentPageTaskView();
|
||||
} else {
|
||||
dummyTask = recentsView.getTaskViewAt(taskCount - 1);
|
||||
}
|
||||
} else {
|
||||
dummyTask = recentsView.getTaskViewAt(0);
|
||||
}
|
||||
return recentsView.getTempClipAnimationHelper().updateForFullscreenOverview(dummyTask)
|
||||
.getScaleAndTranslation();
|
||||
}
|
||||
@@ -91,7 +98,7 @@ public class BackgroundAppState extends OverviewState {
|
||||
if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
|
||||
// Translate hotseat offscreen if we show it in overview.
|
||||
ScaleAndTranslation scaleAndTranslation = super.getHotseatScaleAndTranslation(launcher);
|
||||
scaleAndTranslation.translationY = LayoutUtils.getShelfTrackingDistance(launcher,
|
||||
scaleAndTranslation.translationY += LayoutUtils.getShelfTrackingDistance(launcher,
|
||||
launcher.getDeviceProfile());
|
||||
return scaleAndTranslation;
|
||||
}
|
||||
|
||||
+17
-12
@@ -22,6 +22,7 @@ import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
|
||||
@@ -32,7 +33,6 @@ import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
|
||||
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
|
||||
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
|
||||
@@ -91,8 +92,19 @@ public class OverviewState extends LauncherState {
|
||||
@Override
|
||||
public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
|
||||
if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
|
||||
// If the hotseat icons are visible in overview, keep them in their normal position.
|
||||
return super.getWorkspaceScaleAndTranslation(launcher);
|
||||
DeviceProfile dp = launcher.getDeviceProfile();
|
||||
if (dp.allAppsIconSizePx >= dp.iconSizePx) {
|
||||
return new ScaleAndTranslation(1, 0, 0);
|
||||
} else {
|
||||
float scale = ((float) dp.allAppsIconSizePx) / dp.iconSizePx;
|
||||
// Distance between the screen center (which is the pivotY for hotseat) and the
|
||||
// bottom of the hotseat (which we want to preserve)
|
||||
float distanceFromBottom = dp.heightPx / 2 - dp.hotseatBarBottomPaddingPx;
|
||||
// On scaling, the bottom edge is moved closer to the pivotY. We move the
|
||||
// hotseat back down so that the bottom edge's position is preserved.
|
||||
float translationY = distanceFromBottom * (1 - scale);
|
||||
return new ScaleAndTranslation(scale, 0, translationY);
|
||||
}
|
||||
}
|
||||
return getWorkspaceScaleAndTranslation(launcher);
|
||||
}
|
||||
@@ -160,15 +172,7 @@ public class OverviewState extends LauncherState {
|
||||
}
|
||||
|
||||
public static float getDefaultSwipeHeight(Launcher launcher) {
|
||||
return getDefaultSwipeHeight(launcher, launcher.getDeviceProfile());
|
||||
}
|
||||
|
||||
public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) {
|
||||
float swipeHeight = dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
|
||||
if (SysUINavigationMode.getMode(context) == SysUINavigationMode.Mode.NO_BUTTON) {
|
||||
swipeHeight -= dp.getInsets().bottom;
|
||||
}
|
||||
return swipeHeight;
|
||||
return LayoutUtils.getDefaultSwipeHeight(launcher, launcher.getDeviceProfile());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -202,6 +206,7 @@ public class OverviewState extends LauncherState {
|
||||
builder.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
|
||||
builder.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
|
||||
builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
|
||||
builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, OVERSHOOT_1_7);
|
||||
builder.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
|
||||
}
|
||||
}
|
||||
|
||||
+50
-25
@@ -16,39 +16,37 @@
|
||||
|
||||
package com.android.launcher3.uioverrides.touchcontrollers;
|
||||
|
||||
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_PAUSE_TO_OVERVIEW_ANIM;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
|
||||
import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
|
||||
import static com.android.launcher3.LauncherStateManager.ATOMIC_OVERVIEW_PEEK_COMPONENT;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppTransitionManagerImpl;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.quickstep.OverviewInteractionState;
|
||||
import com.android.quickstep.util.MotionPauseDetector;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
@@ -77,7 +75,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
|
||||
@Override
|
||||
protected long getAtomicDuration() {
|
||||
return 300;
|
||||
return LauncherAppTransitionManagerImpl.ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,8 +103,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
}
|
||||
});
|
||||
mPeekAnim.start();
|
||||
recentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
|
||||
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
|
||||
VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
|
||||
|
||||
mLauncher.getDragLayer().getScrim().animateToSysuiMultiplier(isPaused ? 0 : 1,
|
||||
peekDuration, 0);
|
||||
@@ -131,16 +128,33 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
// Fade in prediction icons quickly, then rest of all apps after reaching overview.
|
||||
float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher)
|
||||
- OVERVIEW.getVerticalProgress(mLauncher);
|
||||
builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(ACCEL,
|
||||
0, ALL_APPS_CONTENT_FADE_THRESHOLD));
|
||||
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(LINEAR,
|
||||
progressToReachOverview, 1));
|
||||
builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
|
||||
ACCEL,
|
||||
0,
|
||||
ALL_APPS_CONTENT_FADE_THRESHOLD));
|
||||
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
|
||||
ACCEL,
|
||||
progressToReachOverview,
|
||||
progressToReachOverview + ALL_APPS_CONTENT_FADE_THRESHOLD));
|
||||
|
||||
// Get workspace out of the way quickly, to prepare for potential pause.
|
||||
builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3);
|
||||
builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, DEACCEL_3);
|
||||
builder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_3);
|
||||
return builder;
|
||||
} else if (fromState == ALL_APPS && toState == NORMAL) {
|
||||
AnimatorSetBuilder builder = new AnimatorSetBuilder();
|
||||
// Keep all apps/predictions opaque until the very end of the transition.
|
||||
float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher);
|
||||
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
|
||||
DEACCEL,
|
||||
progressToReachOverview - ALL_APPS_CONTENT_FADE_THRESHOLD,
|
||||
progressToReachOverview));
|
||||
builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
|
||||
DEACCEL,
|
||||
1 - ALL_APPS_CONTENT_FADE_THRESHOLD,
|
||||
1));
|
||||
return builder;
|
||||
}
|
||||
return super.getAnimatorSetBuilderForStates(fromState, toState);
|
||||
}
|
||||
@@ -155,20 +169,14 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity, boolean fling) {
|
||||
public void onDragEnd(float velocity) {
|
||||
if (mMotionPauseDetector.isPaused() && handlingOverviewAnim()) {
|
||||
if (mPeekAnim != null) {
|
||||
mPeekAnim.cancel();
|
||||
}
|
||||
|
||||
AnimatorSetBuilder builder = new AnimatorSetBuilder();
|
||||
builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
|
||||
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
|
||||
builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
|
||||
builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
|
||||
}
|
||||
AnimatorSet overviewAnim = mLauncher.getStateManager().createAtomicAnimation(
|
||||
NORMAL, OVERVIEW, builder, ANIM_ALL, ATOMIC_DURATION);
|
||||
Animator overviewAnim = mLauncher.getAppTransitionManager().createStateElementAnimation(
|
||||
INDEX_PAUSE_TO_OVERVIEW_ANIM);
|
||||
overviewAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
@@ -177,7 +185,12 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
});
|
||||
overviewAnim.start();
|
||||
} else {
|
||||
super.onDragEnd(velocity, fling);
|
||||
super.onDragEnd(velocity);
|
||||
}
|
||||
|
||||
View searchView = mLauncher.getAppsView().getSearchView();
|
||||
if (searchView instanceof FeedbackHandler) {
|
||||
((FeedbackHandler) searchView).resetFeedback();
|
||||
}
|
||||
mMotionPauseDetector.clear();
|
||||
}
|
||||
@@ -205,4 +218,16 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for views with feedback animation requiring reset
|
||||
*/
|
||||
public interface FeedbackHandler {
|
||||
|
||||
/**
|
||||
* reset searchWidget feedback
|
||||
*/
|
||||
void resetFeedback();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-6
@@ -23,6 +23,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
import static com.android.launcher3.touch.AbstractStateChangeTouchController.SUCCESS_TRANSITION_PROGRESS;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
@@ -43,21 +44,25 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
import com.android.launcher3.config.BaseFlags;
|
||||
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.quickstep.util.AssistantUtilities;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
|
||||
/**
|
||||
* Handles swiping up on the nav bar to go home from launcher, e.g. overview or all apps.
|
||||
*/
|
||||
public class NavBarToHomeTouchController implements TouchController, SwipeDetector.Listener {
|
||||
public class NavBarToHomeTouchController implements TouchController,
|
||||
SingleAxisSwipeDetector.Listener {
|
||||
|
||||
private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL_3;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final SwipeDetector mSwipeDetector;
|
||||
private final SingleAxisSwipeDetector mSwipeDetector;
|
||||
private final float mPullbackDistance;
|
||||
|
||||
private boolean mNoIntercept;
|
||||
@@ -67,7 +72,8 @@ public class NavBarToHomeTouchController implements TouchController, SwipeDetect
|
||||
|
||||
public NavBarToHomeTouchController(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
mSwipeDetector = new SwipeDetector(mLauncher, this, SwipeDetector.VERTICAL);
|
||||
mSwipeDetector = new SingleAxisSwipeDetector(mLauncher, this,
|
||||
SingleAxisSwipeDetector.VERTICAL);
|
||||
mPullbackDistance = mLauncher.getResources().getDimension(R.dimen.home_pullback_distance);
|
||||
}
|
||||
|
||||
@@ -79,7 +85,8 @@ public class NavBarToHomeTouchController implements TouchController, SwipeDetect
|
||||
if (mNoIntercept) {
|
||||
return false;
|
||||
}
|
||||
mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false);
|
||||
mSwipeDetector.setDetectableScrollConditions(SingleAxisSwipeDetector.DIRECTION_POSITIVE,
|
||||
false /* ignoreSlop */);
|
||||
}
|
||||
|
||||
if (mNoIntercept) {
|
||||
@@ -101,6 +108,10 @@ public class NavBarToHomeTouchController implements TouchController, SwipeDetect
|
||||
if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
|
||||
return true;
|
||||
}
|
||||
if (BaseFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
|
||||
&& AssistantUtilities.isExcludedAssistantRunning()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -173,7 +184,8 @@ public class NavBarToHomeTouchController implements TouchController, SwipeDetect
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity, boolean fling) {
|
||||
public void onDragEnd(float velocity) {
|
||||
boolean fling = mSwipeDetector.isFling(velocity);
|
||||
final int logAction = fling ? Touch.FLING : Touch.SWIPE;
|
||||
float progress = mCurrentAnimation.getProgressFraction();
|
||||
float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(progress);
|
||||
@@ -190,6 +202,8 @@ public class NavBarToHomeTouchController implements TouchController, SwipeDetect
|
||||
AbstractFloatingView.closeAllOpenViews(mLauncher);
|
||||
logStateChange(topOpenView.getLogContainerType(), logAction);
|
||||
}
|
||||
ActivityManagerWrapper.getInstance()
|
||||
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
||||
} else {
|
||||
// Quickly return to the state we came from (we didn't move far).
|
||||
ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
|
||||
|
||||
+473
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* 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.touchcontrollers;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_PAUSE_TO_OVERVIEW_ANIM;
|
||||
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.QUICK_SWITCH;
|
||||
import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
|
||||
import static com.android.launcher3.anim.AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
|
||||
import static com.android.launcher3.anim.AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_5;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
|
||||
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
|
||||
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
|
||||
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.CANCEL;
|
||||
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
|
||||
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
|
||||
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.PointF;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.LauncherStateManager.AnimationConfig;
|
||||
import com.android.launcher3.QuickstepAppTransitionManagerImpl;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.graphics.OverviewScrim;
|
||||
import com.android.launcher3.touch.BaseSwipeDetector;
|
||||
import com.android.launcher3.touch.BothAxesSwipeDetector;
|
||||
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.TouchController;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.quickstep.OverviewInteractionState;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.util.MotionPauseDetector;
|
||||
import com.android.quickstep.util.ShelfPeekAnim;
|
||||
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
|
||||
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
||||
import com.android.quickstep.views.LauncherRecentsView;
|
||||
|
||||
/**
|
||||
* Handles quick switching to a recent task from the home screen. To give as much flexibility to
|
||||
* the user as possible, also handles swipe up and hold to go to overview and swiping back home.
|
||||
*/
|
||||
public class NoButtonQuickSwitchTouchController implements TouchController,
|
||||
BothAxesSwipeDetector.Listener, MotionPauseDetector.OnMotionPauseListener {
|
||||
|
||||
/** The minimum progress of the scale/translationY animation until drag end. */
|
||||
private static final float Y_ANIM_MIN_PROGRESS = 0.15f;
|
||||
private static final Interpolator FADE_OUT_INTERPOLATOR = DEACCEL_5;
|
||||
private static final Interpolator TRANSLATE_OUT_INTERPOLATOR = ACCEL_0_75;
|
||||
private static final Interpolator SCALE_DOWN_INTERPOLATOR = DEACCEL;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final BothAxesSwipeDetector mSwipeDetector;
|
||||
private final float mXRange;
|
||||
private final float mYRange;
|
||||
private final MotionPauseDetector mMotionPauseDetector;
|
||||
private final float mMotionPauseMinDisplacement;
|
||||
|
||||
private boolean mNoIntercept;
|
||||
private LauncherState mStartState;
|
||||
|
||||
private ShelfPeekAnim mShelfPeekAnim;
|
||||
private boolean mIsHomeScreenVisible = true;
|
||||
|
||||
// As we drag, we control 3 animations: one to get non-overview components out of the way,
|
||||
// and the other two to set overview properties based on x and y progress.
|
||||
private AnimatorPlaybackController mNonOverviewAnim;
|
||||
private AnimatorPlaybackController mXOverviewAnim;
|
||||
private AnimatorPlaybackController mYOverviewAnim;
|
||||
|
||||
public NoButtonQuickSwitchTouchController(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
mSwipeDetector = new BothAxesSwipeDetector(mLauncher, this);
|
||||
mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
|
||||
mYRange = LayoutUtils.getShelfTrackingDistance(mLauncher, mLauncher.getDeviceProfile());
|
||||
mMotionPauseDetector = new MotionPauseDetector(mLauncher);
|
||||
mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
|
||||
R.dimen.motion_pause_detector_min_displacement_from_app);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mNoIntercept = !canInterceptTouch(ev);
|
||||
if (mNoIntercept) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only detect horizontal swipe for intercept, then we will allow swipe up as well.
|
||||
mSwipeDetector.setDetectableScrollConditions(DIRECTION_RIGHT,
|
||||
false /* ignoreSlopWhenSettling */);
|
||||
}
|
||||
|
||||
if (mNoIntercept) {
|
||||
return false;
|
||||
}
|
||||
|
||||
onControllerTouchEvent(ev);
|
||||
return mSwipeDetector.isDraggingOrSettling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onControllerTouchEvent(MotionEvent ev) {
|
||||
return mSwipeDetector.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
private boolean canInterceptTouch(MotionEvent ev) {
|
||||
if (!mLauncher.isInState(LauncherState.NORMAL)) {
|
||||
return false;
|
||||
}
|
||||
if ((ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0) {
|
||||
return false;
|
||||
}
|
||||
int stateFlags = OverviewInteractionState.INSTANCE.get(mLauncher).getSystemUiStateFlags();
|
||||
if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
mMotionPauseDetector.clear();
|
||||
if (start) {
|
||||
mShelfPeekAnim = ((QuickstepAppTransitionManagerImpl) mLauncher
|
||||
.getAppTransitionManager()).getShelfPeekAnim();
|
||||
|
||||
mStartState = mLauncher.getStateManager().getState();
|
||||
|
||||
mMotionPauseDetector.setOnMotionPauseListener(this);
|
||||
|
||||
// We have detected horizontal drag start, now allow swipe up as well.
|
||||
mSwipeDetector.setDetectableScrollConditions(DIRECTION_RIGHT | DIRECTION_UP,
|
||||
false /* ignoreSlopWhenSettling */);
|
||||
|
||||
setupAnimators();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMotionPauseChanged(boolean isPaused) {
|
||||
ShelfAnimState shelfState = isPaused ? PEEK : HIDE;
|
||||
if (shelfState == PEEK) {
|
||||
// Some shelf elements (e.g. qsb) were hidden, but we need them visible when peeking.
|
||||
AnimatorSetBuilder builder = new AnimatorSetBuilder();
|
||||
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
|
||||
allAppsController.setAlphas(NORMAL.getVisibleElements(mLauncher),
|
||||
new AnimationConfig(), builder);
|
||||
builder.build().setDuration(0).start();
|
||||
|
||||
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
|
||||
// Hotseat was hidden, but we need it visible when peeking.
|
||||
mLauncher.getHotseat().setAlpha(1);
|
||||
}
|
||||
}
|
||||
mShelfPeekAnim.setShelfState(shelfState, ShelfPeekAnim.INTERPOLATOR,
|
||||
ShelfPeekAnim.DURATION);
|
||||
VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
|
||||
}
|
||||
|
||||
private void setupAnimators() {
|
||||
// Animate the non-overview components (e.g. workspace, shelf) out of the way.
|
||||
AnimatorSetBuilder nonOverviewBuilder = new AnimatorSetBuilder();
|
||||
nonOverviewBuilder.setInterpolator(ANIM_WORKSPACE_FADE, FADE_OUT_INTERPOLATOR);
|
||||
nonOverviewBuilder.setInterpolator(ANIM_ALL_APPS_FADE, FADE_OUT_INTERPOLATOR);
|
||||
nonOverviewBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, TRANSLATE_OUT_INTERPOLATOR);
|
||||
nonOverviewBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, TRANSLATE_OUT_INTERPOLATOR);
|
||||
updateNonOverviewAnim(QUICK_SWITCH, nonOverviewBuilder, ANIM_ALL);
|
||||
mNonOverviewAnim.dispatchOnStart();
|
||||
|
||||
setupOverviewAnimators();
|
||||
}
|
||||
|
||||
/** Create state animation to control non-overview components. */
|
||||
private void updateNonOverviewAnim(LauncherState toState, AnimatorSetBuilder builder,
|
||||
@LauncherStateManager.AnimationComponents int animComponents) {
|
||||
builder.addFlag(FLAG_DONT_ANIMATE_OVERVIEW);
|
||||
long accuracy = (long) (Math.max(mXRange, mYRange) * 2);
|
||||
mNonOverviewAnim = mLauncher.getStateManager().createAnimationToNewWorkspace(toState,
|
||||
builder, accuracy, this::clearState, animComponents);
|
||||
}
|
||||
|
||||
private void setupOverviewAnimators() {
|
||||
final LauncherState fromState = QUICK_SWITCH;
|
||||
final LauncherState toState = OVERVIEW;
|
||||
LauncherState.ScaleAndTranslation fromScaleAndTranslation = fromState
|
||||
.getOverviewScaleAndTranslation(mLauncher);
|
||||
LauncherState.ScaleAndTranslation toScaleAndTranslation = toState
|
||||
.getOverviewScaleAndTranslation(mLauncher);
|
||||
// Update RecentView's translationX to have it start offscreen.
|
||||
LauncherRecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
float startScale = Utilities.mapRange(
|
||||
SCALE_DOWN_INTERPOLATOR.getInterpolation(Y_ANIM_MIN_PROGRESS),
|
||||
fromScaleAndTranslation.scale,
|
||||
toScaleAndTranslation.scale);
|
||||
fromScaleAndTranslation.translationX = recentsView.getOffscreenTranslationX(startScale);
|
||||
|
||||
// Set RecentView's initial properties.
|
||||
recentsView.setScaleX(fromScaleAndTranslation.scale);
|
||||
recentsView.setScaleY(fromScaleAndTranslation.scale);
|
||||
recentsView.setTranslationX(fromScaleAndTranslation.translationX);
|
||||
recentsView.setTranslationY(fromScaleAndTranslation.translationY);
|
||||
recentsView.setContentAlpha(1);
|
||||
|
||||
// As we drag right, animate the following properties:
|
||||
// - RecentsView translationX
|
||||
// - OverviewScrim
|
||||
AnimatorSet xOverviewAnim = new AnimatorSet();
|
||||
xOverviewAnim.play(ObjectAnimator.ofFloat(recentsView, View.TRANSLATION_X,
|
||||
toScaleAndTranslation.translationX));
|
||||
xOverviewAnim.play(ObjectAnimator.ofFloat(
|
||||
mLauncher.getDragLayer().getOverviewScrim(), OverviewScrim.SCRIM_PROGRESS,
|
||||
toState.getOverviewScrimAlpha(mLauncher)));
|
||||
long xAccuracy = (long) (mXRange * 2);
|
||||
xOverviewAnim.setDuration(xAccuracy);
|
||||
mXOverviewAnim = AnimatorPlaybackController.wrap(xOverviewAnim, xAccuracy);
|
||||
mXOverviewAnim.dispatchOnStart();
|
||||
|
||||
// As we drag up, animate the following properties:
|
||||
// - RecentsView translationY
|
||||
// - RecentsView scale
|
||||
// - RecentsView fullscreenProgress
|
||||
AnimatorSet yAnimation = new AnimatorSet();
|
||||
Animator translateYAnim = ObjectAnimator.ofFloat(recentsView, View.TRANSLATION_Y,
|
||||
toScaleAndTranslation.translationY);
|
||||
Animator scaleAnim = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY,
|
||||
toScaleAndTranslation.scale);
|
||||
Animator fullscreenProgressAnim = ObjectAnimator.ofFloat(recentsView, FULLSCREEN_PROGRESS,
|
||||
fromState.getOverviewFullscreenProgress(), toState.getOverviewFullscreenProgress());
|
||||
scaleAnim.setInterpolator(SCALE_DOWN_INTERPOLATOR);
|
||||
fullscreenProgressAnim.setInterpolator(SCALE_DOWN_INTERPOLATOR);
|
||||
yAnimation.play(translateYAnim);
|
||||
yAnimation.play(scaleAnim);
|
||||
yAnimation.play(fullscreenProgressAnim);
|
||||
long yAccuracy = (long) (mYRange * 2);
|
||||
yAnimation.setDuration(yAccuracy);
|
||||
mYOverviewAnim = AnimatorPlaybackController.wrap(yAnimation, yAccuracy);
|
||||
mYOverviewAnim.dispatchOnStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrag(PointF displacement, MotionEvent ev) {
|
||||
float xProgress = Math.max(0, displacement.x) / mXRange;
|
||||
float yProgress = Math.max(0, -displacement.y) / mYRange;
|
||||
yProgress = Utilities.mapRange(yProgress, Y_ANIM_MIN_PROGRESS, 1f);
|
||||
|
||||
boolean wasHomeScreenVisible = mIsHomeScreenVisible;
|
||||
if (wasHomeScreenVisible && mNonOverviewAnim != null) {
|
||||
mNonOverviewAnim.setPlayFraction(xProgress);
|
||||
}
|
||||
mIsHomeScreenVisible = FADE_OUT_INTERPOLATOR.getInterpolation(xProgress)
|
||||
<= 1 - ALPHA_CUTOFF_THRESHOLD;
|
||||
|
||||
if (wasHomeScreenVisible && !mIsHomeScreenVisible) {
|
||||
// Get the shelf all the way offscreen so it pops up when we decide to peek it.
|
||||
mShelfPeekAnim.setShelfState(HIDE, LINEAR, 0);
|
||||
}
|
||||
|
||||
// Only allow motion pause if the home screen is invisible, since some
|
||||
// home screen elements will appear in the shelf on motion pause.
|
||||
mMotionPauseDetector.setDisallowPause(mIsHomeScreenVisible
|
||||
|| -displacement.y < mMotionPauseMinDisplacement);
|
||||
mMotionPauseDetector.addPosition(displacement.y, ev.getEventTime());
|
||||
|
||||
if (mIsHomeScreenVisible) {
|
||||
// Cancel the shelf anim so it doesn't clobber mNonOverviewAnim.
|
||||
mShelfPeekAnim.setShelfState(CANCEL, LINEAR, 0);
|
||||
}
|
||||
|
||||
if (mXOverviewAnim != null) {
|
||||
mXOverviewAnim.setPlayFraction(xProgress);
|
||||
}
|
||||
if (mYOverviewAnim != null) {
|
||||
mYOverviewAnim.setPlayFraction(yProgress);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd(PointF velocity) {
|
||||
boolean horizontalFling = mSwipeDetector.isFling(velocity.x);
|
||||
boolean verticalFling = mSwipeDetector.isFling(velocity.y);
|
||||
boolean noFling = !horizontalFling && !verticalFling;
|
||||
int logAction = noFling ? Touch.SWIPE : Touch.FLING;
|
||||
if (mMotionPauseDetector.isPaused() && noFling) {
|
||||
cancelAnimations();
|
||||
|
||||
Animator overviewAnim = mLauncher.getAppTransitionManager().createStateElementAnimation(
|
||||
INDEX_PAUSE_TO_OVERVIEW_ANIM);
|
||||
overviewAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
onAnimationToStateCompleted(OVERVIEW, logAction);
|
||||
}
|
||||
});
|
||||
overviewAnim.start();
|
||||
return;
|
||||
}
|
||||
|
||||
final LauncherState targetState;
|
||||
if (horizontalFling && verticalFling) {
|
||||
if (velocity.x < 0) {
|
||||
// Flinging left and up or down both go back home.
|
||||
targetState = NORMAL;
|
||||
} else {
|
||||
if (velocity.y > 0) {
|
||||
// Flinging right and down goes to quick switch.
|
||||
targetState = QUICK_SWITCH;
|
||||
} else {
|
||||
// Flinging up and right could go either home or to quick switch.
|
||||
// Determine the target based on the higher velocity.
|
||||
targetState = Math.abs(velocity.x) > Math.abs(velocity.y)
|
||||
? QUICK_SWITCH : NORMAL;
|
||||
}
|
||||
}
|
||||
} else if (horizontalFling) {
|
||||
targetState = velocity.x > 0 ? QUICK_SWITCH : NORMAL;
|
||||
} else if (verticalFling) {
|
||||
targetState = velocity.y > 0 ? QUICK_SWITCH : NORMAL;
|
||||
} else {
|
||||
// If user isn't flinging, just snap to the closest state based on x progress.
|
||||
boolean passedHorizontalThreshold = mXOverviewAnim.getInterpolatedProgress() > 0.5f;
|
||||
targetState = passedHorizontalThreshold ? QUICK_SWITCH : NORMAL;
|
||||
}
|
||||
|
||||
// Animate the various components to the target state.
|
||||
|
||||
float xProgress = mXOverviewAnim.getProgressFraction();
|
||||
float startXProgress = Utilities.boundToRange(xProgress
|
||||
+ velocity.x * getSingleFrameMs(mLauncher) / mXRange, 0f, 1f);
|
||||
final float endXProgress = targetState == NORMAL ? 0 : 1;
|
||||
long xDuration = BaseSwipeDetector.calculateDuration(velocity.x,
|
||||
Math.abs(endXProgress - startXProgress));
|
||||
ValueAnimator xOverviewAnim = mXOverviewAnim.getAnimationPlayer();
|
||||
xOverviewAnim.setFloatValues(startXProgress, endXProgress);
|
||||
xOverviewAnim.setDuration(xDuration)
|
||||
.setInterpolator(scrollInterpolatorForVelocity(velocity.x));
|
||||
mXOverviewAnim.dispatchOnStartWithVelocity(endXProgress, velocity.x);
|
||||
|
||||
boolean flingUpToNormal = verticalFling && velocity.y < 0 && targetState == NORMAL;
|
||||
|
||||
float yProgress = mYOverviewAnim.getProgressFraction();
|
||||
float startYProgress = Utilities.boundToRange(yProgress
|
||||
- velocity.y * getSingleFrameMs(mLauncher) / mYRange, 0f, 1f);
|
||||
final float endYProgress;
|
||||
if (flingUpToNormal) {
|
||||
endYProgress = 1;
|
||||
} else if (targetState == NORMAL) {
|
||||
// Keep overview at its current scale/translationY as it slides off the screen.
|
||||
endYProgress = startYProgress;
|
||||
} else {
|
||||
endYProgress = 0;
|
||||
}
|
||||
long yDuration = BaseSwipeDetector.calculateDuration(velocity.y,
|
||||
Math.abs(endYProgress - startYProgress));
|
||||
ValueAnimator yOverviewAnim = mYOverviewAnim.getAnimationPlayer();
|
||||
yOverviewAnim.setFloatValues(startYProgress, endYProgress);
|
||||
yOverviewAnim.setDuration(yDuration);
|
||||
mYOverviewAnim.dispatchOnStartWithVelocity(endYProgress, velocity.y);
|
||||
|
||||
ValueAnimator nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer();
|
||||
if (flingUpToNormal && !mIsHomeScreenVisible) {
|
||||
// We are flinging to home while workspace is invisible, run the same staggered
|
||||
// animation as from an app.
|
||||
// Update mNonOverviewAnim to do nothing so it doesn't interfere.
|
||||
updateNonOverviewAnim(targetState, new AnimatorSetBuilder(), 0 /* animComponents */);
|
||||
nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer();
|
||||
|
||||
new StaggeredWorkspaceAnim(mLauncher, velocity.y, false /* animateOverviewScrim */)
|
||||
.start();
|
||||
} else {
|
||||
boolean canceled = targetState == NORMAL;
|
||||
if (canceled) {
|
||||
// Let the state manager know that the animation didn't go to the target state,
|
||||
// but don't clean up yet (we already clean up when the animation completes).
|
||||
mNonOverviewAnim.dispatchOnCancelWithoutCancelRunnable();
|
||||
}
|
||||
float startProgress = mNonOverviewAnim.getProgressFraction();
|
||||
float endProgress = canceled ? 0 : 1;
|
||||
nonOverviewAnim.setFloatValues(startProgress, endProgress);
|
||||
mNonOverviewAnim.dispatchOnStartWithVelocity(endProgress,
|
||||
horizontalFling ? velocity.x : velocity.y);
|
||||
}
|
||||
|
||||
nonOverviewAnim.setDuration(Math.max(xDuration, yDuration));
|
||||
mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState, logAction));
|
||||
|
||||
cancelAnimations();
|
||||
xOverviewAnim.start();
|
||||
yOverviewAnim.start();
|
||||
nonOverviewAnim.start();
|
||||
}
|
||||
|
||||
private void onAnimationToStateCompleted(LauncherState targetState, int logAction) {
|
||||
mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
|
||||
getDirectionForLog(), mSwipeDetector.getDownX(), mSwipeDetector.getDownY(),
|
||||
LauncherLogProto.ContainerType.NAVBAR,
|
||||
mStartState.containerType,
|
||||
targetState.containerType,
|
||||
mLauncher.getWorkspace().getCurrentPage());
|
||||
mLauncher.getStateManager().goToState(targetState, false, this::clearState);
|
||||
}
|
||||
|
||||
private int getDirectionForLog() {
|
||||
return Utilities.isRtl(mLauncher.getResources()) ? Direction.LEFT : Direction.RIGHT;
|
||||
}
|
||||
|
||||
private void cancelAnimations() {
|
||||
if (mNonOverviewAnim != null) {
|
||||
mNonOverviewAnim.getAnimationPlayer().cancel();
|
||||
}
|
||||
if (mXOverviewAnim != null) {
|
||||
mXOverviewAnim.getAnimationPlayer().cancel();
|
||||
}
|
||||
if (mYOverviewAnim != null) {
|
||||
mYOverviewAnim.getAnimationPlayer().cancel();
|
||||
}
|
||||
mShelfPeekAnim.setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
|
||||
mMotionPauseDetector.clear();
|
||||
}
|
||||
|
||||
private void clearState() {
|
||||
cancelAnimations();
|
||||
mNonOverviewAnim = null;
|
||||
mXOverviewAnim = null;
|
||||
mYOverviewAnim = null;
|
||||
mIsHomeScreenVisible = true;
|
||||
mSwipeDetector.finishedScrolling();
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -47,9 +47,9 @@ public final class PortraitOverviewStateTouchHelper {
|
||||
* @return true if we should intercept the motion event
|
||||
*/
|
||||
boolean canInterceptTouch(MotionEvent ev) {
|
||||
if (mRecentsView.getChildCount() > 0) {
|
||||
if (mRecentsView.getTaskViewCount() > 0) {
|
||||
// Allow swiping up in the gap between the hotseat and overview.
|
||||
return ev.getY() >= mRecentsView.getChildAt(0).getBottom();
|
||||
return ev.getY() >= mRecentsView.getTaskViewAt(0).getBottom();
|
||||
} else {
|
||||
// If there are no tasks, we only intercept if we're below the hotseat height.
|
||||
return isTouchOverHotseat(mLauncher, ev);
|
||||
@@ -63,7 +63,7 @@ public final class PortraitOverviewStateTouchHelper {
|
||||
* @return true if going back should take the user to the currently running task
|
||||
*/
|
||||
boolean shouldSwipeDownReturnToApp() {
|
||||
TaskView taskView = mRecentsView.getTaskViewAt(mRecentsView.getNextPage());
|
||||
TaskView taskView = mRecentsView.getNextPageTaskView();
|
||||
return taskView != null && mRecentsView.shouldSwipeDownLaunchApp();
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public final class PortraitOverviewStateTouchHelper {
|
||||
*/
|
||||
PendingAnimation createSwipeDownToTaskAppAnimation(long duration) {
|
||||
mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen());
|
||||
TaskView taskView = mRecentsView.getTaskViewAt(mRecentsView.getCurrentPage());
|
||||
TaskView taskView = mRecentsView.getCurrentPageTaskView();
|
||||
if (taskView == null) {
|
||||
throw new IllegalStateException("There is no task view to animate to.");
|
||||
}
|
||||
|
||||
+7
-4
@@ -30,6 +30,7 @@ import static com.android.launcher3.anim.Interpolators.INSTANT;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
|
||||
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
@@ -42,7 +43,7 @@ import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.touch.AbstractStateChangeTouchController;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.quickstep.OverviewInteractionState;
|
||||
@@ -50,7 +51,7 @@ import com.android.quickstep.SysUINavigationMode;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
|
||||
/**
|
||||
* Handles quick switching to a recent task from the home screen.
|
||||
@@ -60,10 +61,10 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll
|
||||
private @Nullable TaskView mTaskToLaunch;
|
||||
|
||||
public QuickSwitchTouchController(Launcher launcher) {
|
||||
this(launcher, SwipeDetector.HORIZONTAL);
|
||||
this(launcher, SingleAxisSwipeDetector.HORIZONTAL);
|
||||
}
|
||||
|
||||
protected QuickSwitchTouchController(Launcher l, SwipeDetector.Direction dir) {
|
||||
protected QuickSwitchTouchController(Launcher l, SingleAxisSwipeDetector.Direction dir) {
|
||||
super(l, dir);
|
||||
}
|
||||
|
||||
@@ -95,6 +96,8 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll
|
||||
super.onDragStart(start);
|
||||
mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
|
||||
mTaskToLaunch = mLauncher.<RecentsView>getOverviewPanel().getTaskViewAt(0);
|
||||
ActivityManagerWrapper.getInstance()
|
||||
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+17
-13
@@ -19,6 +19,9 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
|
||||
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
|
||||
import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_BOTH;
|
||||
import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGATIVE;
|
||||
import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_POSITIVE;
|
||||
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -32,7 +35,8 @@ import com.android.launcher3.LauncherAnimUtils;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
import com.android.launcher3.touch.BaseSwipeDetector;
|
||||
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.FlingBlockCheck;
|
||||
import com.android.launcher3.util.PendingAnimation;
|
||||
@@ -46,15 +50,14 @@ import com.android.quickstep.views.TaskView;
|
||||
* Touch controller for handling task view card swipes
|
||||
*/
|
||||
public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
extends AnimatorListenerAdapter implements TouchController, SwipeDetector.Listener {
|
||||
|
||||
private static final String TAG = "OverviewSwipeController";
|
||||
extends AnimatorListenerAdapter implements TouchController,
|
||||
SingleAxisSwipeDetector.Listener {
|
||||
|
||||
// Progress after which the transition is assumed to be a success in case user does not fling
|
||||
public static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
|
||||
|
||||
protected final T mActivity;
|
||||
private final SwipeDetector mDetector;
|
||||
private final SingleAxisSwipeDetector mDetector;
|
||||
private final RecentsView mRecentsView;
|
||||
private final int[] mTempCords = new int[2];
|
||||
|
||||
@@ -74,7 +77,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
public TaskViewTouchController(T activity) {
|
||||
mActivity = activity;
|
||||
mRecentsView = activity.getOverviewPanel();
|
||||
mDetector = new SwipeDetector(activity, this, SwipeDetector.VERTICAL);
|
||||
mDetector = new SingleAxisSwipeDetector(activity, this, SingleAxisSwipeDetector.VERTICAL);
|
||||
}
|
||||
|
||||
private boolean canInterceptTouch() {
|
||||
@@ -113,7 +116,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
int directionsToDetectScroll = 0;
|
||||
boolean ignoreSlopWhenSettling = false;
|
||||
if (mCurrentAnimation != null) {
|
||||
directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
|
||||
directionsToDetectScroll = DIRECTION_BOTH;
|
||||
ignoreSlopWhenSettling = true;
|
||||
} else {
|
||||
mTaskBeingDragged = null;
|
||||
@@ -126,12 +129,12 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
if (!SysUINavigationMode.getMode(mActivity).hasGestures) {
|
||||
// Don't allow swipe down to open if we don't support swipe up
|
||||
// to enter overview.
|
||||
directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
|
||||
directionsToDetectScroll = DIRECTION_POSITIVE;
|
||||
} else {
|
||||
// The task can be dragged up to dismiss it,
|
||||
// and down to open if it's the current page.
|
||||
directionsToDetectScroll = i == mRecentsView.getCurrentPage()
|
||||
? SwipeDetector.DIRECTION_BOTH : SwipeDetector.DIRECTION_POSITIVE;
|
||||
? DIRECTION_BOTH : DIRECTION_POSITIVE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -165,8 +168,8 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
return;
|
||||
}
|
||||
int scrollDirections = mDetector.getScrollDirections();
|
||||
if (goingUp && ((scrollDirections & SwipeDetector.DIRECTION_POSITIVE) == 0)
|
||||
|| !goingUp && ((scrollDirections & SwipeDetector.DIRECTION_NEGATIVE) == 0)) {
|
||||
if (goingUp && ((scrollDirections & DIRECTION_POSITIVE) == 0)
|
||||
|| !goingUp && ((scrollDirections & DIRECTION_NEGATIVE) == 0)) {
|
||||
// Trying to re-init in an unsupported direction.
|
||||
return;
|
||||
}
|
||||
@@ -243,7 +246,8 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity, boolean fling) {
|
||||
public void onDragEnd(float velocity) {
|
||||
boolean fling = mDetector.isFling(velocity);
|
||||
final boolean goingToEnd;
|
||||
final int logAction;
|
||||
boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
|
||||
@@ -260,7 +264,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
|
||||
logAction = Touch.SWIPE;
|
||||
goingToEnd = interpolatedProgress > SUCCESS_TRANSITION_PROGRESS;
|
||||
}
|
||||
long animationDuration = SwipeDetector.calculateDuration(
|
||||
long animationDuration = BaseSwipeDetector.calculateDuration(
|
||||
velocity, goingToEnd ? (1 - progress) : progress);
|
||||
if (blockedFling && !goingToEnd) {
|
||||
animationDuration *= LauncherAnimUtils.blockedFlingDurationFactor(velocity);
|
||||
|
||||
+2
-2
@@ -17,12 +17,12 @@ package com.android.launcher3.uioverrides.touchcontrollers;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||
|
||||
public class TransposedQuickSwitchTouchController extends QuickSwitchTouchController {
|
||||
|
||||
public TransposedQuickSwitchTouchController(Launcher launcher) {
|
||||
super(launcher, SwipeDetector.VERTICAL);
|
||||
super(launcher, SingleAxisSwipeDetector.VERTICAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,16 +15,13 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static android.os.VibrationEffect.EFFECT_CLICK;
|
||||
import static android.os.VibrationEffect.createPredefined;
|
||||
|
||||
import static com.android.launcher3.Utilities.postAsyncCallback;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||
import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;
|
||||
import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR;
|
||||
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -39,14 +36,12 @@ import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
@@ -54,8 +49,8 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
|
||||
import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
|
||||
@@ -75,8 +70,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
/**
|
||||
* Base class for swipe up handler with some utility methods
|
||||
*/
|
||||
@@ -107,7 +100,6 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
protected final ClipAnimationHelper mClipAnimationHelper;
|
||||
protected final TransformParams mTransformParams = new TransformParams();
|
||||
|
||||
private final Vibrator mVibrator;
|
||||
protected final Mode mMode;
|
||||
|
||||
// Shift in the range of [0, 1].
|
||||
@@ -126,7 +118,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
|
||||
protected Runnable mGestureEndCallback;
|
||||
|
||||
protected final Handler mMainThreadHandler = MAIN_THREAD_EXECUTOR.getHandler();
|
||||
protected final Handler mMainThreadHandler = MAIN_EXECUTOR.getHandler();
|
||||
protected MultiStateCallback mStateCallback;
|
||||
|
||||
protected boolean mCanceled;
|
||||
@@ -148,7 +140,6 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
|
||||
mClipAnimationHelper = new ClipAnimationHelper(context);
|
||||
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
|
||||
mVibrator = context.getSystemService(Vibrator.class);
|
||||
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
|
||||
.getDeviceProfile(mContext));
|
||||
}
|
||||
@@ -162,19 +153,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
}
|
||||
|
||||
protected void performHapticFeedback() {
|
||||
if (!mVibrator.hasVibrator()) {
|
||||
return;
|
||||
}
|
||||
if (Settings.System.getInt(
|
||||
mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
VibrationEffect effect = createPredefined(EFFECT_CLICK);
|
||||
if (effect == null) {
|
||||
return;
|
||||
}
|
||||
BACKGROUND_EXECUTOR.execute(() -> mVibrator.vibrate(effect));
|
||||
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
|
||||
}
|
||||
|
||||
public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode rotationMode) {
|
||||
@@ -229,10 +208,10 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
// Launch the task user scrolled to (mRecentsView.getNextPage()).
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
// We finish recents animation inside launchTask() when live tile is enabled.
|
||||
mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false /* animate */,
|
||||
mRecentsView.getNextPageTaskView().launchTask(false /* animate */,
|
||||
true /* freezeTaskList */);
|
||||
} else {
|
||||
int taskId = mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).getTask().key.id;
|
||||
int taskId = mRecentsView.getNextPageTaskView().getTask().key.id;
|
||||
mFinishingRecentsAnimationForNewTaskId = taskId;
|
||||
mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
|
||||
if (!mCanceled) {
|
||||
@@ -275,7 +254,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
overviewStackBounds = getStackBounds(dp);
|
||||
}
|
||||
dp.updateInsets(targetSet.homeContentInsets);
|
||||
dp.updateIsSeascape(mContext.getSystemService(WindowManager.class));
|
||||
dp.updateIsSeascape(mContext);
|
||||
if (runningTaskTarget != null) {
|
||||
mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
|
||||
}
|
||||
|
||||
+14
-57
@@ -24,7 +24,6 @@ import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_SHELF
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.INSTANT;
|
||||
@@ -53,15 +52,15 @@ import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherInitListenerEx;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.QuickstepAppTransitionManagerImpl;
|
||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.uioverrides.states.OverviewState;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.util.ShelfPeekAnim;
|
||||
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
|
||||
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
||||
import com.android.quickstep.views.LauncherRecentsView;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
@@ -167,18 +166,8 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
|
||||
@Override
|
||||
public void playAtomicAnimation(float velocity) {
|
||||
// Setup workspace with 0 duration to prepare for our staggered animation.
|
||||
LauncherStateManager stateManager = activity.getStateManager();
|
||||
AnimatorSetBuilder builder = new AnimatorSetBuilder();
|
||||
// setRecentsAttachedToAppWindow() will animate recents out.
|
||||
builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW);
|
||||
stateManager.createAtomicAnimation(BACKGROUND_APP, NORMAL, builder, ANIM_ALL, 0);
|
||||
builder.build().start();
|
||||
|
||||
// Stop scrolling so that it doesn't interfere with the translation offscreen.
|
||||
recentsView.getScroller().forceFinished(true);
|
||||
|
||||
new StaggeredWorkspaceAnim(activity, workspaceView, velocity).start();
|
||||
new StaggeredWorkspaceAnim(activity, velocity, true /* animateOverviewScrim */)
|
||||
.start();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -201,7 +190,9 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
activity.getAppsView().reset(false /* animate */);
|
||||
|
||||
return new AnimationFactory() {
|
||||
private ShelfAnimState mShelfState;
|
||||
private final ShelfPeekAnim mShelfAnim =
|
||||
((QuickstepAppTransitionManagerImpl) activity.getAppTransitionManager())
|
||||
.getShelfPeekAnim();
|
||||
private boolean mIsAttachedToWindow;
|
||||
|
||||
@Override
|
||||
@@ -230,30 +221,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
@Override
|
||||
public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator,
|
||||
long duration) {
|
||||
if (mShelfState == shelfState) {
|
||||
return;
|
||||
}
|
||||
mShelfState = shelfState;
|
||||
activity.getStateManager().cancelStateElementAnimation(INDEX_SHELF_ANIM);
|
||||
if (mShelfState == ShelfAnimState.CANCEL) {
|
||||
return;
|
||||
}
|
||||
float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(activity);
|
||||
float shelfOverviewProgress = OVERVIEW.getVerticalProgress(activity);
|
||||
// Peek based on default overview progress so we can see hotseat if we're showing
|
||||
// that instead of predictions in overview.
|
||||
float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(activity);
|
||||
float shelfPeekingProgress = shelfHiddenProgress
|
||||
- (shelfHiddenProgress - defaultOverviewProgress) * 0.25f;
|
||||
float toProgress = mShelfState == ShelfAnimState.HIDE
|
||||
? shelfHiddenProgress
|
||||
: mShelfState == ShelfAnimState.PEEK
|
||||
? shelfPeekingProgress
|
||||
: shelfOverviewProgress;
|
||||
Animator shelfAnim = activity.getStateManager()
|
||||
.createStateElementAnimation(INDEX_SHELF_ANIM, toProgress);
|
||||
shelfAnim.setInterpolator(interpolator);
|
||||
shelfAnim.setDuration(duration).start();
|
||||
mShelfAnim.setShelfState(shelfState, interpolator, duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -268,22 +236,12 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
|
||||
|
||||
int runningTaskIndex = recentsView.getRunningTaskIndex();
|
||||
if (runningTaskIndex == 0) {
|
||||
if (runningTaskIndex == recentsView.getTaskViewStartIndex()) {
|
||||
// If we are on the first task (we haven't quick switched), translate recents in
|
||||
// from the side. Calculate the start translation based on current scale/scroll.
|
||||
float currScale = recentsView.getScaleX();
|
||||
float scrollOffsetX = recentsView.getScrollOffset();
|
||||
|
||||
float offscreenX = NORMAL.getOverviewScaleAndTranslation(activity).translationX;
|
||||
// The first task is hidden, so offset by its width.
|
||||
int firstTaskWidth = recentsView.getTaskViewAt(0).getWidth();
|
||||
offscreenX -= (firstTaskWidth + recentsView.getPageSpacing()) * currScale;
|
||||
// Offset since scale pushes tasks outwards.
|
||||
offscreenX += firstTaskWidth * (currScale - 1) / 2;
|
||||
offscreenX = Math.max(0, offscreenX);
|
||||
if (recentsView.isRtl()) {
|
||||
offscreenX = -offscreenX;
|
||||
}
|
||||
float offscreenX = recentsView.getOffscreenTranslationX(currScale);
|
||||
|
||||
float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0;
|
||||
float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX;
|
||||
@@ -351,8 +309,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
private void playScaleDownAnim(AnimatorSet anim, Launcher launcher, LauncherState fromState,
|
||||
LauncherState endState) {
|
||||
RecentsView recentsView = launcher.getOverviewPanel();
|
||||
TaskView v = recentsView.getTaskViewAt(recentsView.getCurrentPage());
|
||||
if (v == null) {
|
||||
if (recentsView.getCurrentPageTaskView() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -380,7 +337,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
// recents as a whole needs to translate further to keep up with the app window.
|
||||
TaskView runningTaskView = recentsView.getRunningTaskView();
|
||||
if (runningTaskView == null) {
|
||||
runningTaskView = recentsView.getTaskViewAt(recentsView.getCurrentPage());
|
||||
runningTaskView = recentsView.getCurrentPageTaskView();
|
||||
if (runningTaskView == null) {
|
||||
// There are no task views in LockTask mode when Overview is enabled.
|
||||
return;
|
||||
@@ -483,4 +440,4 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
public void onLaunchTaskSuccess(Launcher launcher) {
|
||||
launcher.getStateManager().moveToRestState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-14
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper
|
||||
.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -29,7 +29,6 @@ import android.util.Log;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
@@ -49,7 +48,6 @@ public class OverviewCommandHelper {
|
||||
private final Context mContext;
|
||||
private final ActivityManagerWrapper mAM;
|
||||
private final RecentsModel mRecentsModel;
|
||||
private final MainThreadExecutor mMainThreadExecutor;
|
||||
private final OverviewComponentObserver mOverviewComponentObserver;
|
||||
|
||||
private long mLastToggleTime;
|
||||
@@ -57,7 +55,6 @@ public class OverviewCommandHelper {
|
||||
public OverviewCommandHelper(Context context, OverviewComponentObserver observer) {
|
||||
mContext = context;
|
||||
mAM = ActivityManagerWrapper.getInstance();
|
||||
mMainThreadExecutor = new MainThreadExecutor();
|
||||
mRecentsModel = RecentsModel.INSTANCE.get(mContext);
|
||||
mOverviewComponentObserver = observer;
|
||||
}
|
||||
@@ -69,19 +66,19 @@ public class OverviewCommandHelper {
|
||||
}
|
||||
|
||||
mAM.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
||||
mMainThreadExecutor.execute(new RecentsActivityCommand<>());
|
||||
MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());
|
||||
}
|
||||
|
||||
public void onOverviewShown(boolean triggeredFromAltTab) {
|
||||
mMainThreadExecutor.execute(new ShowRecentsCommand(triggeredFromAltTab));
|
||||
MAIN_EXECUTOR.execute(new ShowRecentsCommand(triggeredFromAltTab));
|
||||
}
|
||||
|
||||
public void onOverviewHidden() {
|
||||
mMainThreadExecutor.execute(new HideRecentsCommand());
|
||||
MAIN_EXECUTOR.execute(new HideRecentsCommand());
|
||||
}
|
||||
|
||||
public void onTip(int actionType, int viewType) {
|
||||
mMainThreadExecutor.execute(() ->
|
||||
MAIN_EXECUTOR.execute(() ->
|
||||
UserEventDispatcher.newInstance(mContext).logActionTip(actionType, viewType));
|
||||
}
|
||||
|
||||
@@ -112,7 +109,7 @@ public class OverviewCommandHelper {
|
||||
TaskView taskView = rv.getNextTaskView();
|
||||
if (taskView == null) {
|
||||
if (rv.getTaskViewCount() > 0) {
|
||||
taskView = (TaskView) rv.getPageAt(0);
|
||||
taskView = rv.getTaskViewAt(0);
|
||||
taskView.requestFocus();
|
||||
} else {
|
||||
rv.requestFocus();
|
||||
@@ -164,9 +161,6 @@ public class OverviewCommandHelper {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "RecentsActivityCommand.run");
|
||||
}
|
||||
long elapsedTime = mCreateTime - mLastToggleTime;
|
||||
mLastToggleTime = mCreateTime;
|
||||
|
||||
@@ -183,7 +177,7 @@ public class OverviewCommandHelper {
|
||||
// Otherwise, start overview.
|
||||
mListener = mHelper.createActivityInitListener(this::onActivityReady);
|
||||
mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(),
|
||||
this::createWindowAnimation, mContext, mMainThreadExecutor.getHandler(),
|
||||
this::createWindowAnimation, mContext, MAIN_EXECUTOR.getHandler(),
|
||||
mAnimationProvider.getRecentsLaunchDuration());
|
||||
}
|
||||
|
||||
|
||||
+10
-11
@@ -1,12 +1,12 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.testing.TestInformationHandler;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.uioverrides.states.OverviewState;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
@@ -24,7 +24,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
|
||||
switch (method) {
|
||||
case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: {
|
||||
final float swipeHeight =
|
||||
OverviewState.getDefaultSwipeHeight(mContext, mDeviceProfile);
|
||||
LayoutUtils.getDefaultSwipeHeight(mContext, mDeviceProfile);
|
||||
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
|
||||
return response;
|
||||
}
|
||||
@@ -36,12 +36,6 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
|
||||
return response;
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED: {
|
||||
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
|
||||
TouchInteractionService.isInitialized());
|
||||
return response;
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_HOTSEAT_TOP: {
|
||||
if (mLauncher == null) return null;
|
||||
|
||||
@@ -52,7 +46,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
|
||||
|
||||
case TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN: {
|
||||
try {
|
||||
final int leftMargin = new MainThreadExecutor().submit(() ->
|
||||
final int leftMargin = MAIN_EXECUTOR.submit(() ->
|
||||
mLauncher.<RecentsView>getOverviewPanel().getLeftGestureMargin()).get();
|
||||
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, leftMargin);
|
||||
} catch (ExecutionException e) {
|
||||
@@ -65,7 +59,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
|
||||
|
||||
case TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN: {
|
||||
try {
|
||||
final int rightMargin = new MainThreadExecutor().submit(() ->
|
||||
final int rightMargin = MAIN_EXECUTOR.submit(() ->
|
||||
mLauncher.<RecentsView>getOverviewPanel().getRightGestureMargin()).
|
||||
get();
|
||||
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, rightMargin);
|
||||
@@ -80,4 +74,9 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
|
||||
|
||||
return super.call(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLauncherInitialized() {
|
||||
return super.isLauncherInitialized() && TouchInteractionService.isInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,12 @@ public final class RecentsActivity extends BaseRecentsActivity {
|
||||
return (T) mFallbackRecentsView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnToHomescreen() {
|
||||
super.returnToHomescreen();
|
||||
// TODO(b/137318995) This should go home, but doing so removes freeform windows
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityOptions getActivityLaunchOptions(final View v) {
|
||||
if (!(v instanceof TaskView)) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.android.launcher3.util.Preconditions;
|
||||
import com.android.quickstep.util.RecentsAnimationListenerSet;
|
||||
import com.android.quickstep.util.SwipeAnimationTargetSet;
|
||||
import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
@@ -44,6 +45,7 @@ public class SwipeSharedState implements SwipeAnimationListener {
|
||||
public boolean goingToLauncher;
|
||||
public boolean recentsAnimationFinishInterrupted;
|
||||
public int nextRunningTaskId = -1;
|
||||
private int mLogId;
|
||||
|
||||
public void setOverviewComponentObserver(OverviewComponentObserver observer) {
|
||||
mOverviewComponentObserver = observer;
|
||||
@@ -77,7 +79,7 @@ public class SwipeSharedState implements SwipeAnimationListener {
|
||||
mRecentsAnimationListener.removeListener(this);
|
||||
mRecentsAnimationListener.cancelListener();
|
||||
if (mLastAnimationRunning && mLastAnimationTarget != null) {
|
||||
Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(),
|
||||
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
|
||||
finishAnimation
|
||||
? mLastAnimationTarget::finishAnimation
|
||||
: mLastAnimationTarget::cancelAnimation);
|
||||
@@ -155,5 +157,10 @@ public class SwipeSharedState implements SwipeAnimationListener {
|
||||
pw.println(prefix + "nextRunningTaskId=" + nextRunningTaskId);
|
||||
pw.println(prefix + "lastAnimationCancelled=" + mLastAnimationCancelled);
|
||||
pw.println(prefix + "lastAnimationRunning=" + mLastAnimationRunning);
|
||||
pw.println(prefix + "logTraceId=" + mLogId);
|
||||
}
|
||||
|
||||
public void setLogTraceId(int logId) {
|
||||
this.mLogId = logId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@ import android.view.View;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
@@ -267,12 +265,16 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
|
||||
|
||||
@Override
|
||||
protected ActivityOptions makeLaunchOptions(Activity activity) {
|
||||
return ActivityOptionsCompat.makeFreeformOptions();
|
||||
ActivityOptions activityOptions = ActivityOptionsCompat.makeFreeformOptions();
|
||||
// Arbitrary bounds only because freeform is in dev mode right now
|
||||
Rect r = new Rect(50, 50, 200, 200);
|
||||
activityOptions.setLaunchBounds(r);
|
||||
return activityOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onActivityStarted(BaseDraggingActivity activity) {
|
||||
Launcher.getLauncher(activity).getStateManager().goToState(LauncherState.NORMAL);
|
||||
activity.returnToHomescreen();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+53
-60
@@ -23,6 +23,8 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_HINTS_IN_OVERVIEW
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.config.FeatureFlags.FAKE_LANDSCAPE_UI;
|
||||
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
|
||||
@@ -40,7 +42,6 @@ import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.app.Service;
|
||||
import android.app.TaskInfo;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -50,8 +51,6 @@ import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManager.DisplayListener;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
@@ -61,29 +60,26 @@ import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Choreographer;
|
||||
import android.view.Display;
|
||||
import android.view.InputEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.BinderThread;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ResourceUtils;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.config.BaseFlags;
|
||||
import com.android.launcher3.logging.EventLogArray;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.model.AppLaunchTracker;
|
||||
import com.android.launcher3.provider.RestoreDbTask;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
import com.android.launcher3.util.DefaultDisplay;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
|
||||
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
|
||||
@@ -96,6 +92,7 @@ import com.android.quickstep.inputconsumers.OverviewInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
|
||||
import com.android.quickstep.util.AssistantUtilities;
|
||||
import com.android.systemui.shared.recents.IOverviewProxy;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
@@ -107,7 +104,6 @@ import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
|
||||
import com.android.systemui.shared.system.RecentsAnimationListener;
|
||||
import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
|
||||
|
||||
import com.android.systemui.shared.system.TaskInfoCompat;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
@@ -136,11 +132,14 @@ class ArgList extends LinkedList<String> {
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.Q)
|
||||
public class TouchInteractionService extends Service implements
|
||||
NavigationModeChangeListener, DisplayListener {
|
||||
NavigationModeChangeListener, DefaultDisplay.DisplayInfoChangeListener {
|
||||
|
||||
/**
|
||||
* NOTE: This value should be kept same as
|
||||
* ActivityTaskManagerService#INTENT_EXTRA_LOG_TRACE_ID in platform
|
||||
*/
|
||||
public static final String INTENT_EXTRA_LOG_TRACE_ID = "INTENT_EXTRA_LOG_TRACE_ID";
|
||||
|
||||
public static final MainThreadExecutor MAIN_THREAD_EXECUTOR = new MainThreadExecutor();
|
||||
public static final LooperExecutor BACKGROUND_EXECUTOR =
|
||||
new LooperExecutor(UiThreadHelper.getBackgroundLooper());
|
||||
|
||||
public static final EventLogArray TOUCH_INTERACTION_LOG =
|
||||
new EventLogArray("touch_interaction_log", 40);
|
||||
@@ -161,9 +160,9 @@ public class TouchInteractionService extends Service implements
|
||||
public void onInitialize(Bundle bundle) {
|
||||
mISystemUiProxy = ISystemUiProxy.Stub
|
||||
.asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
|
||||
MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor);
|
||||
MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::onSystemUiProxySet);
|
||||
MAIN_THREAD_EXECUTOR.execute(() -> preloadOverview(true /* fromInit */));
|
||||
MAIN_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor);
|
||||
MAIN_EXECUTOR.execute(TouchInteractionService.this::onSystemUiProxySet);
|
||||
MAIN_EXECUTOR.execute(() -> preloadOverview(true /* fromInit */));
|
||||
sIsInitialized = true;
|
||||
}
|
||||
|
||||
@@ -198,7 +197,7 @@ public class TouchInteractionService extends Service implements
|
||||
@Override
|
||||
public void onAssistantVisibilityChanged(float visibility) {
|
||||
mLastAssistantVisibility = visibility;
|
||||
MAIN_THREAD_EXECUTOR.execute(
|
||||
MAIN_EXECUTOR.execute(
|
||||
TouchInteractionService.this::onAssistantVisibilityChanged);
|
||||
}
|
||||
|
||||
@@ -214,13 +213,13 @@ public class TouchInteractionService extends Service implements
|
||||
isButton, gestureSwipeLeft, activityControl.getContainerType());
|
||||
|
||||
if (completed && !isButton && shouldNotifyBackGesture()) {
|
||||
BACKGROUND_EXECUTOR.execute(TouchInteractionService.this::tryNotifyBackGesture);
|
||||
UI_HELPER_EXECUTOR.execute(TouchInteractionService.this::tryNotifyBackGesture);
|
||||
}
|
||||
}
|
||||
|
||||
public void onSystemUiStateChanged(int stateFlags) {
|
||||
mSystemUiStateFlags = stateFlags;
|
||||
MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged);
|
||||
MAIN_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged);
|
||||
}
|
||||
|
||||
/** Deprecated methods **/
|
||||
@@ -244,6 +243,7 @@ public class TouchInteractionService extends Service implements
|
||||
private static boolean sConnected = false;
|
||||
private static boolean sIsInitialized = false;
|
||||
private static final SwipeSharedState sSwipeSharedState = new SwipeSharedState();
|
||||
private int mLogId;
|
||||
|
||||
public static boolean isConnected() {
|
||||
return sConnected;
|
||||
@@ -323,8 +323,7 @@ public class TouchInteractionService extends Service implements
|
||||
registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
|
||||
}
|
||||
|
||||
mDefaultDisplayId = getSystemService(WindowManager.class).getDefaultDisplay()
|
||||
.getDisplayId();
|
||||
mDefaultDisplayId = DefaultDisplay.INSTANCE.get(this).getInfo().id;
|
||||
String blockingActivity = getString(R.string.gesture_blocking_activity);
|
||||
mGestureBlockingActivity = TextUtils.isEmpty(blockingActivity) ? null :
|
||||
ComponentName.unflattenFromString(blockingActivity);
|
||||
@@ -391,9 +390,8 @@ public class TouchInteractionService extends Service implements
|
||||
return;
|
||||
}
|
||||
|
||||
Display defaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay();
|
||||
Point realSize = new Point();
|
||||
defaultDisplay.getRealSize(realSize);
|
||||
DefaultDisplay.Info displayInfo = DefaultDisplay.INSTANCE.get(this).getInfo();
|
||||
Point realSize = new Point(displayInfo.realSize);
|
||||
mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y);
|
||||
if (mMode == Mode.NO_BUTTON) {
|
||||
int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
|
||||
@@ -415,7 +413,7 @@ public class TouchInteractionService extends Service implements
|
||||
} else {
|
||||
mAssistantLeftRegion.setEmpty();
|
||||
mAssistantRightRegion.setEmpty();
|
||||
switch (defaultDisplay.getRotation()) {
|
||||
switch (displayInfo.rotation) {
|
||||
case Surface.ROTATION_90:
|
||||
mSwipeTouchRegion.left = mSwipeTouchRegion.right
|
||||
- getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
|
||||
@@ -438,10 +436,9 @@ public class TouchInteractionService extends Service implements
|
||||
}
|
||||
if (mMode.hasGestures != newMode.hasGestures) {
|
||||
if (newMode.hasGestures) {
|
||||
getSystemService(DisplayManager.class).registerDisplayListener(
|
||||
this, MAIN_THREAD_EXECUTOR.getHandler());
|
||||
DefaultDisplay.INSTANCE.get(this).addChangeListener(this);
|
||||
} else {
|
||||
getSystemService(DisplayManager.class).unregisterDisplayListener(this);
|
||||
DefaultDisplay.INSTANCE.get(this).removeChangeListener(this);
|
||||
}
|
||||
}
|
||||
mMode = newMode;
|
||||
@@ -457,14 +454,8 @@ public class TouchInteractionService extends Service implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayAdded(int i) { }
|
||||
|
||||
@Override
|
||||
public void onDisplayRemoved(int i) { }
|
||||
|
||||
@Override
|
||||
public void onDisplayChanged(int displayId) {
|
||||
if (displayId != mDefaultDisplayId) {
|
||||
public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) {
|
||||
if (info.id != mDefaultDisplayId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -529,7 +520,7 @@ public class TouchInteractionService extends Service implements
|
||||
}
|
||||
disposeEventHandlers();
|
||||
if (mMode.hasGestures) {
|
||||
getSystemService(DisplayManager.class).unregisterDisplayListener(this);
|
||||
DefaultDisplay.INSTANCE.get(this).removeChangeListener(this);
|
||||
}
|
||||
|
||||
sConnected = false;
|
||||
@@ -554,9 +545,12 @@ public class TouchInteractionService extends Service implements
|
||||
Log.e(TAG, "Unknown event " + ev);
|
||||
return;
|
||||
}
|
||||
|
||||
MotionEvent event = (MotionEvent) ev;
|
||||
TOUCH_INTERACTION_LOG.addLog("onMotionEvent", event.getActionMasked());
|
||||
if (event.getAction() == ACTION_DOWN) {
|
||||
mLogId = TOUCH_INTERACTION_LOG.generateAndSetLogId();
|
||||
sSwipeSharedState.setLogTraceId(mLogId);
|
||||
|
||||
if (mSwipeTouchRegion.contains(event.getX(), event.getY())) {
|
||||
boolean useSharedState = mConsumer.useSharedSwipeState();
|
||||
mConsumer.onConsumerAboutToBeSwitched();
|
||||
@@ -576,6 +570,8 @@ public class TouchInteractionService extends Service implements
|
||||
mUncheckedConsumer = InputConsumer.NO_OP;
|
||||
}
|
||||
}
|
||||
|
||||
TOUCH_INTERACTION_LOG.addLog("onMotionEvent", event.getActionMasked());
|
||||
mUncheckedConsumer.onMotionEvent(event);
|
||||
}
|
||||
|
||||
@@ -653,16 +649,14 @@ public class TouchInteractionService extends Service implements
|
||||
mOverviewComponentObserver.getActivityControlHelper();
|
||||
|
||||
boolean forceOverviewInputConsumer = false;
|
||||
if (isExcludedAssistant(runningTaskInfo)) {
|
||||
if (AssistantUtilities.isExcludedAssistant(runningTaskInfo)) {
|
||||
// In the case where we are in the excluded assistant state, ignore it and treat the
|
||||
// running activity as the task behind the assistant
|
||||
runningTaskInfo = mAM.getRunningTask(ACTIVITY_TYPE_ASSISTANT);
|
||||
if (!ActivityManagerWrapper.isHomeTask(runningTaskInfo)) {
|
||||
final ComponentName homeComponent =
|
||||
mOverviewComponentObserver.getHomeIntent().getComponent();
|
||||
forceOverviewInputConsumer =
|
||||
runningTaskInfo.baseIntent.getComponent().equals(homeComponent);
|
||||
}
|
||||
runningTaskInfo = mAM.getRunningTask(ACTIVITY_TYPE_ASSISTANT /* ignoreActivityType */);
|
||||
ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent();
|
||||
ComponentName runningComponent = runningTaskInfo.baseIntent.getComponent();
|
||||
forceOverviewInputConsumer =
|
||||
runningComponent != null && runningComponent.equals(homeComponent);
|
||||
}
|
||||
|
||||
if (runningTaskInfo == null && !sSwipeSharedState.goingToLauncher
|
||||
@@ -676,9 +670,9 @@ public class TouchInteractionService extends Service implements
|
||||
return createOtherActivityInputConsumer(event, info);
|
||||
} else if (sSwipeSharedState.goingToLauncher || activityControl.isResumed()
|
||||
|| forceOverviewInputConsumer) {
|
||||
return createOverviewInputConsumer(event);
|
||||
return createOverviewInputConsumer(event, forceOverviewInputConsumer);
|
||||
} else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) {
|
||||
return createOverviewInputConsumer(event);
|
||||
return createOverviewInputConsumer(event, forceOverviewInputConsumer);
|
||||
} else if (mGestureBlockingActivity != null && runningTaskInfo != null
|
||||
&& mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) {
|
||||
return mResetGestureInputConsumer;
|
||||
@@ -687,12 +681,6 @@ public class TouchInteractionService extends Service implements
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isExcludedAssistant(TaskInfo info) {
|
||||
return info != null
|
||||
&& TaskInfoCompat.getActivityType(info) == ACTIVITY_TYPE_ASSISTANT
|
||||
&& (info.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
|
||||
}
|
||||
|
||||
private boolean disableHorizontalSwipe(MotionEvent event) {
|
||||
// mExclusionRegion can change on binder thread, use a local instance here.
|
||||
Region exclusionRegion = mExclusionRegion;
|
||||
@@ -718,19 +706,20 @@ public class TouchInteractionService extends Service implements
|
||||
return new OtherActivityInputConsumer(this, runningTaskInfo,
|
||||
shouldDefer, mOverviewCallbacks, this::onConsumerInactive,
|
||||
sSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion,
|
||||
disableHorizontalSwipe(event), factory);
|
||||
disableHorizontalSwipe(event), factory, mLogId);
|
||||
}
|
||||
|
||||
private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) {
|
||||
if (mMode == Mode.NO_BUTTON && taskInfo != null) {
|
||||
return new DeviceLockedInputConsumer(this, sSwipeSharedState, mInputMonitorCompat,
|
||||
mSwipeTouchRegion, taskInfo.taskId);
|
||||
mSwipeTouchRegion, taskInfo.taskId, mLogId);
|
||||
} else {
|
||||
return mResetGestureInputConsumer;
|
||||
}
|
||||
}
|
||||
|
||||
public InputConsumer createOverviewInputConsumer(MotionEvent event) {
|
||||
public InputConsumer createOverviewInputConsumer(MotionEvent event,
|
||||
boolean forceOverviewInputConsumer) {
|
||||
final ActivityControlHelper activityControl =
|
||||
mOverviewComponentObserver.getActivityControlHelper();
|
||||
BaseDraggingActivity activity = activityControl.getCreatedActivity();
|
||||
@@ -738,7 +727,10 @@ public class TouchInteractionService extends Service implements
|
||||
return mResetGestureInputConsumer;
|
||||
}
|
||||
|
||||
if (activity.getRootView().hasWindowFocus() || sSwipeSharedState.goingToLauncher) {
|
||||
if (activity.getRootView().hasWindowFocus()
|
||||
|| sSwipeSharedState.goingToLauncher
|
||||
|| (BaseFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
|
||||
&& forceOverviewInputConsumer)) {
|
||||
return new OverviewInputConsumer(activity, mInputMonitorCompat,
|
||||
false /* startingInActivityBounds */);
|
||||
} else {
|
||||
@@ -788,7 +780,8 @@ public class TouchInteractionService extends Service implements
|
||||
}
|
||||
|
||||
// Pass null animation handler to indicate this start is preload.
|
||||
startRecentsActivityAsync(mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState(), null);
|
||||
startRecentsActivityAsync(mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState(),
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -897,7 +890,7 @@ public class TouchInteractionService extends Service implements
|
||||
}
|
||||
|
||||
public static void startRecentsActivityAsync(Intent intent, RecentsAnimationListener listener) {
|
||||
BACKGROUND_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
|
||||
UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
|
||||
.startRecentsActivity(intent, null, listener, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
+9
-15
@@ -26,14 +26,14 @@ import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
|
||||
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
|
||||
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
|
||||
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
|
||||
import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.HIDE;
|
||||
import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.PEEK;
|
||||
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
||||
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
|
||||
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.HOME;
|
||||
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.LAST_TASK;
|
||||
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.NEW_TASK;
|
||||
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.RECENTS;
|
||||
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
|
||||
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
|
||||
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
|
||||
|
||||
@@ -74,13 +74,14 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import com.android.launcher3.util.RaceConditionTracker;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
import com.android.quickstep.ActivityControlHelper.AnimationFactory;
|
||||
import com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState;
|
||||
import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
import com.android.quickstep.inputconsumers.InputConsumer;
|
||||
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
|
||||
import com.android.quickstep.util.ClipAnimationHelper.TargetAlphaProvider;
|
||||
import com.android.quickstep.util.RectFSpringAnim;
|
||||
import com.android.quickstep.util.ShelfPeekAnim;
|
||||
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
|
||||
import com.android.quickstep.util.SwipeAnimationTargetSet;
|
||||
import com.android.quickstep.views.LiveTileOverlay;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
@@ -192,7 +193,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
Math.min(1 / MIN_PROGRESS_FOR_OVERVIEW, 1 / (1 - MIN_PROGRESS_FOR_OVERVIEW));
|
||||
private static final String SCREENSHOT_CAPTURED_EVT = "ScreenshotCaptured";
|
||||
|
||||
private static final long SHELF_ANIM_DURATION = 240;
|
||||
public static final long RECENTS_ATTACH_DURATION = 300;
|
||||
|
||||
/**
|
||||
@@ -206,8 +206,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
private boolean mIsShelfPeeking;
|
||||
|
||||
private boolean mContinuingLastGesture;
|
||||
// To avoid UI jump when gesture is started, we offset the animation by the threshold.
|
||||
private float mShiftAtGestureStart = 0;
|
||||
|
||||
private ThumbnailData mTaskSnapshot;
|
||||
|
||||
@@ -442,7 +440,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
|
||||
@Override
|
||||
public void onMotionPauseChanged(boolean isPaused) {
|
||||
setShelfState(isPaused ? PEEK : HIDE, OVERSHOOT_1_2, SHELF_ANIM_DURATION);
|
||||
setShelfState(isPaused ? PEEK : HIDE, ShelfPeekAnim.INTERPOLATOR, ShelfPeekAnim.DURATION);
|
||||
}
|
||||
|
||||
public void maybeUpdateRecentsAttachedState() {
|
||||
@@ -479,8 +477,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask;
|
||||
if (animate) {
|
||||
// Only animate if an adjacent task view is visible on screen.
|
||||
TaskView adjacentTask1 = mRecentsView.getTaskViewAt(runningTaskIndex + 1);
|
||||
TaskView adjacentTask2 = mRecentsView.getTaskViewAt(runningTaskIndex - 1);
|
||||
TaskView adjacentTask1 = mRecentsView.getNextTaskView();
|
||||
TaskView adjacentTask2 = mRecentsView.getPreviousTaskView();
|
||||
float prevTranslationX = mRecentsView.getTranslationX();
|
||||
mRecentsView.setTranslationX(0);
|
||||
animate = (adjacentTask1 != null && adjacentTask1.getGlobalVisibleRect(TEMP_RECT))
|
||||
@@ -580,9 +578,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
// Normalize the progress to 0 to 1, as the animation controller will clamp it to that
|
||||
// anyway. The controller mimics the drag length factor by applying it to its interpolators.
|
||||
float progress = mCurrentShift.value / mDragLengthFactor;
|
||||
mLauncherTransitionController.setPlayFraction(
|
||||
progress <= mShiftAtGestureStart || mShiftAtGestureStart >= 1
|
||||
? 0 : (progress - mShiftAtGestureStart) / (1 - mShiftAtGestureStart));
|
||||
mLauncherTransitionController.setPlayFraction(progress);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -590,8 +586,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
*/
|
||||
private void updateSysUiFlags(float windowProgress) {
|
||||
if (mRecentsView != null) {
|
||||
TaskView centermostTask = mRecentsView.getTaskViewAt(mRecentsView
|
||||
.getPageNearestToCenterOfScreen());
|
||||
TaskView centermostTask = mRecentsView.getTaskViewNearestToCenterOfScreen();
|
||||
int centermostTaskFlags = centermostTask == null ? 0
|
||||
: centermostTask.getThumbnail().getSysUiStatusNavFlags();
|
||||
boolean useHomeScreenFlags = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
@@ -623,7 +618,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
@Override
|
||||
public void onGestureStarted() {
|
||||
notifyGestureStartedAsync();
|
||||
mShiftAtGestureStart = mCurrentShift.value;
|
||||
setStateOnUiThread(STATE_GESTURE_STARTED);
|
||||
mGestureStarted = true;
|
||||
}
|
||||
|
||||
+1
-1
@@ -176,7 +176,7 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
|
||||
protected void applyLoadPlan(ArrayList<Task> tasks) {
|
||||
// When quick-switching on 3p-launcher, we add a "dummy" tile corresponding to Launcher
|
||||
// as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
|
||||
// track the index of the next task appropriately, as it we are switching on any other app.
|
||||
// track the index of the next task appropriately, as if we are switching on any other app.
|
||||
if (mRunningTaskInfo != null && mRunningTaskInfo.taskId == mRunningTaskId) {
|
||||
// Check if the task list has running task
|
||||
boolean found = false;
|
||||
|
||||
+10
-6
@@ -22,8 +22,9 @@ import static android.view.MotionEvent.ACTION_UP;
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.Utilities.squaredTouchSlop;
|
||||
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
||||
import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
|
||||
import static com.android.quickstep.TouchInteractionService.INTENT_EXTRA_LOG_TRACE_ID;
|
||||
import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync;
|
||||
import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -35,10 +36,10 @@ import android.graphics.RectF;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.DefaultDisplay;
|
||||
import com.android.quickstep.LockScreenRecentsActivity;
|
||||
import com.android.quickstep.MultiStateCallback;
|
||||
import com.android.quickstep.SwipeSharedState;
|
||||
@@ -76,6 +77,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
|
||||
|
||||
private final PointF mTouchDown = new PointF();
|
||||
private final ClipAnimationHelper mClipAnimationHelper;
|
||||
private int mLogId;
|
||||
private final ClipAnimationHelper.TransformParams mTransformParams;
|
||||
private final Point mDisplaySize;
|
||||
private final MultiStateCallback mStateCallback;
|
||||
@@ -90,19 +92,20 @@ public class DeviceLockedInputConsumer implements InputConsumer,
|
||||
private SwipeAnimationTargetSet mTargetSet;
|
||||
|
||||
public DeviceLockedInputConsumer(Context context, SwipeSharedState swipeSharedState,
|
||||
InputMonitorCompat inputMonitorCompat, RectF swipeTouchRegion, int runningTaskId) {
|
||||
InputMonitorCompat inputMonitorCompat, RectF swipeTouchRegion, int runningTaskId,
|
||||
int logId) {
|
||||
mContext = context;
|
||||
mTouchSlopSquared = squaredTouchSlop(context);
|
||||
mSwipeSharedState = swipeSharedState;
|
||||
mClipAnimationHelper = new ClipAnimationHelper(context);
|
||||
mLogId = logId;
|
||||
mTransformParams = new ClipAnimationHelper.TransformParams();
|
||||
mInputMonitorCompat = inputMonitorCompat;
|
||||
mSwipeTouchRegion = swipeTouchRegion;
|
||||
mRunningTaskId = runningTaskId;
|
||||
|
||||
// Do not use DeviceProfile as the user data might be locked
|
||||
mDisplaySize = new Point();
|
||||
context.getSystemService(WindowManager.class).getDefaultDisplay().getRealSize(mDisplaySize);
|
||||
mDisplaySize = DefaultDisplay.INSTANCE.get(context).getInfo().realSize;
|
||||
|
||||
// Init states
|
||||
mStateCallback = new MultiStateCallback(STATE_NAMES);
|
||||
@@ -205,7 +208,8 @@ public class DeviceLockedInputConsumer implements InputConsumer,
|
||||
Intent intent = new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
.setComponent(new ComponentName(mContext, LockScreenRecentsActivity.class))
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId);
|
||||
|
||||
mInputMonitorCompat.pilferPointers();
|
||||
startRecentsActivityAsync(intent, newListenerSet);
|
||||
|
||||
-1
@@ -50,7 +50,6 @@ import com.android.quickstep.fallback.FallbackRecentsView;
|
||||
import com.android.quickstep.util.ObjectWrapper;
|
||||
import com.android.quickstep.util.RectFSpringAnim;
|
||||
import com.android.quickstep.util.SwipeAnimationTargetSet;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
|
||||
+10
-7
@@ -22,11 +22,11 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN;
|
||||
import static android.view.MotionEvent.ACTION_POINTER_UP;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
import static android.view.MotionEvent.INVALID_POINTER_ID;
|
||||
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
|
||||
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
|
||||
import static com.android.quickstep.TouchInteractionService.INTENT_EXTRA_LOG_TRACE_ID;
|
||||
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
|
||||
import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
@@ -35,6 +35,7 @@ import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
@@ -43,12 +44,13 @@ import android.os.Looper;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.RaceConditionTracker;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
import com.android.quickstep.BaseSwipeUpHandler;
|
||||
import com.android.quickstep.BaseSwipeUpHandler.Factory;
|
||||
import com.android.quickstep.OverviewCallbacks;
|
||||
import com.android.quickstep.SwipeSharedState;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
@@ -59,11 +61,8 @@ import com.android.quickstep.util.NavBarPosition;
|
||||
import com.android.quickstep.util.RecentsAnimationListenerSet;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
/**
|
||||
* Input consumer for handling events originating from an activity other than Launcher
|
||||
*/
|
||||
@@ -119,14 +118,16 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
ActivityManagerWrapper.getInstance().cancelRecentsAnimation(
|
||||
true /* restoreHomeStackPosition */);
|
||||
};
|
||||
private int mLogId;
|
||||
|
||||
public OtherActivityInputConsumer(Context base, RunningTaskInfo runningTaskInfo,
|
||||
boolean isDeferredDownTarget, OverviewCallbacks overviewCallbacks,
|
||||
Consumer<OtherActivityInputConsumer> onCompleteCallback,
|
||||
SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat,
|
||||
RectF swipeTouchRegion, boolean disableHorizontalSwipe,
|
||||
BaseSwipeUpHandler.Factory handlerFactory) {
|
||||
Factory handlerFactory, int logId) {
|
||||
super(base);
|
||||
mLogId = logId;
|
||||
|
||||
mMainThreadHandler = new Handler(Looper.getMainLooper());
|
||||
mRunningTask = runningTaskInfo;
|
||||
@@ -341,7 +342,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
RecentsAnimationListenerSet newListenerSet =
|
||||
mSwipeSharedState.newRecentsAnimationListenerSet();
|
||||
newListenerSet.addListener(handler);
|
||||
startRecentsActivityAsync(handler.getLaunchIntent(), newListenerSet);
|
||||
Intent intent = handler.getLaunchIntent();
|
||||
intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId);
|
||||
startRecentsActivityAsync(intent, newListenerSet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-7
@@ -22,9 +22,9 @@ import static android.view.MotionEvent.ACTION_UP;
|
||||
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PointF;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
@@ -34,12 +34,9 @@ import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.logging.StatsLogUtils;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.quickstep.OverviewCallbacks;
|
||||
import com.android.quickstep.util.NavBarPosition;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
|
||||
public class OverviewWithoutFocusInputConsumer implements InputConsumer {
|
||||
@@ -148,9 +145,9 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer {
|
||||
}
|
||||
|
||||
if (triggerQuickstep) {
|
||||
OverviewCallbacks.get(mContext).closeAllWindows();
|
||||
ActivityManagerWrapper.getInstance()
|
||||
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
||||
mContext.startActivity(new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_HOME)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
TOUCH_INTERACTION_LOG.addLog("startQuickstep");
|
||||
BaseActivity activity = BaseDraggingActivity.fromContext(mContext);
|
||||
int pageIndex = -1; // This number doesn't reflect workspace page index.
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep.logging;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
|
||||
/**
|
||||
* This class handles AOSP MetricsLogger function calls and logging around
|
||||
* quickstep interactions and app launches.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class UserEventDispatcherAppPredictionExtension extends UserEventDispatcherExtension {
|
||||
|
||||
public static final int ALL_APPS_PREDICTION_TIPS = 2;
|
||||
|
||||
private static final String TAG = "UserEventDispatcher";
|
||||
|
||||
public UserEventDispatcherAppPredictionExtension(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFillInLogContainerData(
|
||||
@NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target,
|
||||
@NonNull LauncherLogProto.Target targetParent) {
|
||||
PredictionUiStateManager.fillInPredictedRank(itemInfo, target);
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -37,6 +37,7 @@ import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
@@ -50,8 +51,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.
|
||||
import com.android.systemui.shared.system.TransactionCompat;
|
||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Utility class to handle window clip animation
|
||||
*/
|
||||
@@ -213,6 +212,11 @@ public class ClipAnimationHelper {
|
||||
}
|
||||
mCurrentCornerRadius = cornerRadius;
|
||||
}
|
||||
// Fade out Assistant overlay.
|
||||
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
|
||||
&& app.isNotInRecents) {
|
||||
alpha = 1 - Interpolators.DEACCEL_2_5.getInterpolation(progress);
|
||||
}
|
||||
} else if (targetSet.hasRecents) {
|
||||
// If home has a different target then recents, reverse anim the
|
||||
// home target.
|
||||
|
||||
@@ -21,9 +21,9 @@ import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.util.DefaultDisplay;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
|
||||
/**
|
||||
@@ -36,8 +36,7 @@ public class NavBarPosition {
|
||||
|
||||
public NavBarPosition(Context context) {
|
||||
mMode = SysUINavigationMode.getMode(context);
|
||||
mDisplayRotation = context.getSystemService(WindowManager.class)
|
||||
.getDefaultDisplay().getRotation();
|
||||
mDisplayRotation = DefaultDisplay.INSTANCE.get(context).getInfo().rotation;
|
||||
}
|
||||
|
||||
public boolean isRightEdge() {
|
||||
|
||||
+6
-6
@@ -15,11 +15,13 @@
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
|
||||
@@ -31,8 +33,6 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
/**
|
||||
* Wrapper around {@link RecentsAnimationListener} which delegates callbacks to multiple listeners
|
||||
* on the main thread
|
||||
@@ -82,7 +82,7 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener {
|
||||
if (mCancelled) {
|
||||
targetSet.cancelAnimation();
|
||||
} else {
|
||||
Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(), () -> {
|
||||
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
|
||||
for (SwipeAnimationListener listener : getListeners()) {
|
||||
listener.onRecentsAnimationStart(targetSet);
|
||||
}
|
||||
@@ -92,14 +92,14 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener {
|
||||
|
||||
@Override
|
||||
public final void onAnimationCanceled(ThumbnailData thumbnailData) {
|
||||
Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(), () -> {
|
||||
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
|
||||
for (SwipeAnimationListener listener : getListeners()) {
|
||||
listener.onRecentsAnimationCanceled();
|
||||
}
|
||||
});
|
||||
// TODO: handle the transition better instead of simply using a transition delay.
|
||||
if (thumbnailData != null) {
|
||||
MAIN_THREAD_EXECUTOR.getHandler().postDelayed(() -> mController.cleanupScreenshot(),
|
||||
MAIN_EXECUTOR.getHandler().postDelayed(() -> mController.cleanupScreenshot(),
|
||||
TRANSITION_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_SHELF_ANIM;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.uioverrides.states.OverviewState;
|
||||
|
||||
/**
|
||||
* Animates the shelf between states HIDE, PEEK, and OVERVIEW.
|
||||
*/
|
||||
|
||||
public class ShelfPeekAnim {
|
||||
|
||||
public static final Interpolator INTERPOLATOR = OVERSHOOT_1_2;
|
||||
public static final long DURATION = 240;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
|
||||
private ShelfAnimState mShelfState;
|
||||
private boolean mIsPeeking;
|
||||
|
||||
public ShelfPeekAnim(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates to the given state, canceling the previous animation if it was still running.
|
||||
*/
|
||||
public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator, long duration) {
|
||||
if (mShelfState == shelfState) {
|
||||
return;
|
||||
}
|
||||
mLauncher.getStateManager().cancelStateElementAnimation(INDEX_SHELF_ANIM);
|
||||
mShelfState = shelfState;
|
||||
mIsPeeking = mShelfState == ShelfAnimState.PEEK || mShelfState == ShelfAnimState.HIDE;
|
||||
if (mShelfState == ShelfAnimState.CANCEL) {
|
||||
return;
|
||||
}
|
||||
float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(mLauncher);
|
||||
float shelfOverviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
|
||||
// Peek based on default overview progress so we can see hotseat if we're showing
|
||||
// that instead of predictions in overview.
|
||||
float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(mLauncher);
|
||||
float shelfPeekingProgress = shelfHiddenProgress
|
||||
- (shelfHiddenProgress - defaultOverviewProgress) * 0.25f;
|
||||
float toProgress = mShelfState == ShelfAnimState.HIDE
|
||||
? shelfHiddenProgress
|
||||
: mShelfState == ShelfAnimState.PEEK
|
||||
? shelfPeekingProgress
|
||||
: shelfOverviewProgress;
|
||||
Animator shelfAnim = mLauncher.getStateManager()
|
||||
.createStateElementAnimation(INDEX_SHELF_ANIM, toProgress);
|
||||
shelfAnim.setInterpolator(interpolator);
|
||||
shelfAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mShelfState = ShelfAnimState.CANCEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
mIsPeeking = mShelfState == ShelfAnimState.PEEK;
|
||||
}
|
||||
});
|
||||
shelfAnim.setDuration(duration).start();
|
||||
}
|
||||
|
||||
/** @return Whether the shelf is currently peeking or animating to or from peeking. */
|
||||
public boolean isPeeking() {
|
||||
return mIsPeeking;
|
||||
}
|
||||
|
||||
/** The various shelf states we can animate to. */
|
||||
public enum ShelfAnimState {
|
||||
HIDE(true), PEEK(true), OVERVIEW(false), CANCEL(false);
|
||||
|
||||
ShelfAnimState(boolean shouldPreformHaptic) {
|
||||
this.shouldPreformHaptic = shouldPreformHaptic;
|
||||
}
|
||||
|
||||
public final boolean shouldPreformHaptic;
|
||||
}
|
||||
}
|
||||
+26
-40
@@ -18,6 +18,7 @@ package com.android.quickstep.util;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -27,13 +28,11 @@ import android.animation.ObjectAnimator;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.LauncherStateManager.AnimationConfig;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ShortcutAndWidgetContainer;
|
||||
@@ -41,9 +40,8 @@ import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.launcher3.anim.SpringObjectAnimator;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.graphics.OverviewScrim;
|
||||
import com.android.launcher3.views.IconLabelDotView;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -66,18 +64,12 @@ public class StaggeredWorkspaceAnim {
|
||||
private final float mVelocity;
|
||||
private final float mSpringTransY;
|
||||
|
||||
// The original view of the {@link FloatingIconView}.
|
||||
private final View mOriginalView;
|
||||
|
||||
private final List<Animator> mAnimators = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @param floatingViewOriginalView The FloatingIconView's original view.
|
||||
*/
|
||||
public StaggeredWorkspaceAnim(Launcher launcher, @Nullable View floatingViewOriginalView,
|
||||
float velocity) {
|
||||
public StaggeredWorkspaceAnim(Launcher launcher, float velocity, boolean animateOverviewScrim) {
|
||||
prepareToAnimate(launcher);
|
||||
|
||||
mVelocity = velocity;
|
||||
mOriginalView = floatingViewOriginalView;
|
||||
|
||||
// Scale the translationY based on the initial velocity to better sync the workspace items
|
||||
// with the floating view.
|
||||
@@ -133,8 +125,10 @@ public class StaggeredWorkspaceAnim {
|
||||
addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows);
|
||||
}
|
||||
|
||||
addScrimAnimationForState(launcher, BACKGROUND_APP, 0);
|
||||
addScrimAnimationForState(launcher, NORMAL, ALPHA_DURATION_MS);
|
||||
if (animateOverviewScrim) {
|
||||
addScrimAnimationForState(launcher, BACKGROUND_APP, 0);
|
||||
addScrimAnimationForState(launcher, NORMAL, ALPHA_DURATION_MS);
|
||||
}
|
||||
|
||||
AnimatorListener resetClipListener = new AnimatorListenerAdapter() {
|
||||
int numAnimations = mAnimators.size();
|
||||
@@ -160,6 +154,21 @@ public class StaggeredWorkspaceAnim {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup workspace with 0 duration to prepare for our staggered animation.
|
||||
*/
|
||||
private void prepareToAnimate(Launcher launcher) {
|
||||
LauncherStateManager stateManager = launcher.getStateManager();
|
||||
AnimatorSetBuilder builder = new AnimatorSetBuilder();
|
||||
// setRecentsAttachedToAppWindow() will animate recents out.
|
||||
builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW);
|
||||
stateManager.createAtomicAnimation(BACKGROUND_APP, NORMAL, builder, ANIM_ALL, 0);
|
||||
builder.build().start();
|
||||
|
||||
// Stop scrolling so that it doesn't interfere with the translation offscreen.
|
||||
launcher.<RecentsView>getOverviewPanel().getScroller().forceFinished(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the animation.
|
||||
*/
|
||||
@@ -192,35 +201,12 @@ public class StaggeredWorkspaceAnim {
|
||||
springTransY.setStartDelay(startDelay);
|
||||
mAnimators.add(springTransY);
|
||||
|
||||
ObjectAnimator alpha = getAlphaAnimator(v, startDelay);
|
||||
if (v == mOriginalView) {
|
||||
// For IconLabelDotViews, we just want the label to fade in.
|
||||
// Icon, badge, and dots will animate in separately (controlled via FloatingIconView)
|
||||
if (v instanceof IconLabelDotView) {
|
||||
alpha.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
IconLabelDotView view = (IconLabelDotView) v;
|
||||
view.setIconVisible(false);
|
||||
view.setForceHideDot(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
v.setAlpha(0);
|
||||
mAnimators.add(alpha);
|
||||
}
|
||||
|
||||
private ObjectAnimator getAlphaAnimator(View v, long startDelay) {
|
||||
ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f);
|
||||
alpha.setInterpolator(LINEAR);
|
||||
alpha.setDuration(ALPHA_DURATION_MS);
|
||||
alpha.setStartDelay(startDelay);
|
||||
return alpha;
|
||||
|
||||
mAnimators.add(alpha);
|
||||
}
|
||||
|
||||
private void addScrimAnimationForState(Launcher launcher, LauncherState state, long duration) {
|
||||
|
||||
+6
-6
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;
|
||||
import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
|
||||
import android.graphics.Rect;
|
||||
@@ -68,25 +68,25 @@ public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet {
|
||||
|
||||
public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) {
|
||||
mOnFinishListener.accept(this);
|
||||
BACKGROUND_EXECUTOR.execute(() -> {
|
||||
UI_HELPER_EXECUTOR.execute(() -> {
|
||||
controller.setInputConsumerEnabled(false);
|
||||
controller.finish(toRecents, sendUserLeaveHint);
|
||||
|
||||
if (callback != null) {
|
||||
MAIN_THREAD_EXECUTOR.execute(callback);
|
||||
MAIN_EXECUTOR.execute(callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void enableInputConsumer() {
|
||||
BACKGROUND_EXECUTOR.submit(() -> {
|
||||
UI_HELPER_EXECUTOR.submit(() -> {
|
||||
controller.hideCurrentInputMethod();
|
||||
controller.setInputConsumerEnabled(true);
|
||||
});
|
||||
}
|
||||
|
||||
public void setWindowThresholdCrossed(boolean thresholdCrossed) {
|
||||
BACKGROUND_EXECUTOR.execute(() -> {
|
||||
UI_HELPER_EXECUTOR.execute(() -> {
|
||||
controller.setAnimationTargetsBehindSystemBars(!thresholdCrossed);
|
||||
if (mShouldMinimizeSplitScreen && thresholdCrossed) {
|
||||
// NOTE: As a workaround for conflicting animations (Launcher animating the task
|
||||
|
||||
+2
-2
@@ -19,6 +19,7 @@ package com.android.quickstep.views;
|
||||
import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS;
|
||||
|
||||
import static com.android.launcher3.Utilities.prefixTextWithIcon;
|
||||
import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityOptions;
|
||||
@@ -41,7 +42,6 @@ import androidx.annotation.StringRes;
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
@@ -117,7 +117,7 @@ public final class DigitalWellBeingToast {
|
||||
return;
|
||||
}
|
||||
|
||||
Utilities.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
final AppUsageLimit usageLimit = mLauncherApps.getAppUsageLimit(
|
||||
task.getTopComponent().getPackageName(),
|
||||
UserHandle.of(task.key.userId));
|
||||
|
||||
+106
@@ -35,6 +35,7 @@ import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Hotseat;
|
||||
@@ -45,11 +46,14 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.views.ScrimView;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
import com.android.quickstep.util.ClipAnimationHelper;
|
||||
import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.systemui.plugins.PluginListener;
|
||||
import com.android.systemui.plugins.RecentsExtraCard;
|
||||
|
||||
/**
|
||||
* {@link RecentsView} used in Launcher activity
|
||||
@@ -57,8 +61,29 @@ import com.android.quickstep.util.LayoutUtils;
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public class LauncherRecentsView extends RecentsView<Launcher> implements StateListener {
|
||||
|
||||
private static final Rect sTempRect = new Rect();
|
||||
|
||||
private final TransformParams mTransformParams = new TransformParams();
|
||||
|
||||
private RecentsExtraCard mRecentsExtraCardPlugin;
|
||||
private RecentsExtraViewContainer mRecentsExtraViewContainer;
|
||||
private PluginListener<RecentsExtraCard> mRecentsExtraCardPluginListener =
|
||||
new PluginListener<RecentsExtraCard>() {
|
||||
@Override
|
||||
public void onPluginConnected(RecentsExtraCard recentsExtraCard, Context context) {
|
||||
createRecentsExtraCard();
|
||||
mRecentsExtraCardPlugin = recentsExtraCard;
|
||||
mRecentsExtraCardPlugin.setupView(context, mRecentsExtraViewContainer, mActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginDisconnected(RecentsExtraCard plugin) {
|
||||
removeView(mRecentsExtraViewContainer);
|
||||
mRecentsExtraCardPlugin = null;
|
||||
mRecentsExtraViewContainer = null;
|
||||
}
|
||||
};
|
||||
|
||||
public LauncherRecentsView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -144,6 +169,25 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
||||
LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The translationX to apply to this view so that the first task is just offscreen.
|
||||
*/
|
||||
public float getOffscreenTranslationX(float recentsScale) {
|
||||
float offscreenX = NORMAL.getOverviewScaleAndTranslation(mActivity).translationX;
|
||||
// Offset since scale pushes tasks outwards.
|
||||
getTaskSize(sTempRect);
|
||||
int taskWidth = sTempRect.width();
|
||||
offscreenX += taskWidth * (recentsScale - 1) / 2;
|
||||
if (mRunningTaskTileHidden) {
|
||||
// The first task is hidden, so offset by its width.
|
||||
offscreenX -= (taskWidth + getPageSpacing()) * recentsScale;
|
||||
}
|
||||
if (isRtl()) {
|
||||
offscreenX = -offscreenX;
|
||||
}
|
||||
return offscreenX;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) {
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
@@ -264,4 +308,66 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
||||
}
|
||||
return super.shouldStealTouchFromSiblingsBelow(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
PluginManagerWrapper.INSTANCE.get(getContext())
|
||||
.addPluginListener(mRecentsExtraCardPluginListener, RecentsExtraCard.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(
|
||||
mRecentsExtraCardPluginListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int computeMinScrollX() {
|
||||
if (canComputeScrollX() && !mIsRtl) {
|
||||
return computeScrollX();
|
||||
}
|
||||
return super.computeMinScrollX();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int computeMaxScrollX() {
|
||||
if (canComputeScrollX() && mIsRtl) {
|
||||
return computeScrollX();
|
||||
}
|
||||
return super.computeMaxScrollX();
|
||||
}
|
||||
|
||||
private boolean canComputeScrollX() {
|
||||
return mRecentsExtraCardPlugin != null && getTaskViewCount() > 0
|
||||
&& !mDisallowScrollToClearAll;
|
||||
}
|
||||
|
||||
private int computeScrollX() {
|
||||
int scrollIndex = getTaskViewStartIndex() - 1;
|
||||
while (scrollIndex >= 0 && getChildAt(scrollIndex) instanceof RecentsExtraViewContainer
|
||||
&& ((RecentsExtraViewContainer) getChildAt(scrollIndex)).isScrollable()) {
|
||||
scrollIndex--;
|
||||
}
|
||||
return getScrollForPage(scrollIndex + 1);
|
||||
}
|
||||
|
||||
private void createRecentsExtraCard() {
|
||||
mRecentsExtraViewContainer = new RecentsExtraViewContainer(getContext());
|
||||
FrameLayout.LayoutParams helpCardParams =
|
||||
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.MATCH_PARENT);
|
||||
mRecentsExtraViewContainer.setLayoutParams(helpCardParams);
|
||||
mRecentsExtraViewContainer.setScrollable(true);
|
||||
addView(mRecentsExtraViewContainer, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetTaskVisuals() {
|
||||
super.resetTaskVisuals();
|
||||
if (mRecentsExtraViewContainer != null) {
|
||||
mRecentsExtraViewContainer.setAlpha(mContentAlpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.quickstep.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* Empty view to house recents overview extra card
|
||||
*/
|
||||
public class RecentsExtraViewContainer extends FrameLayout implements RecentsView.PageCallbacks {
|
||||
|
||||
private boolean mScrollable = false;
|
||||
|
||||
public RecentsExtraViewContainer(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public RecentsExtraViewContainer(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public RecentsExtraViewContainer(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the view should be scrolled to in the recents overview, similar to the
|
||||
* taskviews.
|
||||
* @return true if viewed should be scrolled to, false if not
|
||||
*/
|
||||
public boolean isScrollable() {
|
||||
return mScrollable;
|
||||
}
|
||||
|
||||
public void setScrollable(boolean scrollable) {
|
||||
this.mScrollable = scrollable;
|
||||
}
|
||||
}
|
||||
@@ -34,9 +34,9 @@ import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
|
||||
import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CLEAR_ALL_BUTTON;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
|
||||
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
|
||||
import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
@@ -186,7 +186,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
private final ViewPool<TaskView> mTaskViewPool;
|
||||
|
||||
private boolean mDwbToastShown;
|
||||
private boolean mDisallowScrollToClearAll;
|
||||
protected boolean mDisallowScrollToClearAll;
|
||||
private boolean mOverlayEnabled;
|
||||
private boolean mFreezeViewVisibility;
|
||||
|
||||
@@ -227,7 +227,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
return;
|
||||
}
|
||||
|
||||
BACKGROUND_EXECUTOR.execute(() -> {
|
||||
UI_HELPER_EXECUTOR.execute(() -> {
|
||||
TaskView taskView = getTaskView(taskId);
|
||||
if (taskView == null) {
|
||||
return;
|
||||
@@ -271,7 +271,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
// Only valid until the launcher state changes to NORMAL
|
||||
protected int mRunningTaskId = -1;
|
||||
private boolean mRunningTaskTileHidden;
|
||||
protected boolean mRunningTaskTileHidden;
|
||||
private Task mTmpRunningTask;
|
||||
|
||||
private boolean mRunningTaskIconScaledDown = false;
|
||||
@@ -288,7 +288,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
private LayoutTransition mLayoutTransition;
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private float mContentAlpha = 1;
|
||||
protected float mContentAlpha = 1;
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
protected float mFullscreenProgress = 0;
|
||||
|
||||
@@ -305,6 +305,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
private Layout mEmptyTextLayout;
|
||||
private LiveTileOverlay mLiveTileOverlay;
|
||||
|
||||
// Keeps track of the index where the first TaskView should be
|
||||
private int mTaskViewStartIndex = 0;
|
||||
|
||||
private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
|
||||
(inMultiWindowMode) -> {
|
||||
if (!inMultiWindowMode && mOverviewStateEnabled) {
|
||||
@@ -328,7 +331,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
|
||||
.inflate(R.layout.overview_clear_all_button, this, false);
|
||||
mClearAllButton.setOnClickListener(this::dismissAllTasks);
|
||||
|
||||
mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
|
||||
10 /* initial size */);
|
||||
|
||||
@@ -429,7 +431,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
super.onViewRemoved(child);
|
||||
|
||||
// Clear the task data for the removed child if it was visible
|
||||
if (child != mClearAllButton) {
|
||||
if (child instanceof TaskView) {
|
||||
TaskView taskView = (TaskView) child;
|
||||
mHasVisibleTaskData.delete(taskView.getTask().key.id);
|
||||
mTaskViewPool.recycle(taskView);
|
||||
@@ -443,7 +445,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
public TaskView getTaskView(int taskId) {
|
||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||
TaskView tv = (TaskView) getChildAt(i);
|
||||
TaskView tv = getTaskViewAt(i);
|
||||
if (tv.getTask() != null && tv.getTask().key != null && tv.getTask().key.id == taskId) {
|
||||
return tv;
|
||||
}
|
||||
@@ -535,28 +537,26 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
|
||||
if (tasks == null || tasks.isEmpty()) {
|
||||
removeAllViews();
|
||||
removeTasksViewsAndClearAllButton();
|
||||
onTaskStackUpdated();
|
||||
return;
|
||||
}
|
||||
|
||||
int oldChildCount = getChildCount();
|
||||
|
||||
// Unload existing visible task data
|
||||
unloadVisibleTaskData();
|
||||
|
||||
TaskView ignoreRestTaskView =
|
||||
TaskView ignoreResetTaskView =
|
||||
mIgnoreResetTaskId == -1 ? null : getTaskView(mIgnoreResetTaskId);
|
||||
|
||||
final int requiredTaskCount = tasks.size();
|
||||
if (getTaskViewCount() != requiredTaskCount) {
|
||||
if (oldChildCount > 0) {
|
||||
if (indexOfChild(mClearAllButton) != -1) {
|
||||
removeView(mClearAllButton);
|
||||
}
|
||||
for (int i = getChildCount(); i < requiredTaskCount; i++) {
|
||||
for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
|
||||
addView(mTaskViewPool.getView());
|
||||
}
|
||||
while (getChildCount() > requiredTaskCount) {
|
||||
while (getTaskViewCount() > requiredTaskCount) {
|
||||
removeView(getChildAt(getChildCount() - 1));
|
||||
}
|
||||
if (requiredTaskCount > 0) {
|
||||
@@ -566,7 +566,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
// Rebind and reset all task views
|
||||
for (int i = requiredTaskCount - 1; i >= 0; i--) {
|
||||
final int pageIndex = requiredTaskCount - i - 1;
|
||||
final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
|
||||
final Task task = tasks.get(i);
|
||||
final TaskView taskView = (TaskView) getChildAt(pageIndex);
|
||||
taskView.bind(task);
|
||||
@@ -577,10 +577,12 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
TaskView runningTaskView = getRunningTaskView();
|
||||
if (runningTaskView != null) {
|
||||
setCurrentPage(indexOfChild(runningTaskView));
|
||||
} else if (getTaskViewCount() > 0) {
|
||||
setCurrentPage(indexOfChild(getTaskViewAt(0)));
|
||||
}
|
||||
}
|
||||
|
||||
if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreRestTaskView) {
|
||||
if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreResetTaskView) {
|
||||
// If the taskView mapping is changing, do not preserve the visuals. Since we are
|
||||
// mostly preserving the first task, and new taskViews are added to the end, it should
|
||||
// generally map to the same task.
|
||||
@@ -591,17 +593,28 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
updateEnabledOverlays();
|
||||
}
|
||||
|
||||
private void removeTasksViewsAndClearAllButton() {
|
||||
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
|
||||
removeView(getTaskViewAt(i));
|
||||
}
|
||||
if (indexOfChild(mClearAllButton) != -1) {
|
||||
removeView(mClearAllButton);
|
||||
}
|
||||
}
|
||||
|
||||
public int getTaskViewCount() {
|
||||
// Account for the clear all button.
|
||||
int childCount = getChildCount();
|
||||
return childCount == 0 ? 0 : childCount - 1;
|
||||
int taskViewCount = getChildCount() - mTaskViewStartIndex;
|
||||
if (indexOfChild(mClearAllButton) != -1) {
|
||||
taskViewCount--;
|
||||
}
|
||||
return taskViewCount;
|
||||
}
|
||||
|
||||
protected void onTaskStackUpdated() { }
|
||||
|
||||
public void resetTaskVisuals() {
|
||||
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
|
||||
TaskView taskView = (TaskView) getChildAt(i);
|
||||
TaskView taskView = getTaskViewAt(i);
|
||||
if (mIgnoreResetTaskId != taskView.getTask().key.id) {
|
||||
taskView.resetVisualProperties();
|
||||
taskView.setStableAlpha(mContentAlpha);
|
||||
@@ -707,7 +720,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through all thet asks, and loads the associated task data for newly visible tasks,
|
||||
* Iterates through all the tasks, and loads the associated task data for newly visible tasks,
|
||||
* and unloads the associated task data for tasks that are no longer visible.
|
||||
*/
|
||||
public void loadVisibleTaskData() {
|
||||
@@ -718,15 +731,16 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
|
||||
int centerPageIndex = getPageNearestToCenterOfScreen();
|
||||
int numChildren = getTaskViewCount();
|
||||
int numChildren = getChildCount();
|
||||
int lower = Math.max(0, centerPageIndex - 2);
|
||||
int upper = Math.min(centerPageIndex + 2, numChildren - 1);
|
||||
|
||||
// Update the task data for the in/visible children
|
||||
for (int i = 0; i < numChildren; i++) {
|
||||
TaskView taskView = (TaskView) getChildAt(i);
|
||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||
TaskView taskView = getTaskViewAt(i);
|
||||
Task task = taskView.getTask();
|
||||
boolean visible = lower <= i && i <= upper;
|
||||
int index = indexOfChild(taskView);
|
||||
boolean visible = lower <= index && index <= upper;
|
||||
if (visible) {
|
||||
if (task == mTmpRunningTask) {
|
||||
// Skip loading if this is the task that we are animating into
|
||||
@@ -801,6 +815,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
return tv == null ? -1 : indexOfChild(tv);
|
||||
}
|
||||
|
||||
public int getTaskViewStartIndex() {
|
||||
return mTaskViewStartIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the view if anything in recents changed.
|
||||
*/
|
||||
@@ -856,10 +874,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
*/
|
||||
public void showCurrentTask(int runningTaskId) {
|
||||
if (getTaskView(runningTaskId) == null) {
|
||||
boolean wasEmpty = getChildCount() == 0;
|
||||
boolean wasEmpty = getTaskViewCount() == 0;
|
||||
// Add an empty view for now until the task plan is loaded and applied
|
||||
final TaskView taskView = mTaskViewPool.getView();
|
||||
addView(taskView, 0);
|
||||
addView(taskView, mTaskViewStartIndex);
|
||||
if (wasEmpty) {
|
||||
addView(mClearAllButton);
|
||||
}
|
||||
@@ -925,14 +943,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
if (runningTaskView == null) {
|
||||
// Launch the first task
|
||||
if (getTaskViewCount() > 0) {
|
||||
getTaskViewAt(0).launchTask(true /* animate */);
|
||||
getTaskViewAt(0).launchTask(true);
|
||||
}
|
||||
} else {
|
||||
TaskView nextTaskView = getNextTaskView();
|
||||
if (nextTaskView != null) {
|
||||
nextTaskView.launchTask(true /* animate */);
|
||||
if (getNextTaskView() != null) {
|
||||
getNextTaskView().launchTask(true);
|
||||
} else {
|
||||
runningTaskView.launchTask(true /* animate */);
|
||||
runningTaskView.launchTask(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1196,7 +1213,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
int count = getTaskViewCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
addDismissedTaskAnimations(getChildAt(i), anim, duration);
|
||||
addDismissedTaskAnimations(getTaskViewAt(i), anim, duration);
|
||||
}
|
||||
|
||||
mPendingAnimation = pendingAnimation;
|
||||
@@ -1204,7 +1221,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
if (onEndListener.isSuccess) {
|
||||
// Remove all the task views now
|
||||
ActivityManagerWrapper.getInstance().removeAllRecentTasks();
|
||||
removeAllViews();
|
||||
removeTasksViewsAndClearAllButton();
|
||||
startHome();
|
||||
}
|
||||
mPendingAnimation = null;
|
||||
@@ -1351,26 +1368,50 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
child.setAlpha(mContentAlpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The most recent task that is older than the currently running task. If there is
|
||||
* currently no running task or there is no task older than it, then return null.
|
||||
*/
|
||||
@Nullable
|
||||
public TaskView getNextTaskView() {
|
||||
TaskView runningTaskView = getRunningTaskView();
|
||||
if (runningTaskView == null) {
|
||||
return null;
|
||||
}
|
||||
return getTaskViewAt(indexOfChild(runningTaskView) + 1);
|
||||
return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() + 1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TaskView getPreviousTaskView() {
|
||||
return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() - 1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TaskView getCurrentPageTaskView() {
|
||||
return getTaskViewAtByAbsoluteIndex(getCurrentPage());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TaskView getNextPageTaskView() {
|
||||
return getTaskViewAtByAbsoluteIndex(getNextPage());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TaskView getTaskViewNearestToCenterOfScreen() {
|
||||
return getTaskViewAtByAbsoluteIndex(getPageNearestToCenterOfScreen());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null instead of indexOutOfBoundsError when index is not in range
|
||||
*/
|
||||
@Nullable
|
||||
public TaskView getTaskViewAt(int index) {
|
||||
View child = getChildAt(index);
|
||||
return child == mClearAllButton ? null : (TaskView) child;
|
||||
return getTaskViewAtByAbsoluteIndex(index + mTaskViewStartIndex);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TaskView getTaskViewAtByAbsoluteIndex(int index) {
|
||||
if (index < getChildCount() && index >= 0) {
|
||||
View child = getChildAt(index);
|
||||
return child instanceof TaskView ? (TaskView) child : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updateEmptyMessage() {
|
||||
boolean isEmpty = getChildCount() == 0;
|
||||
boolean isEmpty = getTaskViewCount() == 0;
|
||||
boolean hasSizeChanged = mLastMeasureSize.x != getWidth()
|
||||
|| mLastMeasureSize.y != getHeight();
|
||||
if (isEmpty == mShowEmptyMessage && !hasSizeChanged) {
|
||||
@@ -1504,7 +1545,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
throw new IllegalStateException("Another pending animation is still running");
|
||||
}
|
||||
|
||||
int count = getChildCount();
|
||||
int count = getTaskViewCount();
|
||||
if (count == 0) {
|
||||
return new PendingAnimation(new AnimatorSet());
|
||||
}
|
||||
@@ -1677,18 +1718,38 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
@Override
|
||||
protected int computeMinScrollX() {
|
||||
if (mIsRtl && mDisallowScrollToClearAll) {
|
||||
// We aren't showing the clear all button, so use the leftmost task as the min scroll.
|
||||
return getScrollForPage(getTaskViewCount() - 1);
|
||||
if (getTaskViewCount() > 0) {
|
||||
if (mDisallowScrollToClearAll) {
|
||||
// We aren't showing the clear all button,
|
||||
// so use the leftmost task as the min scroll.
|
||||
if (mIsRtl) {
|
||||
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
|
||||
}
|
||||
return getScrollForPage(mTaskViewStartIndex);
|
||||
}
|
||||
if (mIsRtl) {
|
||||
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
|
||||
}
|
||||
return getScrollForPage(mTaskViewStartIndex);
|
||||
}
|
||||
return super.computeMinScrollX();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int computeMaxScrollX() {
|
||||
if (!mIsRtl && mDisallowScrollToClearAll) {
|
||||
// We aren't showing the clear all button, so use the rightmost task as the max scroll.
|
||||
return getScrollForPage(getTaskViewCount() - 1);
|
||||
if (getTaskViewCount() > 0) {
|
||||
if (mDisallowScrollToClearAll) {
|
||||
// We aren't showing the clear all button,
|
||||
// so use the rightmost task as the min scroll.
|
||||
if (mIsRtl) {
|
||||
return getScrollForPage(mTaskViewStartIndex);
|
||||
}
|
||||
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
|
||||
}
|
||||
if (mIsRtl) {
|
||||
return getScrollForPage(mTaskViewStartIndex);
|
||||
}
|
||||
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
|
||||
}
|
||||
return super.computeMaxScrollX();
|
||||
}
|
||||
@@ -1740,7 +1801,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
int overlayEnabledPage = mOverlayEnabled ? getNextPage() : -1;
|
||||
int taskCount = getTaskViewCount();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
((TaskView) getChildAt(i)).setOverlayEnabled(i == overlayEnabledPage);
|
||||
getTaskViewAt(i).setOverlayEnabled(i == overlayEnabledPage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1760,4 +1821,25 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
final WindowInsets insets = getRootWindowInsets();
|
||||
return Math.max(insets.getSystemGestureInsets().right, insets.getSystemWindowInsetRight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(View child, int index) {
|
||||
super.addView(child, index);
|
||||
if (isExtraCardView(child, index)) {
|
||||
mTaskViewStartIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeView(View view) {
|
||||
if (isExtraCardView(view, indexOfChild(view))) {
|
||||
mTaskViewStartIndex--;
|
||||
}
|
||||
super.removeView(view);
|
||||
}
|
||||
|
||||
private boolean isExtraCardView(View view, int index) {
|
||||
return !(view instanceof TaskView) && !(view instanceof ClearAllButton)
|
||||
&& index <= mTaskViewStartIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -40,6 +41,7 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.TaskOverlayFactory;
|
||||
|
||||
+38
-1
@@ -39,24 +39,28 @@ import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Property;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.SystemUiController;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.quickstep.TaskOverlayFactory;
|
||||
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
|
||||
import com.android.quickstep.util.TaskCornerRadius;
|
||||
import com.android.systemui.plugins.OverviewScreenshotActions;
|
||||
import com.android.systemui.plugins.PluginListener;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
/**
|
||||
* A task in the Recents view.
|
||||
*/
|
||||
public class TaskThumbnailView extends View {
|
||||
public class TaskThumbnailView extends View implements PluginListener<OverviewScreenshotActions> {
|
||||
|
||||
private final static ColorMatrix COLOR_MATRIX = new ColorMatrix();
|
||||
private final static ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix();
|
||||
@@ -100,6 +104,7 @@ public class TaskThumbnailView extends View {
|
||||
|
||||
private boolean mOverlayEnabled;
|
||||
private boolean mRotated;
|
||||
private OverviewScreenshotActions mOverviewScreenshotActionsPlugin;
|
||||
|
||||
public TaskThumbnailView(Context context) {
|
||||
this(context, null);
|
||||
@@ -147,6 +152,11 @@ public class TaskThumbnailView extends View {
|
||||
mPaint.setShader(null);
|
||||
mOverlay.reset();
|
||||
}
|
||||
|
||||
if (mOverviewScreenshotActionsPlugin != null) {
|
||||
mOverviewScreenshotActionsPlugin
|
||||
.setupActions((ViewGroup) getTaskView(), getThumbnail(), mActivity);
|
||||
}
|
||||
updateThumbnailPaintFilter();
|
||||
}
|
||||
|
||||
@@ -211,6 +221,33 @@ public class TaskThumbnailView extends View {
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginConnected(OverviewScreenshotActions overviewScreenshotActions,
|
||||
Context context) {
|
||||
mOverviewScreenshotActionsPlugin = overviewScreenshotActions;
|
||||
mOverviewScreenshotActionsPlugin.setupActions(getTaskView(), getThumbnail(), mActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginDisconnected(OverviewScreenshotActions plugin) {
|
||||
if (mOverviewScreenshotActionsPlugin != null) {
|
||||
mOverviewScreenshotActionsPlugin = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
PluginManagerWrapper.INSTANCE.get(getContext())
|
||||
.addPluginListener(this, OverviewScreenshotActions.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(this);
|
||||
}
|
||||
|
||||
public RectF getInsetsToDrawInFullscreen(boolean isMultiWindowMode) {
|
||||
// Don't show insets in multi window mode.
|
||||
return isMultiWindowMode ? EMPTY_RECT_F : mClippedInsets;
|
||||
|
||||
@@ -53,6 +53,7 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="recent_task_option_split_screen" msgid="5353188922202653570">"Split screen"</string>
|
||||
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
|
||||
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
|
||||
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overview"</string>
|
||||
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
|
||||
<string name="accessibility_close_task" msgid="5354563209433803643">"Close"</string>
|
||||
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
|
||||
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
|
||||
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
|
||||
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
|
||||
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minute"</string>
|
||||
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> left today"</string>
|
||||
<string name="title_app_suggestions" msgid="4185902664111965088">"App suggestions"</string>
|
||||
<string name="all_apps_label" msgid="8542784161730910663">"All apps"</string>
|
||||
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Your predicted apps"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="recent_task_option_split_screen" msgid="5353188922202653570">"Split screen"</string>
|
||||
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
|
||||
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
|
||||
<string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overview"</string>
|
||||
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
|
||||
<string name="accessibility_close_task" msgid="5354563209433803643">"Close"</string>
|
||||
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
|
||||
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
|
||||
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
|
||||
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
|
||||
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minute"</string>
|
||||
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> left today"</string>
|
||||
<string name="title_app_suggestions" msgid="4185902664111965088">"App suggestions"</string>
|
||||
<string name="all_apps_label" msgid="8542784161730910663">"All apps"</string>
|
||||
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Your predicted apps"</string>
|
||||
</resources>
|
||||
@@ -21,8 +21,6 @@
|
||||
<!-- Activity which blocks home gesture -->
|
||||
<string name="gesture_blocking_activity" translatable="false"></string>
|
||||
|
||||
<string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherExtension</string>
|
||||
|
||||
<string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string>
|
||||
|
||||
<string name="test_information_handler_class" translatable="false">com.android.quickstep.QuickstepTestInformationHandler</string>
|
||||
|
||||
@@ -57,6 +57,9 @@ import android.os.Looper;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
@@ -69,6 +72,7 @@ import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
import com.android.quickstep.util.RemoteAnimationTargetSet;
|
||||
import com.android.quickstep.util.ShelfPeekAnim;
|
||||
import com.android.systemui.shared.system.ActivityCompat;
|
||||
import com.android.systemui.shared.system.ActivityOptionsCompat;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
@@ -80,9 +84,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* {@link LauncherAppTransitionManager} with Quickstep-specific app transitions for launching from
|
||||
* home and/or all-apps.
|
||||
@@ -150,6 +151,8 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
|
||||
private RemoteAnimationProvider mRemoteAnimationProvider;
|
||||
|
||||
private final ShelfPeekAnim mShelfPeekAnim;
|
||||
|
||||
private final AnimatorListenerAdapter mForceInvisibleListener = new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
@@ -177,6 +180,12 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
|
||||
mLauncher.addOnDeviceProfileChangeListener(this);
|
||||
registerRemoteAnimations();
|
||||
|
||||
mShelfPeekAnim = new ShelfPeekAnim(mLauncher);
|
||||
}
|
||||
|
||||
public ShelfPeekAnim getShelfPeekAnim() {
|
||||
return mShelfPeekAnim;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,16 +14,17 @@
|
||||
|
||||
package com.android.launcher3.uioverrides.plugins;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.systemui.shared.plugins.PluginInitializer;
|
||||
|
||||
public class PluginInitializerImpl implements PluginInitializer {
|
||||
@Override
|
||||
public Looper getBgLooper() {
|
||||
return LauncherModel.getWorkerLooper();
|
||||
return MODEL_EXECUTOR.getLooper();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager.AnimationComponents;
|
||||
import com.android.launcher3.touch.AbstractStateChangeTouchController;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
@@ -24,7 +24,7 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro
|
||||
private static final String TAG = "LandscapeEdgeSwipeCtrl";
|
||||
|
||||
public LandscapeEdgeSwipeController(Launcher l) {
|
||||
super(l, SwipeDetector.HORIZONTAL);
|
||||
super(l, SingleAxisSwipeDetector.HORIZONTAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+20
-2
@@ -43,7 +43,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.touch.AbstractStateChangeTouchController;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||
import com.android.launcher3.uioverrides.states.OverviewState;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
@@ -79,7 +79,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
|
||||
private boolean mFinishFastOnSecondTouch;
|
||||
|
||||
public PortraitStatesTouchController(Launcher l, boolean allowDragToOverview) {
|
||||
super(l, SwipeDetector.VERTICAL);
|
||||
super(l, SingleAxisSwipeDetector.VERTICAL);
|
||||
mOverviewPortraitStateTouchHelper = new PortraitOverviewStateTouchHelper(l);
|
||||
mAllowDragToOverview = allowDragToOverview;
|
||||
}
|
||||
@@ -177,6 +177,20 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
|
||||
return builder;
|
||||
}
|
||||
|
||||
private AnimatorSetBuilder getNormalToAllAppsAnimation() {
|
||||
AnimatorSetBuilder builder = new AnimatorSetBuilder();
|
||||
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
|
||||
0, ALL_APPS_CONTENT_FADE_THRESHOLD));
|
||||
return builder;
|
||||
}
|
||||
|
||||
private AnimatorSetBuilder getAllAppsToNormalAnimation() {
|
||||
AnimatorSetBuilder builder = new AnimatorSetBuilder();
|
||||
builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
|
||||
1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1));
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState,
|
||||
LauncherState toState) {
|
||||
@@ -187,6 +201,10 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
|
||||
builder = getOverviewToAllAppsAnimation();
|
||||
} else if (fromState == ALL_APPS && toState == OVERVIEW) {
|
||||
builder = getAllAppsToOverviewAnimation();
|
||||
} else if (fromState == NORMAL && toState == ALL_APPS) {
|
||||
builder = getNormalToAllAppsAnimation();
|
||||
} else if (fromState == ALL_APPS && toState == NORMAL) {
|
||||
builder = getAllAppsToNormalAnimation();
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
import com.android.quickstep.util.RemoteAnimationTargetSet;
|
||||
import com.android.quickstep.util.ShelfPeekAnim;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
@@ -109,16 +110,6 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
|
||||
|
||||
interface AnimationFactory {
|
||||
|
||||
enum ShelfAnimState {
|
||||
HIDE(true), PEEK(true), OVERVIEW(false), CANCEL(false);
|
||||
|
||||
ShelfAnimState(boolean shouldPreformHaptic) {
|
||||
this.shouldPreformHaptic = shouldPreformHaptic;
|
||||
}
|
||||
|
||||
public final boolean shouldPreformHaptic;
|
||||
}
|
||||
|
||||
default void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { }
|
||||
|
||||
void createActivityController(long transitionLength);
|
||||
@@ -127,8 +118,8 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
|
||||
|
||||
default void onTransitionCancelled() { }
|
||||
|
||||
default void setShelfState(ShelfAnimState animState, Interpolator interpolator,
|
||||
long duration) { }
|
||||
default void setShelfState(ShelfPeekAnim.ShelfAnimState animState,
|
||||
Interpolator interpolator, long duration) { }
|
||||
|
||||
/**
|
||||
* @param attached Whether to show RecentsView alongside the app window. If false, recents
|
||||
|
||||
@@ -157,6 +157,6 @@ public abstract class BaseRecentsActivity extends BaseDraggingActivity {
|
||||
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
|
||||
super.dump(prefix, fd, writer, args);
|
||||
writer.println(prefix + "Misc:");
|
||||
dumpMisc(writer);
|
||||
dumpMisc(prefix + "\t", writer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,20 +15,21 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
/**
|
||||
* Sets alpha for the back button
|
||||
*/
|
||||
@@ -62,7 +63,7 @@ public class OverviewInteractionState {
|
||||
// because of its high send frequency and data may be very different than the previous value
|
||||
// For example, send back alpha on uihandler to avoid flickering when setting its visibility
|
||||
mUiHandler = new Handler(this::handleUiMessage);
|
||||
mBgHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleBgMessage);
|
||||
mBgHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleBgMessage);
|
||||
|
||||
onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(context)
|
||||
.addModeChangeListener(this::onNavigationModeChanged));
|
||||
|
||||
@@ -16,19 +16,22 @@
|
||||
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.util.SparseBooleanArray;
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.KeyguardManagerCompat;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -41,7 +44,8 @@ import java.util.function.Consumer;
|
||||
public class RecentTasksList extends TaskStackChangeListener {
|
||||
|
||||
private final KeyguardManagerCompat mKeyguardManager;
|
||||
private final MainThreadExecutor mMainThreadExecutor;
|
||||
private final LooperExecutor mMainThreadExecutor;
|
||||
private final ActivityManagerWrapper mActivityManagerWrapper;
|
||||
|
||||
// The list change id, increments as the task list changes in the system
|
||||
private int mChangeId;
|
||||
@@ -52,11 +56,13 @@ public class RecentTasksList extends TaskStackChangeListener {
|
||||
|
||||
ArrayList<Task> mTasks = new ArrayList<>();
|
||||
|
||||
public RecentTasksList(Context context) {
|
||||
mMainThreadExecutor = new MainThreadExecutor();
|
||||
mKeyguardManager = new KeyguardManagerCompat(context);
|
||||
public RecentTasksList(LooperExecutor mainThreadExecutor,
|
||||
KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) {
|
||||
mMainThreadExecutor = mainThreadExecutor;
|
||||
mKeyguardManager = keyguardManager;
|
||||
mChangeId = 1;
|
||||
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
|
||||
mActivityManagerWrapper = activityManagerWrapper;
|
||||
mActivityManagerWrapper.registerTaskStackListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +70,7 @@ public class RecentTasksList extends TaskStackChangeListener {
|
||||
*/
|
||||
public void getTaskKeys(int numTasks, Consumer<ArrayList<Task>> callback) {
|
||||
// Kick off task loading in the background
|
||||
BACKGROUND_EXECUTOR.execute(() -> {
|
||||
UI_HELPER_EXECUTOR.execute(() -> {
|
||||
ArrayList<Task> tasks = loadTasksInBackground(numTasks, true /* loadKeysOnly */);
|
||||
mMainThreadExecutor.execute(() -> callback.accept(tasks));
|
||||
});
|
||||
@@ -86,12 +92,12 @@ public class RecentTasksList extends TaskStackChangeListener {
|
||||
if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) {
|
||||
// The list is up to date, send the callback on the next frame,
|
||||
// so that requestID can be returned first.
|
||||
mMainThreadExecutor.getHandler().post(resultCallback);
|
||||
mMainThreadExecutor.post(resultCallback);
|
||||
return requestLoadId;
|
||||
}
|
||||
|
||||
// Kick off task loading in the background
|
||||
BACKGROUND_EXECUTOR.execute(() -> {
|
||||
UI_HELPER_EXECUTOR.execute(() -> {
|
||||
ArrayList<Task> tasks = loadTasksInBackground(Integer.MAX_VALUE, loadKeysOnly);
|
||||
|
||||
mMainThreadExecutor.execute(() -> {
|
||||
@@ -136,12 +142,13 @@ public class RecentTasksList extends TaskStackChangeListener {
|
||||
/**
|
||||
* Loads and creates a list of all the recent tasks.
|
||||
*/
|
||||
private ArrayList<Task> loadTasksInBackground(int numTasks,
|
||||
@VisibleForTesting
|
||||
ArrayList<Task> loadTasksInBackground(int numTasks,
|
||||
boolean loadKeysOnly) {
|
||||
int currentUserId = Process.myUserHandle().getIdentifier();
|
||||
ArrayList<Task> allTasks = new ArrayList<>();
|
||||
List<ActivityManager.RecentTaskInfo> rawTasks =
|
||||
ActivityManagerWrapper.getInstance().getRecentTasks(numTasks, currentUserId);
|
||||
mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId);
|
||||
// The raw tasks are given in most-recent to least-recent order, we need to reverse it
|
||||
Collections.reverse(rawTasks);
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -22,7 +24,6 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
|
||||
@@ -92,14 +93,10 @@ public class RecentsActivityTracker<T extends BaseRecentsActivity> implements Ac
|
||||
private static class Scheduler implements Runnable {
|
||||
|
||||
private WeakReference<RecentsActivityTracker> mPendingTracker = new WeakReference<>(null);
|
||||
private MainThreadExecutor mMainThreadExecutor;
|
||||
|
||||
public synchronized void schedule(RecentsActivityTracker tracker) {
|
||||
mPendingTracker = new WeakReference<>(tracker);
|
||||
if (mMainThreadExecutor == null) {
|
||||
mMainThreadExecutor = new MainThreadExecutor();
|
||||
}
|
||||
mMainThreadExecutor.execute(this);
|
||||
MAIN_EXECUTOR.execute(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.createAndStartNewLooper;
|
||||
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
@@ -22,16 +26,20 @@ import android.app.ActivityManager;
|
||||
import android.content.ComponentCallbacks2;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.LauncherAppsCompat.OnAppsChangedCallbackCompat;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
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.KeyguardManagerCompat;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -61,13 +69,14 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
|
||||
private RecentsModel(Context context) {
|
||||
mContext = context;
|
||||
HandlerThread loaderThread = new HandlerThread("TaskThumbnailIconCache",
|
||||
Process.THREAD_PRIORITY_BACKGROUND);
|
||||
loaderThread.start();
|
||||
mTaskList = new RecentTasksList(context);
|
||||
mIconCache = new TaskIconCache(context, loaderThread.getLooper());
|
||||
mThumbnailCache = new TaskThumbnailCache(context, loaderThread.getLooper());
|
||||
Looper looper =
|
||||
createAndStartNewLooper("TaskThumbnailIconCache", THREAD_PRIORITY_BACKGROUND);
|
||||
mTaskList = new RecentTasksList(MAIN_EXECUTOR,
|
||||
new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance());
|
||||
mIconCache = new TaskIconCache(context, looper);
|
||||
mThumbnailCache = new TaskThumbnailCache(context, looper);
|
||||
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
|
||||
setupPackageListener();
|
||||
}
|
||||
|
||||
public TaskIconCache getIconCache() {
|
||||
@@ -166,6 +175,7 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
public void onTaskRemoved(int taskId) {
|
||||
Task.TaskKey dummyKey = new Task.TaskKey(taskId, 0, null, null, 0, 0);
|
||||
mThumbnailCache.remove(dummyKey);
|
||||
mIconCache.onTaskRemoved(dummyKey);
|
||||
}
|
||||
|
||||
public void setSystemUiProxy(ISystemUiProxy systemUiProxy) {
|
||||
@@ -200,6 +210,21 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
}
|
||||
}
|
||||
|
||||
private void setupPackageListener() {
|
||||
LauncherAppsCompat.getInstance(mContext)
|
||||
.addOnAppsChangedCallback(new OnAppsChangedCallbackCompat() {
|
||||
@Override
|
||||
public void onPackageRemoved(String packageName, UserHandle user) {
|
||||
mIconCache.invalidatePackage(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageChanged(String packageName, UserHandle user) {
|
||||
mIconCache.invalidatePackage(packageName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addThumbnailChangeListener(TaskThumbnailChangeListener listener) {
|
||||
mThumbnailChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.uioverrides.RecentsUiFactory.GO_LOW_RAM_RECENTS_ENABLED;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -27,26 +28,25 @@ import android.os.Looper;
|
||||
import android.util.LruCache;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.icons.cache.HandlerRunnable;
|
||||
import com.android.launcher3.uioverrides.RecentsUiFactory;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.Task.TaskKey;
|
||||
import com.android.systemui.shared.recents.model.TaskKeyLruCache;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Manages the caching of task icons and related data.
|
||||
* TODO: This class should later be merged into IconCache.
|
||||
* TODO(b/138944598): This class should later be merged into IconCache.
|
||||
*/
|
||||
public class TaskIconCache {
|
||||
|
||||
private final Handler mBackgroundHandler;
|
||||
private final MainThreadExecutor mMainThreadExecutor;
|
||||
private final AccessibilityManager mAccessibilityManager;
|
||||
|
||||
private final NormalizedIconLoader mIconLoader;
|
||||
@@ -67,7 +67,6 @@ public class TaskIconCache {
|
||||
|
||||
public TaskIconCache(Context context, Looper backgroundLooper) {
|
||||
mBackgroundHandler = new Handler(backgroundLooper);
|
||||
mMainThreadExecutor = new MainThreadExecutor();
|
||||
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
|
||||
|
||||
Resources res = context.getResources();
|
||||
@@ -103,7 +102,7 @@ public class TaskIconCache {
|
||||
// We don't call back to the provided callback in this case
|
||||
return;
|
||||
}
|
||||
mMainThreadExecutor.execute(() -> {
|
||||
MAIN_EXECUTOR.execute(() -> {
|
||||
task.icon = icon;
|
||||
task.titleDescription = contentDescription;
|
||||
callback.accept(task);
|
||||
@@ -149,6 +148,21 @@ public class TaskIconCache {
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
void onTaskRemoved(TaskKey taskKey) {
|
||||
mIconCache.remove(taskKey);
|
||||
}
|
||||
|
||||
void invalidatePackage(String packageName) {
|
||||
// TODO(b/138944598): Merge this class into IconCache so we can do this at the base level
|
||||
Map<ComponentName, ActivityInfo> activityInfoCache = mActivityInfoCache.snapshot();
|
||||
for (ComponentName cn : activityInfoCache.keySet()) {
|
||||
if (cn.getPackageName().equals(packageName)) {
|
||||
mActivityInfoCache.remove(cn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class IconLoadRequest extends HandlerRunnable {
|
||||
IconLoadRequest(Handler handler) {
|
||||
super(handler, null);
|
||||
|
||||
@@ -15,12 +15,14 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.icons.cache.HandlerRunnable;
|
||||
@@ -30,13 +32,13 @@ import com.android.systemui.shared.recents.model.Task.TaskKey;
|
||||
import com.android.systemui.shared.recents.model.TaskKeyLruCache;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class TaskThumbnailCache {
|
||||
|
||||
private final Handler mBackgroundHandler;
|
||||
private final MainThreadExecutor mMainThreadExecutor;
|
||||
|
||||
private final int mCacheSize;
|
||||
private final ThumbnailCache mCache;
|
||||
@@ -94,7 +96,6 @@ public class TaskThumbnailCache {
|
||||
|
||||
public TaskThumbnailCache(Context context, Looper backgroundLooper) {
|
||||
mBackgroundHandler = new Handler(backgroundLooper);
|
||||
mMainThreadExecutor = new MainThreadExecutor();
|
||||
mHighResLoadingState = new HighResLoadingState(context);
|
||||
|
||||
Resources res = context.getResources();
|
||||
@@ -168,7 +169,7 @@ public class TaskThumbnailCache {
|
||||
// We don't call back to the provided callback in this case
|
||||
return;
|
||||
}
|
||||
mMainThreadExecutor.execute(() -> {
|
||||
MAIN_EXECUTOR.execute(() -> {
|
||||
mCache.put(key, thumbnail);
|
||||
callback.accept(thumbnail);
|
||||
onEnd();
|
||||
|
||||
@@ -29,12 +29,16 @@ import android.content.Intent;
|
||||
import android.stats.launcher.nano.Launcher;
|
||||
import android.stats.launcher.nano.LauncherExtension;
|
||||
import android.stats.launcher.nano.LauncherTarget;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
import com.android.launcher3.logging.StatsLogUtils;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.systemui.shared.system.StatsLogCompat;
|
||||
import com.google.protobuf.nano.MessageNano;
|
||||
@@ -50,6 +54,8 @@ import com.google.protobuf.nano.MessageNano;
|
||||
public class StatsLogCompatManager extends StatsLogManager {
|
||||
|
||||
private static final int SUPPORTED_TARGET_DEPTH = 2;
|
||||
private static final String TAG = "StatsLogCompatManager";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
public StatsLogCompatManager(Context context) { }
|
||||
|
||||
@@ -59,6 +65,9 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH];
|
||||
int srcState = mStateProvider.getCurrentState();
|
||||
fillInLauncherExtension(v, ext);
|
||||
if (ext.srcTarget[0] != null) {
|
||||
ext.srcTarget[0].item = LauncherTarget.APP_ICON;
|
||||
}
|
||||
StatsLogCompat.write(LAUNCH_APP, srcState, BACKGROUND /* dstState */,
|
||||
MessageNano.toByteArray(ext), true);
|
||||
}
|
||||
@@ -95,28 +104,132 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
}
|
||||
|
||||
public static boolean fillInLauncherExtension(View v, LauncherExtension extension) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "fillInLauncherExtension");
|
||||
}
|
||||
|
||||
StatsLogUtils.LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v);
|
||||
if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "View or provider is null, or view doesn't have an ItemInfo tag.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
ItemInfo itemInfo = (ItemInfo) v.getTag();
|
||||
Target child = new Target();
|
||||
Target parent = new Target();
|
||||
provider.fillInLogContainerData(v, itemInfo, child, parent);
|
||||
extension.srcTarget[0] = new LauncherTarget();
|
||||
extension.srcTarget[1] = new LauncherTarget();
|
||||
copy(child, extension.srcTarget[0]);
|
||||
copy(parent, extension.srcTarget[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean fillInLauncherExtensionWithPageId(LauncherExtension ext, int pageId) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "fillInLauncherExtensionWithPageId, pageId = " + pageId);
|
||||
}
|
||||
|
||||
Target target = new Target();
|
||||
target.pageIndex = pageId;
|
||||
ext.srcTarget[0] = new LauncherTarget();
|
||||
copy(target, ext.srcTarget[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void copy(Target src, LauncherTarget dst) {
|
||||
// fill in
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "copy target information from clearcut Target to LauncherTarget.");
|
||||
}
|
||||
|
||||
// Fill in type
|
||||
switch (src.type) {
|
||||
case Target.Type.ITEM:
|
||||
dst.type = LauncherTarget.ITEM_TYPE;
|
||||
break;
|
||||
case Target.Type.CONTROL:
|
||||
dst.type = LauncherTarget.CONTROL_TYPE;
|
||||
break;
|
||||
case Target.Type.CONTAINER:
|
||||
dst.type = LauncherTarget.CONTAINER_TYPE;
|
||||
break;
|
||||
default:
|
||||
dst.type = LauncherTarget.NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in item
|
||||
switch (src.itemType) {
|
||||
case ItemType.APP_ICON:
|
||||
dst.item = LauncherTarget.APP_ICON;
|
||||
break;
|
||||
case ItemType.SHORTCUT:
|
||||
dst.item = LauncherTarget.SHORTCUT;
|
||||
break;
|
||||
case ItemType.WIDGET:
|
||||
dst.item = LauncherTarget.WIDGET;
|
||||
break;
|
||||
case ItemType.FOLDER_ICON:
|
||||
dst.item = LauncherTarget.FOLDER_ICON;
|
||||
break;
|
||||
case ItemType.DEEPSHORTCUT:
|
||||
dst.item = LauncherTarget.DEEPSHORTCUT;
|
||||
break;
|
||||
case ItemType.SEARCHBOX:
|
||||
dst.item = LauncherTarget.SEARCHBOX;
|
||||
break;
|
||||
case ItemType.EDITTEXT:
|
||||
dst.item = LauncherTarget.EDITTEXT;
|
||||
break;
|
||||
case ItemType.NOTIFICATION:
|
||||
dst.item = LauncherTarget.NOTIFICATION;
|
||||
break;
|
||||
case ItemType.TASK:
|
||||
dst.item = LauncherTarget.TASK;
|
||||
break;
|
||||
default:
|
||||
dst.item = LauncherTarget.DEFAULT_ITEM;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in container
|
||||
switch (src.containerType) {
|
||||
case ContainerType.HOTSEAT:
|
||||
dst.container = LauncherTarget.HOTSEAT;
|
||||
break;
|
||||
case ContainerType.FOLDER:
|
||||
dst.container = LauncherTarget.FOLDER;
|
||||
break;
|
||||
case ContainerType.PREDICTION:
|
||||
dst.container = LauncherTarget.PREDICTION;
|
||||
break;
|
||||
case ContainerType.SEARCHRESULT:
|
||||
dst.container = LauncherTarget.SEARCHRESULT;
|
||||
break;
|
||||
default:
|
||||
dst.container = LauncherTarget.DEFAULT_CONTAINER;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in control
|
||||
switch (src.controlType) {
|
||||
case ControlType.UNINSTALL_TARGET:
|
||||
dst.control = LauncherTarget.UNINSTALL;
|
||||
break;
|
||||
case ControlType.REMOVE_TARGET:
|
||||
dst.control = LauncherTarget.REMOVE;
|
||||
break;
|
||||
default:
|
||||
dst.control = LauncherTarget.DEFAULT_CONTROL;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in other fields
|
||||
dst.pageId = src.pageIndex;
|
||||
dst.gridX = src.gridX;
|
||||
dst.gridY = src.gridY;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,10 +20,10 @@ import android.util.Log;
|
||||
|
||||
import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CANCEL_TARGET;
|
||||
import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE;
|
||||
import static com.android.systemui.shared.system.LauncherEventUtil.DISMISS;
|
||||
import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_QUICK_SCRUB_ONBOARDING_TIP;
|
||||
import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_SWIPE_UP_ONBOARDING_TIP;
|
||||
import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE;
|
||||
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.quickstep.util;
|
||||
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.TaskInfo;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.TaskInfoCompat;
|
||||
|
||||
/**
|
||||
* Utility class for interacting with the Assistant.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.Q)
|
||||
public final class AssistantUtilities {
|
||||
|
||||
/** Returns true if an Assistant activity that is excluded from recents is running. */
|
||||
public static boolean isExcludedAssistantRunning() {
|
||||
return isExcludedAssistant(ActivityManagerWrapper.getInstance().getRunningTask());
|
||||
}
|
||||
|
||||
/** Returns true if the given task holds an Assistant activity that is excluded from recents. */
|
||||
public static boolean isExcludedAssistant(TaskInfo info) {
|
||||
return info != null
|
||||
&& TaskInfoCompat.getActivityType(info) == ACTIVITY_TYPE_ASSISTANT
|
||||
&& (info.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
|
||||
}
|
||||
|
||||
private AssistantUtilities() {}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import androidx.annotation.IntDef;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
@@ -39,12 +39,27 @@ public class LayoutUtils {
|
||||
@IntDef({MULTI_WINDOW_STRATEGY_HALF_SCREEN, MULTI_WINDOW_STRATEGY_DEVICE_PROFILE})
|
||||
private @interface MultiWindowStrategy {}
|
||||
|
||||
/**
|
||||
* The height for the swipe up motion
|
||||
*/
|
||||
public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) {
|
||||
float swipeHeight = dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
|
||||
if (SysUINavigationMode.getMode(context) == SysUINavigationMode.Mode.NO_BUTTON) {
|
||||
swipeHeight -= dp.getInsets().bottom;
|
||||
}
|
||||
return swipeHeight;
|
||||
}
|
||||
|
||||
public static void calculateLauncherTaskSize(Context context, DeviceProfile dp, Rect outRect) {
|
||||
float extraSpace;
|
||||
if (dp.isVerticalBarLayout()) {
|
||||
extraSpace = 0;
|
||||
} else {
|
||||
extraSpace = dp.hotseatBarSizePx + dp.verticalDragHandleSizePx;
|
||||
Resources res = context.getResources();
|
||||
|
||||
extraSpace = getDefaultSwipeHeight(context, dp) + dp.verticalDragHandleSizePx
|
||||
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size)
|
||||
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
|
||||
}
|
||||
calculateTaskSize(context, dp, extraSpace, MULTI_WINDOW_STRATEGY_HALF_SCREEN, outRect);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.quickstep.views;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.QUICK_SWITCH;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
@@ -35,15 +36,18 @@ import android.util.AttributeSet;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.QuickstepAppTransitionManagerImpl;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.uioverrides.states.OverviewState;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.ScrimView;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.util.ShelfPeekAnim;
|
||||
|
||||
/**
|
||||
* Scrim used for all-apps and shelf in Overview
|
||||
@@ -161,9 +165,9 @@ public class ShelfScrimView extends ScrimView implements NavigationModeChangeLis
|
||||
mMidProgress = OVERVIEW.getVerticalProgress(mLauncher);
|
||||
Rect hotseatPadding = dp.getHotseatLayoutPadding();
|
||||
int hotseatSize = dp.hotseatBarSizePx + dp.getInsets().bottom
|
||||
- hotseatPadding.bottom - hotseatPadding.top;
|
||||
+ hotseatPadding.bottom + hotseatPadding.top;
|
||||
float dragHandleTop =
|
||||
Math.min(hotseatSize, OverviewState.getDefaultSwipeHeight(context, dp));
|
||||
Math.min(hotseatSize, LayoutUtils.getDefaultSwipeHeight(context, dp));
|
||||
mDragHandleProgress = 1 - (dragHandleTop / mShiftRange);
|
||||
}
|
||||
mTopOffset = dp.getInsets().top - mShelfOffset;
|
||||
@@ -193,8 +197,12 @@ public class ShelfScrimView extends ScrimView implements NavigationModeChangeLis
|
||||
if (mProgress >= 1) {
|
||||
mRemainingScreenColor = 0;
|
||||
mShelfColor = 0;
|
||||
ShelfPeekAnim shelfPeekAnim = ((QuickstepAppTransitionManagerImpl)
|
||||
mLauncher.getAppTransitionManager()).getShelfPeekAnim();
|
||||
LauncherState state = mLauncher.getStateManager().getState();
|
||||
if (mSysUINavigationMode == Mode.NO_BUTTON
|
||||
&& mLauncher.getStateManager().getState() == BACKGROUND_APP) {
|
||||
&& (state == BACKGROUND_APP || state == QUICK_SWITCH)
|
||||
&& shelfPeekAnim.isPeeking()) {
|
||||
// Show the shelf background when peeking during swipe up.
|
||||
mShelfColor = setColorAlphaBound(mEndScrim, mMidAlpha);
|
||||
}
|
||||
|
||||
@@ -150,10 +150,10 @@ public class AppPredictionsUITests extends AbstractQuickStepTest {
|
||||
List<AppTarget> targets = new ArrayList<>(activities.length);
|
||||
for (LauncherActivityInfo info : activities) {
|
||||
ComponentName cn = info.getComponentName();
|
||||
AppTarget target =
|
||||
new AppTarget.Builder(new AppTargetId("app:" + cn), cn.getPackageName(), info.getUser())
|
||||
.setClassName(cn.getClassName())
|
||||
.build();
|
||||
AppTarget target = new AppTarget.Builder(
|
||||
new AppTargetId("app:" + cn), cn.getPackageName(), info.getUser())
|
||||
.setClassName(cn.getClassName())
|
||||
.build();
|
||||
targets.add(target);
|
||||
}
|
||||
mCallback.onTargetsAvailable(targets);
|
||||
|
||||
@@ -42,6 +42,7 @@ import androidx.test.uiautomator.UiDevice;
|
||||
import androidx.test.uiautomator.Until;
|
||||
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation;
|
||||
import com.android.launcher3.tapl.TestHelpers;
|
||||
import com.android.launcher3.testcomponent.TestCommandReceiver;
|
||||
import com.android.launcher3.util.rule.FailureWatcher;
|
||||
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
||||
@@ -78,7 +79,7 @@ public class FallbackRecentsTest {
|
||||
Context context = instrumentation.getContext();
|
||||
mDevice = UiDevice.getInstance(instrumentation);
|
||||
mDevice.setOrientationNatural();
|
||||
mLauncher = new LauncherInstrumentation(instrumentation);
|
||||
mLauncher = new LauncherInstrumentation();
|
||||
|
||||
mOrderSensitiveRules = RuleChain.
|
||||
outerRule(new NavigationModeSwitchRule(mLauncher)).
|
||||
@@ -103,6 +104,11 @@ public class FallbackRecentsTest {
|
||||
}
|
||||
}
|
||||
};
|
||||
if (TestHelpers.isInLauncherProcess()) {
|
||||
mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand(
|
||||
TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()).
|
||||
getString("result"));
|
||||
}
|
||||
}
|
||||
|
||||
@NavigationModeSwitch(mode = THREE_BUTTON)
|
||||
|
||||
@@ -181,7 +181,7 @@ public class NavigationModeSwitchRule implements TestRule {
|
||||
SysUINavigationMode.INSTANCE.get(targetContext);
|
||||
targetContext.getMainExecutor().execute(() ->
|
||||
sysUINavigationMode.addModeChangeListener(listener));
|
||||
latch.await(10, TimeUnit.SECONDS);
|
||||
latch.await(60, TimeUnit.SECONDS);
|
||||
targetContext.getMainExecutor().execute(() ->
|
||||
sysUINavigationMode.removeModeChangeListener(listener));
|
||||
assertTrue("Navigation mode didn't change to " + expectedMode,
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.quickstep;
|
||||
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.KeyguardManagerCompat;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
public class RecentTasksListTest {
|
||||
|
||||
private ActivityManagerWrapper mockActivityManagerWrapper;
|
||||
|
||||
// Class under test
|
||||
private RecentTasksList mRecentTasksList;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
LooperExecutor mockMainThreadExecutor = mock(LooperExecutor.class);
|
||||
KeyguardManagerCompat mockKeyguardManagerCompat = mock(KeyguardManagerCompat.class);
|
||||
mockActivityManagerWrapper = mock(ActivityManagerWrapper.class);
|
||||
mRecentTasksList = new RecentTasksList(mockMainThreadExecutor, mockKeyguardManagerCompat,
|
||||
mockActivityManagerWrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTaskRemoved_reloadsAllTasks() {
|
||||
mRecentTasksList.onTaskRemoved(0);
|
||||
verify(mockActivityManagerWrapper, times(1))
|
||||
.getRecentTasks(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTaskStackChanged_doesNotFetchTasks() {
|
||||
mRecentTasksList.onTaskStackChanged();
|
||||
verify(mockActivityManagerWrapper, times(0))
|
||||
.getRecentTasks(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadTasksInBackground_onlyKeys_noValidTaskDescription() {
|
||||
ActivityManager.RecentTaskInfo recentTaskInfo = new ActivityManager.RecentTaskInfo();
|
||||
when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
|
||||
.thenReturn(Collections.singletonList(recentTaskInfo));
|
||||
|
||||
List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, true);
|
||||
|
||||
assertEquals(1, taskList.size());
|
||||
assertNull(taskList.get(0).taskDescription.getLabel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadTasksInBackground_moreThanKeys_hasValidTaskDescription() {
|
||||
String taskDescription = "Wheeee!";
|
||||
ActivityManager.RecentTaskInfo recentTaskInfo = new ActivityManager.RecentTaskInfo();
|
||||
recentTaskInfo.taskDescription = new ActivityManager.TaskDescription(taskDescription);
|
||||
when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
|
||||
.thenReturn(Collections.singletonList(recentTaskInfo));
|
||||
|
||||
List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, false);
|
||||
|
||||
assertEquals(1, taskList.size());
|
||||
assertEquals(taskDescription, taskList.get(0).taskDescription.getLabel());
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation;
|
||||
import com.android.launcher3.util.RaceConditionReproducer;
|
||||
import com.android.quickstep.NavigationModeSwitchRule.Mode;
|
||||
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
||||
@@ -80,8 +79,6 @@ public class StartLauncherViaGestureTests extends AbstractQuickStepTest {
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
public void testStressPressHome() {
|
||||
if (LauncherInstrumentation.isAvd()) return; // b/136278866
|
||||
|
||||
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
|
||||
// Destroy Launcher activity.
|
||||
closeLauncherActivity();
|
||||
@@ -94,8 +91,6 @@ public class StartLauncherViaGestureTests extends AbstractQuickStepTest {
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
public void testStressSwipeToOverview() {
|
||||
if (LauncherInstrumentation.isAvd()) return; // b/136278866
|
||||
|
||||
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
|
||||
// Destroy Launcher activity.
|
||||
closeLauncherActivity();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -34,6 +35,7 @@ import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.tapl.AllApps;
|
||||
import com.android.launcher3.tapl.AllAppsFromOverview;
|
||||
import com.android.launcher3.tapl.Background;
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel;
|
||||
import com.android.launcher3.tapl.Overview;
|
||||
import com.android.launcher3.tapl.OverviewTask;
|
||||
import com.android.launcher3.tapl.TestHelpers;
|
||||
@@ -210,16 +212,21 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
@PortraitLandscape
|
||||
public void testBackground() throws Exception {
|
||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||
final Background background = getAndAssertBackground();
|
||||
|
||||
assertNotNull("Background.switchToOverview() returned null", background.switchToOverview());
|
||||
assertTrue("Launcher internal state didn't switch to Overview",
|
||||
isInState(LauncherState.OVERVIEW));
|
||||
}
|
||||
|
||||
private Background getAndAssertBackground() {
|
||||
final Background background = mLauncher.getBackground();
|
||||
assertNotNull("Launcher.getBackground() returned null", background);
|
||||
executeOnLauncher(launcher -> assertTrue(
|
||||
"Launcher activity is the top activity; expecting another activity to be the top "
|
||||
+ "one",
|
||||
isInBackground(launcher)));
|
||||
|
||||
assertNotNull("Background.switchToOverview() returned null", background.switchToOverview());
|
||||
assertTrue("Launcher internal state didn't switch to Overview",
|
||||
isInState(LauncherState.OVERVIEW));
|
||||
return background;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -237,4 +244,47 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL));
|
||||
assertNotNull("getHome returned null", mLauncher.getWorkspace());
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
@PortraitLandscape
|
||||
public void testQuickSwitchFromApp() throws Exception {
|
||||
startTestActivity(2);
|
||||
startTestActivity(3);
|
||||
startTestActivity(4);
|
||||
|
||||
Background background = getAndAssertBackground();
|
||||
background.quickSwitchToPreviousApp();
|
||||
assertTrue("The first app we should have quick switched to is not running",
|
||||
isTestActivityRunning(3));
|
||||
|
||||
background = getAndAssertBackground();
|
||||
background.quickSwitchToPreviousApp();
|
||||
if (mLauncher.getNavigationModel() == NavigationModel.THREE_BUTTON) {
|
||||
// 3-button mode toggles between 2 apps, rather than going back further.
|
||||
assertTrue("Second quick switch should have returned to the first app.",
|
||||
isTestActivityRunning(4));
|
||||
} else {
|
||||
assertTrue("The second app we should have quick switched to is not running",
|
||||
isTestActivityRunning(2));
|
||||
}
|
||||
getAndAssertBackground();
|
||||
}
|
||||
|
||||
private boolean isTestActivityRunning(int activityNumber) {
|
||||
return mDevice.wait(Until.hasObject(By.pkg(getAppPackageName())
|
||||
.text("TestActivity" + activityNumber)),
|
||||
DEFAULT_UI_TIMEOUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
@PortraitLandscape
|
||||
public void testQuickSwitchFromHome() throws Exception {
|
||||
startTestActivity(2);
|
||||
mLauncher.pressHome().quickSwitchToPreviousApp();
|
||||
assertTrue("The most recent task is not running after quick switching from home",
|
||||
isTestActivityRunning(2));
|
||||
getAndAssertBackground();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,5 @@
|
||||
style="@style/BaseIcon"
|
||||
android:textColor="?attr/folderTextColor"
|
||||
android:includeFontPadding="false"
|
||||
android:hapticFeedbackEnabled="false"
|
||||
launcher:iconDisplay="folder" />
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"Werk"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"Program is nie geïnstalleer nie."</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"Program is nie beskikbaar nie"</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"ስራ"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"መተግበሪያ አልተጫነም።"</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"መተግበሪያ አይገኝም"</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"العمل"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"لم يتم تثبيت التطبيق."</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"التطبيق ليس متاحًا"</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"কৰ্মস্থান"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"এপটো ইনষ্টল কৰা নহ\'ল।"</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"এপটো নাই"</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"İş"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"Tətbiq quraşdırılmayıb."</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"Tətbiq əlçatmazdır"</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"Aplikacija nije instalirana."</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"Aplikacija nije dostupna"</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"Працоўная"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"Праграма не ўсталявана."</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"Праграма недаступная"</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"Работа"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"Приложението не е инсталирано."</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"Приложението не е налично"</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"কাজ"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"অ্যাপ্লিকেশান ইনস্টল করা নেই৷"</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"অ্যাপ্লিকেশান অনুপলব্ধ"</string>
|
||||
@@ -93,7 +92,7 @@
|
||||
<string name="title_change_settings" msgid="1376365968844349552">"সেটিংস পরিবর্তন করুন"</string>
|
||||
<string name="notification_dots_service_title" msgid="4284221181793592871">"বিজ্ঞপ্তির ডট দেখুন"</string>
|
||||
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"হোম স্ক্রিনে আইকন যোগ করুন"</string>
|
||||
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"নতুন অ্যাপ্লিকেশানগুলির জন্যে"</string>
|
||||
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"নতুন অ্যাপের জন্য"</string>
|
||||
<string name="package_state_unknown" msgid="7592128424511031410">"অজানা"</string>
|
||||
<string name="abandoned_clean_this" msgid="7610119707847920412">"সরান"</string>
|
||||
<string name="abandoned_search" msgid="891119232568284442">"সার্চ"</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"Posao"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"Aplikacija nije instalirana."</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"Aplikacija nije dostupna"</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
|
||||
<string name="folder_name" msgid="7371454440695724752"></string>
|
||||
<string name="work_folder_name" msgid="3753320833950115786">"Feina"</string>
|
||||
<string name="activity_not_found" msgid="8071924732094499514">"L\'aplicació no s\'ha instal·lat."</string>
|
||||
<string name="activity_not_available" msgid="7456344436509528827">"L\'aplicació no està disponible."</string>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user