Merge "Deleting sample code demonstrating how to extend Launcher3" into ub-launcher3-master
diff --git a/Android.mk b/Android.mk
index 4cc5e42..282b878 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,6 +17,14 @@
LOCAL_PATH := $(call my-dir)
#
+# Prebuilt Java Libraries
+#
+include $(CLEAR_VARS)
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+ libSharedSystemUI:quickstep/libs/sysui_shared.jar
+include $(BUILD_MULTI_PREBUILT)
+
+#
# Build rule for Launcher3 app.
#
include $(CLEAR_VARS)
@@ -112,22 +120,58 @@
include $(BUILD_PACKAGE)
#
-# Launcher proto buffer jar used for development
+# Build rule for Quickstep app.
#
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-proto-files-under, protos) $(call all-proto-files-under, proto_overrides)
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-v4 \
+ android-support-v7-recyclerview \
+ android-support-dynamic-animation \
+ libSharedSystemUI
+
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src) \
+ $(call all-java-files-under, src_config) \
+ $(call all-java-files-under, quickstep/src) \
+ $(call all-java-files-under, quickstep/src_flags) \
+ $(call all-proto-files-under, protos) \
+ $(call all-proto-files-under, proto_overrides)
+
+LOCAL_RESOURCE_DIR := \
+ $(LOCAL_PATH)/quickstep/res \
+ $(LOCAL_PATH)/res \
+ prebuilts/sdk/current/support/v7/recyclerview/res \
+
+LOCAL_PROGUARD_ENABLED := disabled
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := launcher_proto_lib
-LOCAL_IS_HOST_MODULE := true
-LOCAL_STATIC_JAVA_LIBRARIES := host-libprotobuf-java-nano
+LOCAL_AAPT_FLAGS := \
+ --auto-add-overlay \
+ --extra-packages android.support.v7.recyclerview \
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_SDK_VERSION := system_current
+LOCAL_MIN_SDK_VERSION := 26
+LOCAL_PACKAGE_NAME := Launcher3QuickStep
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
+
+LOCAL_FULL_LIBS_MANIFEST_FILES := \
+ $(LOCAL_PATH)/AndroidManifest.xml \
+ $(LOCAL_PATH)/AndroidManifest-common.xml
+
+LOCAL_MANIFEST_FILE := quickstep/AndroidManifest.xml
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
+
+include $(BUILD_PACKAGE)
+
+
+
# ==================================================
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/build.gradle b/build.gradle
index a1b3a60..f357e5c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -40,7 +40,20 @@
applicationId 'com.android.launcher3'
testApplicationId 'com.android.launcher3.tests'
}
+
+ quickstep {
+ applicationId 'com.android.launcher3'
+ testApplicationId 'com.android.launcher3.tests'
+ }
}
+
+ // Disable release builds for now
+ android.variantFilter { variant ->
+ if (variant.buildType.name.endsWith('release')) {
+ variant.setIgnore(true);
+ }
+ }
+
sourceSets {
main {
res.srcDirs = ['res']
@@ -52,31 +65,34 @@
}
}
+ debug {
+ manifest.srcFile "AndroidManifest.xml"
+ }
+
androidTest {
res.srcDirs = ['tests/res']
java.srcDirs = ['tests/src']
manifest.srcFile "tests/AndroidManifest-common.xml"
}
- aosp {
- java.srcDirs = ['src_flags']
- manifest.srcFile "AndroidManifest.xml"
+ androidTestDebug {
+ manifest.srcFile "tests/AndroidManifest.xml"
}
- aospAndroidTest {
- manifest.srcFile "tests/AndroidManifest.xml"
+ aosp {
+ java.srcDirs = ['src_flags']
}
l3go {
res.srcDirs = ['go/res']
java.srcDirs = ['go/src_flags']
- // Note: we are using the Launcher3 manifest here because the gradle manifest-merger uses
- // different attributes than the build system.
- manifest.srcFile "AndroidManifest.xml"
+ manifest.srcFile "go/AndroidManifest.xml"
}
- l3goAndroidTest {
- manifest.srcFile "tests/AndroidManifest.xml"
+ quickstep {
+ res.srcDirs = ['quickstep/res']
+ java.srcDirs = ['quickstep/src_flags', 'quickstep/src']
+ manifest.srcFile "quickstep/AndroidManifest.xml"
}
}
}
@@ -93,6 +109,8 @@
compile "com.android.support:recyclerview-v7:${SUPPORT_LIBS_VERSION}"
compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7'
+ quickstepCompile fileTree(dir: "quickstep/libs", include: 'sysui_shared.jar')
+
testCompile 'junit:junit:4.12'
androidTestCompile "org.mockito:mockito-core:1.9.5"
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
new file mode 100644
index 0000000..08c740c4
--- /dev/null
+++ b/quickstep/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.launcher3" >
+
+ <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
+
+ <application
+ android:backupAgent="com.android.launcher3.LauncherBackupAgent"
+ android:fullBackupOnly="true"
+ android:fullBackupContent="@xml/backupscheme"
+ android:hardwareAccelerated="true"
+ android:icon="@drawable/ic_launcher_home"
+ android:label="@string/derived_app_name"
+ android:theme="@style/LauncherTheme"
+ android:largeHeap="@bool/config_largeHeap"
+ android:restoreAnyVersion="true"
+ android:supportsRtl="true" >
+
+ <service android:name="com.android.quickstep.TouchInteractionService"
+ android:exported="true" />
+
+ <!-- STOPSHIP: Change exported to false once all the integration is complete.
+ It is set to true so that the activity can be started from command line -->
+ <activity android:name="com.android.quickstep.RecentsActivity"
+ android:exported="true" />
+ </application>
+
+</manifest>
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
new file mode 100644
index 0000000..f9ce6e0
--- /dev/null
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
new file mode 100644
index 0000000..ef61226
--- /dev/null
+++ b/quickstep/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?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>
+
+ <!-- Application name -->
+ <string name="derived_app_name" translatable="false">Quickstep</string>
+</resources>
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
new file mode 100644
index 0000000..8f75980
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+package com.android.quickstep;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.support.annotation.Nullable;
+import android.widget.ArrayAdapter;
+
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.recents.model.Task;
+
+/**
+ * A simple activity to show the recently launched tasks
+ */
+public class RecentsActivity extends ListActivity {
+
+ private ArrayAdapter<Task> mAdapter;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(this);
+ plan.preloadPlan(new RecentsTaskLoader(this, 1, 1, 0), -1, UserHandle.myUserId());
+
+ mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
+ mAdapter.addAll(plan.getTaskStack().getStackTasks());
+ setListAdapter(mAdapter);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
new file mode 100644
index 0000000..091ab54
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+package com.android.quickstep;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Service connected by system-UI for handling touch interaction.
+ */
+public class TouchInteractionService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/quickstep/src_flags/com/android/launcher3/config/FeatureFlags.java b/quickstep/src_flags/com/android/launcher3/config/FeatureFlags.java
new file mode 100644
index 0000000..1edf592
--- /dev/null
+++ b/quickstep/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package com.android.launcher3.config;
+
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.states.OverviewState;
+
+/**
+ * Defines a set of flags used to control various launcher behaviors
+ */
+public final class FeatureFlags extends BaseFlags {
+
+ private FeatureFlags() {}
+
+ public static LauncherState createOverviewState(int id) {
+ return new OverviewState(id);
+ }
+}
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index 8ac8570..5eb6cc7 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -154,7 +154,7 @@
for (int i = data.size() - 1; i >= 0; i--) {
AppInfo info = data.get(i);
if (matcher.matches(info, info.componentName)) {
- info.isDisabled = op.apply(info.isDisabled);
+ info.runtimeStatusFlags = op.apply(info.runtimeStatusFlags);
modified.add(info);
}
}
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index 7d2f753..a5422aa 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -32,10 +32,6 @@
*/
public class AppInfo extends ItemInfoWithIcon {
- public static final int FLAG_SYSTEM_UNKNOWN = 0;
- public static final int FLAG_SYSTEM_YES = 1 << 0;
- public static final int FLAG_SYSTEM_NO = 1 << 1;
-
/**
* The intent used to start the application.
*/
@@ -43,16 +39,6 @@
public ComponentName componentName;
- /**
- * {@see ShortcutInfo#isDisabled}
- */
- public int isDisabled = ShortcutInfo.DEFAULT;
-
- /**
- * Stores if the app is a system app or not.
- */
- public int isSystemApp;
-
public AppInfo() {
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
}
@@ -74,15 +60,14 @@
this.container = ItemInfo.NO_ID;
this.user = user;
if (PackageManagerHelper.isAppSuspended(info.getApplicationInfo())) {
- isDisabled |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ runtimeStatusFlags |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
}
if (quietModeEnabled) {
- isDisabled |= ShortcutInfo.FLAG_DISABLED_QUIET_USER;
+ runtimeStatusFlags |= ShortcutInfo.FLAG_DISABLED_QUIET_USER;
}
intent = makeLaunchIntent(info);
-
- isSystemApp = (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0
+ runtimeStatusFlags |= (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0
? FLAG_SYSTEM_NO : FLAG_SYSTEM_YES;
}
@@ -92,8 +77,6 @@
componentName = info.componentName;
title = Utilities.trim(info.title);
intent = new Intent(info.intent);
- isDisabled = info.isDisabled;
- isSystemApp = info.isSystemApp;
}
@Override
@@ -119,9 +102,4 @@
.setComponent(cn)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
}
-
- @Override
- public boolean isDisabled() {
- return isDisabled != 0;
- }
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 364b204..a590504 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -184,6 +184,7 @@
public void reset() {
mBadgeInfo = null;
mBadgePalette = null;
+ mBadgeScale = 0f;
mForceHideBadge = false;
}
diff --git a/src/com/android/launcher3/ItemInfoWithIcon.java b/src/com/android/launcher3/ItemInfoWithIcon.java
index 1e020e2..1c4e88b 100644
--- a/src/com/android/launcher3/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/ItemInfoWithIcon.java
@@ -33,11 +33,70 @@
*/
public boolean usingLowResIcon;
+ /**
+ * Indicates that the icon is disabled due to safe mode restrictions.
+ */
+ public static final int FLAG_DISABLED_SAFEMODE = 1 << 0;
+
+ /**
+ * Indicates that the icon is disabled as the app is not available.
+ */
+ public static final int FLAG_DISABLED_NOT_AVAILABLE = 1 << 1;
+
+ /**
+ * Indicates that the icon is disabled as the app is suspended
+ */
+ public static final int FLAG_DISABLED_SUSPENDED = 1 << 2;
+
+ /**
+ * Indicates that the icon is disabled as the user is in quiet mode.
+ */
+ public static final int FLAG_DISABLED_QUIET_USER = 1 << 3;
+
+ /**
+ * Indicates that the icon is disabled as the publisher has disabled the actual shortcut.
+ */
+ public static final int FLAG_DISABLED_BY_PUBLISHER = 1 << 4;
+
+ /**
+ * Indicates that the icon is disabled as the user partition is currently locked.
+ */
+ public static final int FLAG_DISABLED_LOCKED_USER = 1 << 5;
+
+ public static final int FLAG_DISABLED_MASK = FLAG_DISABLED_SAFEMODE |
+ FLAG_DISABLED_NOT_AVAILABLE | FLAG_DISABLED_SUSPENDED |
+ FLAG_DISABLED_QUIET_USER | FLAG_DISABLED_BY_PUBLISHER | FLAG_DISABLED_LOCKED_USER;
+
+
+ /**
+ * The item points to a system app.
+ */
+ public static final int FLAG_SYSTEM_YES = 1 << 6;
+
+ /**
+ * The item points to a non system app.
+ */
+ public static final int FLAG_SYSTEM_NO = 1 << 7;
+
+ public static final int FLAG_SYSTEM_MASK = FLAG_SYSTEM_YES | FLAG_SYSTEM_NO;
+
+ /**
+ * Status associated with the system state of the underlying item. This is calculated every
+ * time a new info is created and not persisted on the disk.
+ */
+ public int runtimeStatusFlags = 0;
+
protected ItemInfoWithIcon() { }
protected ItemInfoWithIcon(ItemInfoWithIcon info) {
super(info);
iconBitmap = info.iconBitmap;
usingLowResIcon = info.usingLowResIcon;
+ runtimeStatusFlags = info.runtimeStatusFlags;
+ }
+
+ @Override
+ public boolean isDisabled() {
+ return (runtimeStatusFlags & FLAG_DISABLED_MASK) != 0;
}
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 6b5ee5e..94d9067 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -19,6 +19,11 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_QUIET_USER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -2048,10 +2053,10 @@
// Open shortcut
final ShortcutInfo shortcut = (ShortcutInfo) tag;
- if (shortcut.isDisabled != 0) {
- if ((shortcut.isDisabled &
- ~ShortcutInfo.FLAG_DISABLED_SUSPENDED &
- ~ShortcutInfo.FLAG_DISABLED_QUIET_USER) == 0) {
+ if (shortcut.isDisabled()) {
+ if ((shortcut.runtimeStatusFlags &
+ ~FLAG_DISABLED_SUSPENDED &
+ ~FLAG_DISABLED_QUIET_USER) == 0) {
// If the app is only disabled because of the above flags, launch activity anyway.
// Framework will tell the user why the app is suspended.
} else {
@@ -2062,10 +2067,10 @@
}
// Otherwise just use a generic error message.
int error = R.string.activity_not_available;
- if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_SAFEMODE) != 0) {
+ if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_SAFEMODE) != 0) {
error = R.string.safemode_shortcut_error;
- } else if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_BY_PUBLISHER) != 0 ||
- (shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_LOCKED_USER) != 0) {
+ } else if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_BY_PUBLISHER) != 0 ||
+ (shortcut.runtimeStatusFlags & FLAG_DISABLED_LOCKED_USER) != 0) {
error = R.string.shortcut_not_available;
}
Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index de3f441..63c232d 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -21,8 +21,8 @@
import android.view.View;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.states.AllAppsState;
-import com.android.launcher3.states.OverviewState;
import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -39,7 +39,6 @@
protected static final int FLAG_HIDE_HOTSEAT = 1 << 2;
protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 3;
protected static final int FLAG_DO_NOT_RESTORE = 1 << 4;
- protected static final int FLAG_HAS_SPRING = 1 << 5;
private static final LauncherState[] sAllStates = new LauncherState[4];
@@ -50,7 +49,7 @@
public static final LauncherState SPRING_LOADED = new SpringLoadedState(2);
- public static final LauncherState OVERVIEW = new OverviewState(3);
+ public static final LauncherState OVERVIEW = FeatureFlags.createOverviewState(3);
public final int ordinal;
@@ -90,7 +89,6 @@
* @see com.android.launcher3.allapps.AllAppsTransitionController
*/
public final float verticalProgress;
- public final boolean hasVerticalSpring;
public LauncherState(int id, int containerType, int transitionDuration, float verticalProgress,
int flags) {
@@ -106,7 +104,6 @@
this.doNotRestore = (flags & FLAG_DO_NOT_RESTORE) != 0;
this.verticalProgress = verticalProgress;
- this.hasVerticalSpring = (flags & FLAG_HAS_SPRING) != 0;
this.ordinal = id;
sAllStates[id] = this;
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 863cae7..fd94067 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -28,6 +28,7 @@
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimationLayerSet;
import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.AnimatorPlaybackController;
/**
* TODO: figure out what kind of tests we can write for this
@@ -133,8 +134,7 @@
private void goToState(LauncherState state, boolean animated, long delay,
Runnable onCompleteRunnable) {
- if (mLauncher.isInState(state) && mConfig.mCurrentAnimation == null
- && !mAllAppsController.isTransitioning()) {
+ if (mLauncher.isInState(state) && mConfig.mCurrentAnimation == null) {
// Run any queued runnable
if (onCompleteRunnable != null) {
@@ -159,27 +159,42 @@
return;
}
- AnimatorSet animation = createAnimationToNewWorkspace(state, onCompleteRunnable);
+ // Since state NORMAL can be reached from multiple states, just assume that the
+ // transition plays in reverse and use the same duration as previous state.
+ mConfig.duration = state == NORMAL ? mState.transitionDuration : state.transitionDuration;
+
+ AnimatorSet animation = createAnimationToNewWorkspaceInternal(state, onCompleteRunnable);
Runnable runnable = new StartAnimRunnable(animation, state.getFinalFocus(mLauncher));
if (delay > 0) {
mUiHandler.postDelayed(runnable, delay);
- } else if (mConfig.shouldPost) {
- mUiHandler.post(runnable);
} else {
- runnable.run();
+ mUiHandler.post(runnable);
}
}
- protected AnimatorSet createAnimationToNewWorkspace(final LauncherState state,
- final Runnable onCompleteRunnable) {
+ /**
+ * Creates a {@link AnimatorPlaybackController} that can be used for a controlled
+ * state transition.
+ * @param state the final state for the transition.
+ * @param duration intended duration for normal playback. Use higher duration for better
+ * accuracy.
+ */
+ protected AnimatorPlaybackController createAnimationToNewWorkspace(
+ LauncherState state, long duration) {
mConfig.reset();
- mConfig.duration = state == NORMAL ? mState.transitionDuration : state.transitionDuration;
+ mConfig.userControlled = true;
+ mConfig.duration = duration;
+ return AnimatorPlaybackController.wrap(
+ createAnimationToNewWorkspaceInternal(state, null), duration);
+ }
+
+ protected AnimatorSet createAnimationToNewWorkspaceInternal(final LauncherState state,
+ final Runnable onCompleteRunnable) {
final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
final AnimationLayerSet layerViews = new AnimationLayerSet();
- mAllAppsController.animateToFinalProgress(state.verticalProgress,
- state.hasVerticalSpring, animation, mConfig);
+ mAllAppsController.animateToFinalProgress(state.verticalProgress, animation, mConfig);
mLauncher.getWorkspace().setStateWithAnimation(state,
layerViews, animation, mConfig);
@@ -242,14 +257,14 @@
}
public static class AnimationConfig extends AnimatorListenerAdapter {
- public boolean shouldPost;
public long duration;
+ public boolean userControlled;
private AnimatorSet mCurrentAnimation;
public void reset() {
- shouldPost = true;
duration = 0;
+ userControlled = false;
if (mCurrentAnimation != null) {
mCurrentAnimation.setDuration(0);
diff --git a/src/com/android/launcher3/PinchToOverviewListener.java b/src/com/android/launcher3/PinchToOverviewListener.java
index d1a2538..27edaf6 100644
--- a/src/com/android/launcher3/PinchToOverviewListener.java
+++ b/src/com/android/launcher3/PinchToOverviewListener.java
@@ -22,18 +22,19 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
-import com.android.launcher3.compat.AnimatorSetCompat;
+import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.util.TouchController;
/**
* Detects pinches and animates the Workspace to/from overview mode.
*/
-public class PinchToOverviewListener
- implements TouchController, OnScaleGestureListener, Runnable {
+public class PinchToOverviewListener extends AnimatorListenerAdapter
+ implements TouchController, OnScaleGestureListener {
private static final float ACCEPT_THRESHOLD = 0.65f;
/**
@@ -47,7 +48,7 @@
private Workspace mWorkspace = null;
private boolean mPinchStarted = false;
- private AnimatorSetCompat mCurrentAnimation;
+ private AnimatorPlaybackController mCurrentAnimation;
private float mCurrentScale;
private boolean mShouldGoToFinalState;
@@ -100,8 +101,9 @@
}
mToState = mLauncher.isInState(OVERVIEW) ? NORMAL : OVERVIEW;
- mCurrentAnimation = AnimatorSetCompat.wrap(mLauncher.getStateManager()
- .createAnimationToNewWorkspace(mToState, this), OVERVIEW_TRANSITION_MS);
+ mCurrentAnimation = mLauncher.getStateManager()
+ .createAnimationToNewWorkspace(mToState, OVERVIEW_TRANSITION_MS);
+ mCurrentAnimation.getTarget().addListener(this);
mPinchStarted = true;
mCurrentScale = 1;
mShouldGoToFinalState = false;
@@ -111,7 +113,7 @@
}
@Override
- public void run() {
+ public void onAnimationEnd(Animator animation) {
mCurrentAnimation = null;
mPinchStarted = false;
}
@@ -121,9 +123,9 @@
if (mShouldGoToFinalState) {
mCurrentAnimation.start();
} else {
- mCurrentAnimation.addListener(new AnimatorListenerAdapter() {
+ mCurrentAnimation.setEndAction(new Runnable() {
@Override
- public void onAnimationEnd(Animator animation) {
+ public void run() {
mLauncher.getStateManager().goToState(
mToState == OVERVIEW ? NORMAL : OVERVIEW, false);
}
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index adf008b..ec608ca 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -65,13 +65,6 @@
public static final int FLAG_SUPPORTS_WEB_UI = 16; //0B10000;
/**
- * Indicates if it represents a common type mentioned in {@link CommonAppTypeParser}.
- * Upto 15 different types supported.
- */
- @Deprecated
- public static final int FLAG_RESTORED_APP_TYPE = 0B0011110000;
-
- /**
* The intent used to start the application.
*/
public Intent intent;
@@ -83,42 +76,6 @@
public Intent.ShortcutIconResource iconResource;
/**
- * Indicates that the icon is disabled due to safe mode restrictions.
- */
- public static final int FLAG_DISABLED_SAFEMODE = 1 << 0;
-
- /**
- * Indicates that the icon is disabled as the app is not available.
- */
- public static final int FLAG_DISABLED_NOT_AVAILABLE = 1 << 1;
-
- /**
- * Indicates that the icon is disabled as the app is suspended
- */
- public static final int FLAG_DISABLED_SUSPENDED = 1 << 2;
-
- /**
- * Indicates that the icon is disabled as the user is in quiet mode.
- */
- public static final int FLAG_DISABLED_QUIET_USER = 1 << 3;
-
- /**
- * Indicates that the icon is disabled as the publisher has disabled the actual shortcut.
- */
- public static final int FLAG_DISABLED_BY_PUBLISHER = 1 << 4;
-
- /**
- * Indicates that the icon is disabled as the user partition is currently locked.
- */
- public static final int FLAG_DISABLED_LOCKED_USER = 1 << 5;
-
- /**
- * Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
- * sd-card is not available).
- */
- public int isDisabled = DEFAULT;
-
- /**
* A message to display when the user tries to start a disabled shortcut.
* This is currently only used for deep shortcuts.
*/
@@ -142,7 +99,6 @@
iconResource = info.iconResource;
status = info.status;
mInstallProgress = info.mInstallProgress;
- isDisabled = info.isDisabled;
}
/** TODO: Remove this. It's only called by ApplicationInfo.makeShortcut. */
@@ -150,7 +106,6 @@
super(info);
title = Utilities.trim(info.title);
intent = new Intent(info.intent);
- isDisabled = info.isDisabled;
}
/**
@@ -219,9 +174,9 @@
contentDescription = UserManagerCompat.getInstance(context)
.getBadgedLabelForUser(label, user);
if (shortcutInfo.isEnabled()) {
- isDisabled &= ~FLAG_DISABLED_BY_PUBLISHER;
+ runtimeStatusFlags &= ~FLAG_DISABLED_BY_PUBLISHER;
} else {
- isDisabled |= FLAG_DISABLED_BY_PUBLISHER;
+ runtimeStatusFlags |= FLAG_DISABLED_BY_PUBLISHER;
}
disabledMessage = shortcutInfo.getDisabledMessage();
}
@@ -233,11 +188,6 @@
}
@Override
- public boolean isDisabled() {
- return isDisabled != 0;
- }
-
- @Override
public ComponentName getTargetComponent() {
ComponentName cn = super.getTargetComponent();
if (cn == null && (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 8e83a30..68a441a 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -1,5 +1,8 @@
package com.android.launcher3;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_SYSTEM_MASK;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_SYSTEM_NO;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -83,10 +86,10 @@
return false;
}
- if (info instanceof AppInfo) {
- AppInfo appInfo = (AppInfo) info;
- if (appInfo.isSystemApp != AppInfo.FLAG_SYSTEM_UNKNOWN) {
- return (appInfo.isSystemApp & AppInfo.FLAG_SYSTEM_NO) != 0;
+ if (info instanceof ItemInfoWithIcon) {
+ ItemInfoWithIcon iconInfo = (ItemInfoWithIcon) info;
+ if ((iconInfo.runtimeStatusFlags & FLAG_SYSTEM_MASK) != 0) {
+ return (iconInfo.runtimeStatusFlags & FLAG_SYSTEM_NO) != 0;
}
}
return getUninstallTarget(info) != null;
diff --git a/src/com/android/launcher3/VerticalSwipeController.java b/src/com/android/launcher3/VerticalSwipeController.java
new file mode 100644
index 0000000..12c6916
--- /dev/null
+++ b/src/com/android/launcher3/VerticalSwipeController.java
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+package com.android.launcher3;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+import static com.android.launcher3.anim.SpringAnimationHandler.Y_DIRECTION;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.support.animation.SpringAnimation;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.SpringAnimationHandler;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.util.TouchController;
+
+import java.util.ArrayList;
+
+/**
+ * Handles vertical touch gesture on the DragLayer
+ */
+public class VerticalSwipeController extends AnimatorListenerAdapter
+ implements TouchController, SwipeDetector.Listener {
+
+ private static final String TAG = "VerticalSwipeController";
+
+ private static final float RECATCH_REJECTION_FRACTION = .0875f;
+ private static final int SINGLE_FRAME_MS = 16;
+
+ // Progress after which the transition is assumed to be a success in case user does not fling
+ private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
+
+ private final Launcher mLauncher;
+ private final SwipeDetector mDetector;
+
+ private boolean mNoIntercept;
+ private int mStartContainerType;
+
+ private AnimatorPlaybackController mCurrentAnimation;
+ private LauncherState mToState;
+
+ private float mStartProgress;
+ // Ratio of transition process [0, 1] to drag displacement (px)
+ private float mProgressMultiplier;
+
+ private SpringAnimationHandler[] mSpringHandlers;
+
+ public VerticalSwipeController(Launcher l) {
+ mLauncher = l;
+ mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
+ }
+
+ private boolean canInterceptTouch(MotionEvent ev) {
+ if (!mLauncher.isInState(NORMAL) && !mLauncher.isInState(ALL_APPS)) {
+ // Don't listen for the pinch gesture if on all apps, widget picker, -1, etc.
+ return false;
+ }
+ if (mCurrentAnimation != null) {
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (mLauncher.isInState(ALL_APPS) && !mLauncher.getAppsView().shouldContainerScroll(ev)) {
+ return false;
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) {
+ Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception());
+ mDetector.finishedScrolling();
+ mCurrentAnimation = null;
+ }
+ }
+
+ private void initSprings() {
+ AllAppsContainerView appsView = mLauncher.getAppsView();
+
+ SpringAnimationHandler handler = appsView.getSpringAnimationHandler();
+ if (handler == null) {
+ mSpringHandlers = new SpringAnimationHandler[0];
+ return;
+ }
+
+ ArrayList<SpringAnimationHandler> handlers = new ArrayList<>();
+ handlers.add(handler);
+
+ SpringAnimation searchSpring = appsView.getSearchUiManager().getSpringForFling();
+ if (searchSpring != null) {
+ SpringAnimationHandler searchHandler =
+ new SpringAnimationHandler(Y_DIRECTION, handler.getFactory());
+ searchHandler.add(searchSpring, true /* setDefaultValues */);
+ handlers.add(searchHandler);
+ }
+
+ mSpringHandlers = handlers.toArray(new SpringAnimationHandler[handlers.size()]);
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mNoIntercept = !canInterceptTouch(ev);
+ if (mNoIntercept) {
+ return false;
+ }
+
+ // Now figure out which direction scroll events the controller will start
+ // calling the callbacks.
+ final int directionsToDetectScroll;
+ boolean ignoreSlopWhenSettling = false;
+
+ if (mCurrentAnimation != null) {
+ if (mCurrentAnimation.getProgressFraction() > 1 - RECATCH_REJECTION_FRACTION) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ } else if (mCurrentAnimation.getProgressFraction() < RECATCH_REJECTION_FRACTION ) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
+ } else {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
+ ignoreSlopWhenSettling = true;
+ }
+ } else {
+ if (mLauncher.isInState(ALL_APPS)) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
+ mStartContainerType = ContainerType.ALLAPPS;
+ } else {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ mStartContainerType = mLauncher.getDragLayer().isEventOverHotseat(ev) ?
+ ContainerType.HOTSEAT : ContainerType.WORKSPACE;
+ }
+ }
+
+ mDetector.setDetectableScrollConditions(
+ directionsToDetectScroll, ignoreSlopWhenSettling);
+
+ if (mSpringHandlers == null) {
+ initSprings();
+ }
+ }
+
+ if (mNoIntercept) {
+ return false;
+ }
+
+ onControllerTouchEvent(ev);
+ return mDetector.isDraggingOrSettling();
+ }
+
+ @Override
+ public boolean onControllerTouchEvent(MotionEvent ev) {
+ for (SpringAnimationHandler h : mSpringHandlers) {
+ h.addMovement(ev);
+ }
+ return mDetector.onTouchEvent(ev);
+ }
+
+ @Override
+ public void onDragStart(boolean start) {
+ if (mCurrentAnimation == null) {
+ float range = getShiftRange();
+ long maxAccuracy = (long) (2 * range);
+
+ // Build current animation
+ mToState = mLauncher.isInState(ALL_APPS) ? NORMAL : ALL_APPS;
+ mCurrentAnimation = mLauncher.getStateManager()
+ .createAnimationToNewWorkspace(mToState, maxAccuracy);
+ mCurrentAnimation.getTarget().addListener(this);
+ mStartProgress = 0;
+ mProgressMultiplier = (mLauncher.isInState(ALL_APPS) ? 1 : -1) / range;
+ mCurrentAnimation.dispatchOnStart();
+ } else {
+ mCurrentAnimation.pause();
+ mStartProgress = mCurrentAnimation.getProgressFraction();
+ }
+
+ for (SpringAnimationHandler h : mSpringHandlers) {
+ h.skipToEnd();
+ }
+ }
+
+ private float getShiftRange() {
+ return mLauncher.mAllAppsController.getShiftRange();
+ }
+
+ @Override
+ public boolean onDrag(float displacement, float velocity) {
+ float deltaProgress = mProgressMultiplier * displacement;
+ mCurrentAnimation.setPlayFraction(deltaProgress + mStartProgress);
+ return true;
+ }
+
+ @Override
+ public void onDragEnd(float velocity, boolean fling) {
+ final long animationDuration;
+ final int logAction;
+ final LauncherState targetState;
+ final float progress = mCurrentAnimation.getProgressFraction();
+
+ if (fling) {
+ logAction = Touch.FLING;
+ if (velocity < 0) {
+ targetState = ALL_APPS;
+ animationDuration = SwipeDetector.calculateDuration(velocity,
+ mToState == ALL_APPS ? (1 - progress) : progress);
+ } else {
+ targetState = NORMAL;
+ animationDuration = SwipeDetector.calculateDuration(velocity,
+ mToState == ALL_APPS ? progress : (1 - progress));
+ }
+ // snap to top or bottom using the release velocity
+ } else {
+ logAction = Touch.SWIPE;
+ if (progress > SUCCESS_TRANSITION_PROGRESS) {
+ targetState = mToState;
+ animationDuration = SwipeDetector.calculateDuration(velocity, 1 - progress);
+ } else {
+ targetState = mToState == ALL_APPS ? NORMAL : ALL_APPS;
+ animationDuration = SwipeDetector.calculateDuration(velocity, progress);
+ }
+ }
+
+ if (fling && targetState == ALL_APPS) {
+ for (SpringAnimationHandler h : mSpringHandlers) {
+ // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
+ h.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
+ }
+ }
+
+ mCurrentAnimation.setEndAction(new Runnable() {
+ @Override
+ public void run() {
+ if (targetState == mToState) {
+ // Transition complete. log the action
+ mLauncher.getUserEventDispatcher().logActionOnContainer(logAction,
+ mToState == ALL_APPS ? Direction.UP : Direction.DOWN,
+ mStartContainerType, mLauncher.getWorkspace().getCurrentPage());
+ } else {
+ mLauncher.getStateManager().goToState(
+ mToState == ALL_APPS ? NORMAL : ALL_APPS, false);
+ }
+ mDetector.finishedScrolling();
+ mCurrentAnimation = null;
+ }
+ });
+
+ float nextFrameProgress = Utilities.boundToRange(
+ progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
+
+ ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
+ anim.setFloatValues(nextFrameProgress, targetState == mToState ? 1f : 0f);
+ anim.setDuration(animationDuration);
+ anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
+ anim.start();
+ }
+}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index e72f54e..24c4704 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1582,6 +1582,7 @@
ValueAnimator stepAnimator = ValueAnimator.ofFloat(0, 1);
stepAnimator.addUpdateListener(listener);
+ stepAnimator.setDuration(config.duration);
anim.play(stepAnimator);
anim.addListener(listener);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index a84172d..9b64043 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -1,25 +1,19 @@
package com.android.launcher3.allapps;
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.support.animation.SpringAnimation;
import android.util.Property;
-import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.R;
@@ -27,16 +21,9 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.SpringAnimationHandler;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.GradientView;
-import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
-import com.android.launcher3.util.TouchController;
/**
* Handles AllApps view transition.
@@ -48,8 +35,7 @@
* If release velocity < THRES1, snap according to either top or bottom depending on whether it's
* closer to top or closer to the page indicator.
*/
-public class AllAppsTransitionController implements TouchController, SwipeDetector.Listener,
- SearchUiManager.OnScrollRangeChangeListener {
+public class AllAppsTransitionController implements SearchUiManager.OnScrollRangeChangeListener {
private static final Property<AllAppsTransitionController, Float> PROGRESS =
new Property<AllAppsTransitionController, Float>(Float.class, "progress") {
@@ -65,24 +51,16 @@
}
};
- // Spring values used when the user has not flung all apps.
- private static final float SPRING_MAX_RELEASE_VELOCITY = 10000;
- // The delay (as a % of the animation duration) to start the springs.
- private static final float SPRING_DELAY = 0.3f;
-
private final Interpolator mWorkspaceAccelnterpolator = Interpolators.ACCEL_2;
private final Interpolator mHotseatAccelInterpolator = Interpolators.ACCEL_1_5;
- private final Interpolator mFastOutSlowInInterpolator = Interpolators.FAST_OUT_SLOW_IN;
private static final float PARALLAX_COEFFICIENT = .125f;
- private static final int SINGLE_FRAME_MS = 16;
private AllAppsContainerView mAppsView;
private Workspace mWorkspace;
private Hotseat mHotseat;
private final Launcher mLauncher;
- private final SwipeDetector mDetector;
private final boolean mIsDarkTheme;
// Animation in this class is controlled by a single variable {@link mProgress}.
@@ -91,190 +69,25 @@
// When {@link mProgress} is 0, all apps container is pulled up.
// When {@link mProgress} is 1, all apps container is pulled down.
- private float mShiftStart; // [0, mShiftRange]
private float mShiftRange; // changes depending on the orientation
private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent
- // Velocity of the container. Unit is in px/ms.
- private float mContainerVelocity;
-
private static final float DEFAULT_SHIFT_RANGE = 10;
- private static final float RECATCH_REJECTION_FRACTION = .0875f;
-
- private long mAnimationDuration;
-
- private boolean mNoIntercept;
- private boolean mTouchEventStartedOnHotseat;
-
- // Used in discovery bounce animation to provide the transition without workspace changing.
private boolean mIsTranslateWithoutWorkspace = false;
private Animator mDiscoBounceAnimation;
private GradientView mGradientView;
- private SpringAnimation mSearchSpring;
- private SpringAnimationHandler mSpringAnimationHandler;
-
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
- mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
mShiftRange = DEFAULT_SHIFT_RANGE;
mProgress = 1f;
mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
}
- @Override
- public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mNoIntercept = false;
- mTouchEventStartedOnHotseat = mLauncher.getDragLayer().isEventOverHotseat(ev);
- if (!mLauncher.isInState(ALL_APPS) && !mLauncher.isInState(NORMAL)) {
- mNoIntercept = true;
- } else if (mLauncher.isInState(ALL_APPS) &&
- !mAppsView.shouldContainerScroll(ev)) {
- mNoIntercept = true;
- } else if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
- mNoIntercept = true;
- } else {
- // Now figure out which direction scroll events the controller will start
- // calling the callbacks.
- int directionsToDetectScroll = 0;
- boolean ignoreSlopWhenSettling = false;
-
- if (mDetector.isIdleState()) {
- if (mLauncher.isInState(ALL_APPS)) {
- directionsToDetectScroll |= SwipeDetector.DIRECTION_NEGATIVE;
- } else {
- directionsToDetectScroll |= SwipeDetector.DIRECTION_POSITIVE;
- }
- } else {
- if (isInDisallowRecatchBottomZone()) {
- directionsToDetectScroll |= SwipeDetector.DIRECTION_POSITIVE;
- } else if (isInDisallowRecatchTopZone()) {
- directionsToDetectScroll |= SwipeDetector.DIRECTION_NEGATIVE;
- } else {
- directionsToDetectScroll |= SwipeDetector.DIRECTION_BOTH;
- ignoreSlopWhenSettling = true;
- }
- }
- mDetector.setDetectableScrollConditions(directionsToDetectScroll,
- ignoreSlopWhenSettling);
- }
- }
-
- if (mNoIntercept) {
- return false;
- }
- mDetector.onTouchEvent(ev);
- if (mDetector.isSettlingState() && (isInDisallowRecatchBottomZone() || isInDisallowRecatchTopZone())) {
- return false;
- }
- return mDetector.isDraggingOrSettling();
- }
-
- @Override
- public boolean onControllerTouchEvent(MotionEvent ev) {
- if (hasSpringAnimationHandler()) {
- mSpringAnimationHandler.addMovement(ev);
- }
- return mDetector.onTouchEvent(ev);
- }
-
- private boolean isInDisallowRecatchTopZone() {
- return mProgress < RECATCH_REJECTION_FRACTION;
- }
-
- private boolean isInDisallowRecatchBottomZone() {
- return mProgress > 1 - RECATCH_REJECTION_FRACTION;
- }
-
- @Override
- public void onDragStart(boolean start) {
- mLauncher.getStateManager().cancelAnimation();
- cancelDiscoveryAnimation();
- mShiftStart = mAppsView.getTranslationY();
- onProgressAnimationStart();
- if (hasSpringAnimationHandler()) {
- mSpringAnimationHandler.skipToEnd();
- }
- }
-
- @Override
- public boolean onDrag(float displacement, float velocity) {
- if (mAppsView == null) {
- return false; // early termination.
- }
-
- mContainerVelocity = velocity;
-
- float shift = Math.min(Math.max(0, mShiftStart + displacement), mShiftRange);
- setProgress(shift / mShiftRange);
-
- return true;
- }
-
- @Override
- public void onDragEnd(float velocity, boolean fling) {
- if (mAppsView == null) {
- return; // early termination.
- }
-
- final int containerType = mTouchEventStartedOnHotseat
- ? ContainerType.HOTSEAT : ContainerType.WORKSPACE;
- if (fling) {
- if (velocity < 0) {
- calculateDuration(velocity, mAppsView.getTranslationY());
- if (!mLauncher.isInState(ALL_APPS)) {
- logSwipeOnContainer(Touch.FLING, Direction.UP, containerType);
- }
- mLauncher.getStateManager().goToState(ALL_APPS);
- if (hasSpringAnimationHandler()) {
- mSpringAnimationHandler.add(mSearchSpring, true /* setDefaultValues */);
- // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
- mSpringAnimationHandler.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
- }
- } else {
- calculateDuration(velocity, Math.abs(mShiftRange - mAppsView.getTranslationY()));
- if (mLauncher.isInState(ALL_APPS)) {
- logSwipeOnContainer(Touch.FLING, Direction.DOWN, ContainerType.ALLAPPS);
- }
- mLauncher.getStateManager().goToState(NORMAL);
- }
- // snap to top or bottom using the release velocity
- } else {
- if (mAppsView.getTranslationY() > mShiftRange / 2) {
- calculateDuration(velocity, Math.abs(mShiftRange - mAppsView.getTranslationY()));
- if (mLauncher.isInState(ALL_APPS)) {
- logSwipeOnContainer(Touch.SWIPE, Direction.DOWN, ContainerType.ALLAPPS);
- }
- mLauncher.getStateManager().goToState(NORMAL);
- } else {
- calculateDuration(velocity, Math.abs(mAppsView.getTranslationY()));
- if (!mLauncher.isInState(ALL_APPS)) {
- logSwipeOnContainer(Touch.SWIPE, Direction.UP, containerType);
- }
- mLauncher.getStateManager().goToState(ALL_APPS);
- }
- }
- }
-
- /**
- * Important, make sure that this method is called only when actual launcher state transition
- * happen and not when user swipes in one direction only to cancel that swipe seconds later.
- *
- * @param touchType Swipe or Fling
- * @param direction Up or Down
- * @param containerType Workspace or Allapps
- */
- private void logSwipeOnContainer(int touchType, int direction, int containerType) {
- mLauncher.getUserEventDispatcher().logActionOnContainer(
- touchType, direction, containerType,
- mLauncher.getWorkspace().getCurrentPage());
- }
-
- public boolean isTransitioning() {
- return mDetector.isDraggingOrSettling();
+ public float getShiftRange() {
+ return mShiftRange;
}
private void onProgressAnimationStart() {
@@ -310,10 +123,9 @@
* @param progress value between 0 and 1, 0 shows all apps and 1 shows workspace
*
* @see #setFinalProgress(float)
- * @see #animateToFinalProgress(float, boolean, AnimatorSet, AnimationConfig)
+ * @see #animateToFinalProgress(float, AnimatorSet, AnimationConfig)
*/
public void setProgress(float progress) {
- float shiftPrevious = mProgress * mShiftRange;
mProgress = progress;
float shiftCurrent = progress * mShiftRange;
@@ -341,11 +153,6 @@
mWorkspace.setWorkspaceYTranslationAndAlpha(
PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent), workspaceAlpha);
- if (!mDetector.isDraggingState()) {
- mContainerVelocity = mDetector.computeVelocity(shiftCurrent - shiftPrevious,
- System.currentTimeMillis());
- }
-
updateLightStatusBar(shiftCurrent);
}
@@ -353,10 +160,6 @@
return mProgress;
}
- private void calculateDuration(float velocity, float disp) {
- mAnimationDuration = SwipeDetector.calculateDuration(velocity, disp / mShiftRange);
- }
-
/**
* Sets the vertical transition progress to {@param progress} and updates all the dependent UI
* accordingly.
@@ -371,34 +174,20 @@
* dependent UI using various animation events
*
* @param progress the final vertical progress at the end of the animation
- * @param addSpring should there be an addition spring animation for the sub-views
* @param animationOut the target AnimatorSet where this animation should be added
* @param outConfig an in/out configuration which can be shared with other animations
*/
- public void animateToFinalProgress(float progress, boolean addSpring,
- AnimatorSet animationOut, AnimationConfig outConfig) {
+ public void animateToFinalProgress(
+ float progress, AnimatorSet animationOut, AnimationConfig outConfig) {
if (Float.compare(mProgress, progress) == 0) {
// Fail fast
onProgressAnimationEnd();
return;
}
- outConfig.shouldPost = true;
- Interpolator interpolator;
- if (mDetector.isIdleState()) {
- mAnimationDuration = LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
- mShiftStart = mAppsView.getTranslationY();
- interpolator = mFastOutSlowInInterpolator;
- } else {
- interpolator = scrollInterpolatorForVelocity(mContainerVelocity);
- mProgress = Utilities.boundToRange(
- mProgress + mContainerVelocity * SINGLE_FRAME_MS / mShiftRange, 0f, 1f);
- outConfig.shouldPost = false;
- }
-
- outConfig.duration = mAnimationDuration;
+ Interpolator interpolator = outConfig.userControlled ? LINEAR : FAST_OUT_SLOW_IN;
ObjectAnimator anim = ObjectAnimator.ofFloat(this, PROGRESS, mProgress, progress);
- anim.setDuration(mAnimationDuration);
+ anim.setDuration(outConfig.duration);
anim.setInterpolator(interpolator);
anim.addListener(new AnimationSuccessListener() {
@Override
@@ -413,20 +202,6 @@
});
animationOut.play(anim);
- if (addSpring) {
- ValueAnimator springAnim = ValueAnimator.ofFloat(0, 1);
- springAnim.setDuration((long) (mAnimationDuration * SPRING_DELAY));
- springAnim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- if (!mSpringAnimationHandler.isRunning()) {
- float velocity = mProgress * SPRING_MAX_RELEASE_VELOCITY;
- mSpringAnimationHandler.animateToPositionWithVelocity(0, 1, velocity);
- }
- }
- });
- animationOut.play(anim);
- }
}
public void showDiscoveryBounce() {
@@ -476,12 +251,6 @@
mWorkspace = workspace;
mHotseat.bringToFront();
mAppsView.getSearchUiManager().addOnScrollRangeChangeListener(this);
- mSpringAnimationHandler = mAppsView.getSpringAnimationHandler();
- mSearchSpring = mAppsView.getSearchUiManager().getSpringForFling();
- }
-
- private boolean hasSpringAnimationHandler() {
- return FeatureFlags.LAUNCHER3_PHYSICS && mSpringAnimationHandler != null;
}
@Override
@@ -503,13 +272,5 @@
mHotseat.setVisibility(View.INVISIBLE);
mAppsView.setVisibility(View.VISIBLE);
}
- if (hasSpringAnimationHandler()) {
- mSpringAnimationHandler.remove(mSearchSpring);
- mSpringAnimationHandler.reset();
- }
-
- // TODO: This call should no longer be needed once caret stops animating.
- setProgress(mProgress);
- mDetector.finishedScrolling();
}
}
diff --git a/src/com/android/launcher3/anim/AnimationSuccessListener.java b/src/com/android/launcher3/anim/AnimationSuccessListener.java
index feebc6c..9448632 100644
--- a/src/com/android/launcher3/anim/AnimationSuccessListener.java
+++ b/src/com/android/launcher3/anim/AnimationSuccessListener.java
@@ -24,7 +24,7 @@
*/
public abstract class AnimationSuccessListener extends AnimatorListenerAdapter {
- private boolean mCancelled = false;
+ protected boolean mCancelled = false;
@Override
public void onAnimationCancel(Animator animation) {
diff --git a/src/com/android/launcher3/compat/AnimatorSetCompat.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
similarity index 75%
rename from src/com/android/launcher3/compat/AnimatorSetCompat.java
rename to src/com/android/launcher3/anim/AnimatorPlaybackController.java
index 6676725..826a20e 100644
--- a/src/com/android/launcher3/compat/AnimatorSetCompat.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -13,37 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.compat;
+package com.android.launcher3.anim;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
-import android.os.Build;
-
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.Interpolators;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
- * Compat implementation for various new APIs in {@link AnimatorSet}
+ * Helper class to control the playback of an {@link AnimatorSet}, with custom interpolators
+ * and durations.
*
- * Note: The compat implementation does not support start delays on child animations or
+ * Note: The implementation does not support start delays on child animations or
* sequential playbacks.
*/
-public abstract class AnimatorSetCompat implements ValueAnimator.AnimatorUpdateListener {
+public abstract class AnimatorPlaybackController implements ValueAnimator.AnimatorUpdateListener {
- public static AnimatorSetCompat wrap(AnimatorSet anim, int duration) {
- if (Utilities.ATLEAST_OREO) {
- return new AnimatorSetCompatVO(anim, duration);
- } else {
- return new AnimatorSetCompatVL(anim, duration);
- }
+ public static AnimatorPlaybackController wrap(AnimatorSet anim, long duration) {
+
+ /**
+ * TODO: use {@link AnimatorSet#setCurrentPlayTime(long)} once b/68382377 is fixed.
+ */
+ return new AnimatorPlaybackControllerVL(anim, duration);
}
private final ValueAnimator mAnimationPlayer;
@@ -52,23 +47,28 @@
protected final AnimatorSet mAnim;
protected float mCurrentFraction;
+ private Runnable mEndAction;
- protected AnimatorSetCompat(AnimatorSet anim, int duration) {
+ protected AnimatorPlaybackController(AnimatorSet anim, long duration) {
mAnim = anim;
mDuration = duration;
mAnimationPlayer = ValueAnimator.ofFloat(0, 1);
mAnimationPlayer.setInterpolator(Interpolators.LINEAR);
+ mAnimationPlayer.addListener(new OnAnimationEndDispatcher());
mAnimationPlayer.addUpdateListener(this);
}
+ public AnimatorSet getTarget() {
+ return mAnim;
+ }
+
/**
* Starts playing the animation forward from current position.
*/
public void start() {
mAnimationPlayer.setFloatValues(mCurrentFraction, 1);
mAnimationPlayer.setDuration(clampDuration(1 - mCurrentFraction));
- mAnimationPlayer.addListener(new OnAnimationEndDispatcher());
mAnimationPlayer.start();
}
@@ -78,20 +78,38 @@
public void reverse() {
mAnimationPlayer.setFloatValues(mCurrentFraction, 0);
mAnimationPlayer.setDuration(clampDuration(mCurrentFraction));
- mAnimationPlayer.addListener(new OnAnimationEndDispatcher());
mAnimationPlayer.start();
}
/**
+ * Pauses the currently playing animation.
+ */
+ public void pause() {
+ mAnimationPlayer.cancel();
+ }
+
+ /**
+ * Returns the underlying animation used for controlling the set.
+ */
+ public ValueAnimator getAnimationPlayer() {
+ return mAnimationPlayer;
+ }
+
+ /**
* Sets the current animation position and updates all the child animators accordingly.
*/
public abstract void setPlayFraction(float fraction);
+ public float getProgressFraction() {
+ return mCurrentFraction;
+ }
+
/**
- * @see Animator#addListener(AnimatorListener)
+ * Sets the action to be called when the animation is completed. Also clears any
+ * previously set action.
*/
- public void addListener(Animator.AnimatorListener listener) {
- mAnimationPlayer.addListener(listener);
+ public void setEndAction(Runnable runnable) {
+ mEndAction = runnable;
}
@Override
@@ -124,11 +142,11 @@
}
}
- public static class AnimatorSetCompatVL extends AnimatorSetCompat {
+ public static class AnimatorPlaybackControllerVL extends AnimatorPlaybackController {
private final ValueAnimator[] mChildAnimations;
- private AnimatorSetCompatVL(AnimatorSet anim, int duration) {
+ private AnimatorPlaybackControllerVL(AnimatorSet anim, long duration) {
super(anim, duration);
// Build animation list
@@ -164,25 +182,19 @@
}
- @TargetApi(Build.VERSION_CODES.O)
- private static class AnimatorSetCompatVO extends AnimatorSetCompat {
-
- private AnimatorSetCompatVO(AnimatorSet anim, int duration) {
- super(anim, duration);
- }
+ private class OnAnimationEndDispatcher extends AnimationSuccessListener {
@Override
- public void setPlayFraction(float fraction) {
- mCurrentFraction = fraction;
- mAnim.setCurrentPlayTime(clampDuration(fraction));
+ public void onAnimationStart(Animator animation) {
+ mCancelled = false;
}
- }
-
- private class OnAnimationEndDispatcher extends AnimationSuccessListener {
@Override
public void onAnimationSuccess(Animator animator) {
dispatchOnEndRecursively(mAnim);
+ if (mEndAction != null) {
+ mEndAction.run();
+ }
}
private void dispatchOnEndRecursively(Animator animator) {
diff --git a/src/com/android/launcher3/anim/SpringAnimationHandler.java b/src/com/android/launcher3/anim/SpringAnimationHandler.java
index eec3a48..29a2430 100644
--- a/src/com/android/launcher3/anim/SpringAnimationHandler.java
+++ b/src/com/android/launcher3/anim/SpringAnimationHandler.java
@@ -83,6 +83,10 @@
mAnimations.add(spring);
}
+ public AnimationFactory<T> getFactory() {
+ return mAnimationFactory;
+ }
+
/**
* Adds a new or recycled animation to the list of springs handled by this class.
*
diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java
index c2cc215..6ce334e 100644
--- a/src/com/android/launcher3/badge/BadgeRenderer.java
+++ b/src/com/android/launcher3/badge/BadgeRenderer.java
@@ -26,6 +26,7 @@
import android.graphics.Rect;
import android.graphics.Shader;
import android.support.annotation.Nullable;
+import android.util.Log;
import android.util.SparseArray;
import com.android.launcher3.R;
@@ -38,6 +39,8 @@
*/
public class BadgeRenderer {
+ private static final String TAG = "BadgeRenderer";
+
private static final boolean DOTS_ONLY = true;
// The badge sizes are defined as percentages of the app icon size.
@@ -95,6 +98,10 @@
*/
public void draw(Canvas canvas, IconPalette palette, @Nullable BadgeInfo badgeInfo,
Rect iconBounds, float badgeScale, Point spaceForOffset) {
+ if (palette == null || iconBounds == null || spaceForOffset == null) {
+ Log.e(TAG, "Invalid null argument(s) passed in call to draw.");
+ return;
+ }
mTextPaint.setColor(palette.textColor);
IconDrawer iconDrawer = badgeInfo != null && badgeInfo.isIconLarge()
? mLargeIconDrawer : mSmallIconDrawer;
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index f01923f..4fbab39 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -16,6 +16,9 @@
package com.android.launcher3.config;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.states.OverviewState;
+
/**
* Defines a set of flags used to control various launcher behaviors.
*
@@ -58,4 +61,8 @@
// Features to control Launcher3Go behavior
public static final boolean GO_DISABLE_WIDGETS = false;
+
+ public static LauncherState createOverviewState(int id) {
+ return new OverviewState(id);
+ }
}
diff --git a/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java b/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java
index 06493b2..ed5cfeb 100644
--- a/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java
+++ b/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java
@@ -41,7 +41,6 @@
this.intent = item.isInstantApp ? item.launchIntent : item.installIntent;
this.title = item.title;
this.iconBitmap = item.bitmap;
- this.isDisabled = ShortcutInfo.DEFAULT;
this.usingLowResIcon = false;
this.isInstantApp = item.isInstantApp;
this.isRecent = item.isRecent;
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 5b1a4dc..0f0b20d 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -46,6 +46,7 @@
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
+import com.android.launcher3.VerticalSwipeController;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags;
@@ -96,6 +97,7 @@
// Handles all apps pull up interaction
private AllAppsTransitionController mAllAppsController;
+ private VerticalSwipeController mVerticalSwipeController;
private TouchController mActiveController;
/**
@@ -121,6 +123,7 @@
mLauncher = launcher;
mDragController = dragController;
mAllAppsController = allAppsTransitionController;
+ mVerticalSwipeController = new VerticalSwipeController(mLauncher);
boolean isAccessibilityEnabled = ((AccessibilityManager) mLauncher.getSystemService(
Context.ACCESSIBILITY_SERVICE)).isEnabled();
@@ -191,8 +194,8 @@
return true;
}
- if (mAllAppsController.onControllerInterceptTouchEvent(ev)) {
- mActiveController = mAllAppsController;
+ if (mVerticalSwipeController.onControllerInterceptTouchEvent(ev)) {
+ mActiveController = mVerticalSwipeController;
return true;
}
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index d471af6..1eddb2c 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -72,7 +72,7 @@
PackageManager packageManager = context.getPackageManager();
// the resource
try {
- Resources resources = packageManager.getResourcesForApplication(iconRes.resourceName);
+ Resources resources = packageManager.getResourcesForApplication(iconRes.packageName);
if (resources != null) {
final int id = resources.getIdentifier(iconRes.resourceName, null, null);
// do not stamp old legacy shortcuts as the app may have already forgotten about it
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index bc7da9b..47f370a 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -16,11 +16,15 @@
package com.android.launcher3.model;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_SYSTEM_NO;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_SYSTEM_YES;
+
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
+import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.database.Cursor;
import android.database.CursorWrapper;
@@ -274,8 +278,13 @@
info.iconBitmap = icon != null ? icon : info.iconBitmap;
}
- if (lai != null && PackageManagerHelper.isAppSuspended(lai.getApplicationInfo())) {
- info.isDisabled = ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ if (lai != null) {
+ ApplicationInfo appInfo = lai.getApplicationInfo();
+ if (PackageManagerHelper.isAppSuspended(appInfo)) {
+ info.runtimeStatusFlags |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ }
+ info.runtimeStatusFlags |= (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
+ ? FLAG_SYSTEM_NO : FLAG_SYSTEM_YES;
}
// from the db
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 5386fb4..c2cfebb 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -27,8 +27,6 @@
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Process;
-import android.os.SystemClock;
-import android.os.Trace;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -76,6 +74,9 @@
import java.util.Map;
import java.util.concurrent.CancellationException;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
/**
@@ -466,13 +467,13 @@
true /* badged */, fallbackIconProvider);
if (pmHelper.isAppSuspended(
pinnedShortcut.getPackage(), info.user)) {
- info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
}
intent = info.intent;
} else {
// Create a shortcut info in disabled mode for now.
info = c.loadSimpleShortcut();
- info.isDisabled |= ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
+ info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
}
} else { // item type == ITEM_TYPE_SHORTCUT
info = c.loadSimpleShortcut();
@@ -480,7 +481,7 @@
// Shortcuts are only available on the primary profile
if (!TextUtils.isEmpty(targetPkg)
&& pmHelper.isAppSuspended(targetPkg, c.user)) {
- disabledState |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ disabledState |= FLAG_DISABLED_SUSPENDED;
}
// App shortcuts that used to be automatically added to Launcher
@@ -503,9 +504,9 @@
info.rank = c.getInt(rankIndex);
info.spanX = 1;
info.spanY = 1;
- info.isDisabled |= disabledState;
+ info.runtimeStatusFlags |= disabledState;
if (isSafeMode && !Utilities.isSystemApp(context, intent)) {
- info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;
+ info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
}
if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 53a9862..470dadf 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -244,9 +244,9 @@
infoUpdated = true;
}
- int oldDisabledFlags = si.isDisabled;
- si.isDisabled = flagOp.apply(si.isDisabled);
- if (si.isDisabled != oldDisabledFlags) {
+ int oldRuntimeFlags = si.runtimeStatusFlags;
+ si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
+ if (si.runtimeStatusFlags != oldRuntimeFlags) {
shortcutUpdated = true;
}
}
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 8170f9a..2e9ac72 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.model;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
+
import android.content.Context;
import android.os.UserHandle;
@@ -87,12 +89,12 @@
removedKeys.add(key);
continue;
}
- si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
+ si.runtimeStatusFlags &= ~FLAG_DISABLED_LOCKED_USER;
si.updateFromDeepShortcutInfo(shortcut, context);
si.iconBitmap = LauncherIcons.createShortcutIcon(shortcut, context,
si.iconBitmap);
} else {
- si.isDisabled |= ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
+ si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
}
updatedShortcutInfos.add(si);
}
diff --git a/src/com/android/launcher3/states/AllAppsState.java b/src/com/android/launcher3/states/AllAppsState.java
index ee35b4d..ed3023a 100644
--- a/src/com/android/launcher3/states/AllAppsState.java
+++ b/src/com/android/launcher3/states/AllAppsState.java
@@ -32,7 +32,7 @@
public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
- private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY | FLAG_HAS_SPRING;
+ private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
public AllAppsState(int id) {
super(id, ContainerType.ALLAPPS, ALL_APPS_TRANSITION_MS, 0f, STATE_FLAGS);