Merge "Using new APIs for disabling metaData table" into ub-launcher3-master
diff --git a/proguard.flags b/proguard.flags
index b8cade5..086337d 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -39,7 +39,7 @@
public int getY();
}
--keep class com.android.launcher3.dragndrop.DragLayer$LayoutParams {
+-keep class com.android.launcher3.views.BaseDragLayer$LayoutParams {
public void setWidth(int);
public int getWidth();
public void setHeight(int);
@@ -102,6 +102,11 @@
public <init>(...);
}
+# InstantAppResolver
+-keep class com.android.quickstep.InstantAppResolverImpl {
+ public <init>(...);
+}
+
-keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** {
*;
}
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index d531a46..8b28597 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -47,7 +47,21 @@
<!-- 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" />
+ android:exported="true"
+ android:excludeFromRecents="true" />
+
+ <!-- Content provider to settings search -->
+ <provider
+ android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
+ android:authorities="com.android.launcher3"
+ android:grantUriPermissions="true"
+ android:multiprocess="true"
+ android:permission="android.permission.READ_SEARCH_INDEXABLES"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
+ </intent-filter>
+ </provider>
</application>
</manifest>
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 6e62add..6e56055 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/layout/fallback_recents_activity.xml b/quickstep/res/layout/fallback_recents_activity.xml
new file mode 100644
index 0000000..b3fc4ed
--- /dev/null
+++ b/quickstep/res/layout/fallback_recents_activity.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<com.android.quickstep.RecentsRootView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drag_layer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.android.quickstep.FallbackRecentsView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/overview_panel"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:theme="@style/HomeScreenElementTheme" />
+
+</com.android.quickstep.RecentsRootView>
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index 9f4f8a1..54a90cf 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.quickstep.RecentsView
+<com.android.quickstep.views.LauncherRecentsView
xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@style/HomeScreenElementTheme"
android:layout_width="match_parent"
@@ -24,8 +24,4 @@
android:alpha="0.0"
android:visibility="invisible" >
- <com.android.launcher3.uioverrides.WorkspaceCard
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</com.android.quickstep.RecentsView>
\ No newline at end of file
+</com.android.quickstep.views.LauncherRecentsView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 91b6aa3..0ac2b11 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -13,12 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.quickstep.TaskView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.quickstep.views.TaskView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="4dp">
- <com.android.quickstep.TaskThumbnailView
+ <com.android.quickstep.views.TaskThumbnailView
android:id="@+id/snapshot"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -29,4 +29,4 @@
android:layout_width="@dimen/task_thumbnail_icon_size"
android:layout_height="@dimen/task_thumbnail_icon_size"
android:layout_gravity="top|center_horizontal" />
-</com.android.quickstep.TaskView>
\ No newline at end of file
+</com.android.quickstep.views.TaskView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_menu.xml b/quickstep/res/layout/task_menu.xml
index 6e3fb4f..b846665 100644
--- a/quickstep/res/layout/task_menu.xml
+++ b/quickstep/res/layout/task_menu.xml
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.quickstep.TaskMenuView
+<com.android.quickstep.views.TaskMenuView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/bg_popup_item_width"
android:layout_height="wrap_content"
@@ -33,4 +33,4 @@
android:paddingTop="18dp"
android:drawablePadding="8dp"
android:gravity="center_horizontal"/>
-</com.android.quickstep.TaskMenuView>
\ No newline at end of file
+</com.android.quickstep.views.TaskMenuView>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index cf86176..e61e359 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -16,8 +16,6 @@
<resources>
- <dimen name="options_menu_icon_size">24dp</dimen>
-
<dimen name="task_thumbnail_top_margin">24dp</dimen>
<dimen name="task_thumbnail_icon_size">48dp</dimen>
<dimen name="task_menu_background_radius">12dp</dimen>
@@ -33,12 +31,10 @@
<dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
<dimen name="quickstep_fling_min_velocity">250dp</dimen>
- <dimen name="workspace_overview_offset_x">-24dp</dimen>
-
<!-- Launcher app transition -->
<dimen name="content_trans_y">25dp</dimen>
<dimen name="workspace_trans_y">80dp</dimen>
- <dimen name="recents_adjacent_trans_x">120dp</dimen>
+ <dimen name="recents_adjacent_trans_x">140dp</dimen>
<dimen name="recents_adjacent_trans_y">80dp</dimen>
<fraction name="recents_adjacent_scale">150%</fraction>
</resources>
diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml
index ba99d81..2bd9f8f 100644
--- a/quickstep/res/values/override.xml
+++ b/quickstep/res/values/override.xml
@@ -16,5 +16,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_transition_manager_class" translatable="false">com.android.launcher3.LauncherAppTransitionManagerImpl</string>
+
+ <string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
</resources>
diff --git a/quickstep/res/xml/indexable_launcher_prefs.xml b/quickstep/res/xml/indexable_launcher_prefs.xml
new file mode 100644
index 0000000..2655402
--- /dev/null
+++ b/quickstep/res/xml/indexable_launcher_prefs.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 Google Inc.
+
+ 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <SwitchPreference
+ android:key="pref_add_icon_to_home"
+ android:title="@string/auto_add_shortcuts_label"
+ android:summary="@string/auto_add_shortcuts_description"
+ android:defaultValue="true"
+ />
+
+ <ListPreference
+ android:key="pref_override_icon_shape"
+ android:title="@string/icon_shape_override_label"
+ android:summary="@string/icon_shape_override_label_location"
+ android:entries="@array/icon_shape_override_paths_names"
+ android:entryValues="@array/icon_shape_override_paths_values"
+ android:defaultValue=""
+ android:persistent="false" />
+
+</PreferenceScreen>
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 872e6ca..f919339 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -15,27 +15,92 @@
*/
package com.android.launcher3;
+import static com.android.systemui.shared.recents.utilities.Utilities
+ .postAtFrontOfQueueAsynchronously;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.Handler;
+import android.support.annotation.BinderThread;
+import android.support.annotation.UiThread;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
+@TargetApi(Build.VERSION_CODES.P)
+public abstract class LauncherAnimationRunner extends AnimatorListenerAdapter
+ implements RemoteAnimationRunnerCompat {
-public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
+ private static final int REFRESH_RATE_MS = 16;
- AnimatorSet mAnimator;
- private Launcher mLauncher;
+ private final Handler mHandler;
- LauncherAnimationRunner(Launcher launcher) {
- mLauncher = launcher;
+ private Runnable mSysFinishRunnable;
+
+ private AnimatorSet mAnimator;
+
+ public LauncherAnimationRunner(Handler handler) {
+ mHandler = handler;
}
+ @BinderThread
+ @Override
+ public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, Runnable runnable) {
+ postAtFrontOfQueueAsynchronously(mHandler, () -> {
+ // Finish any previous animation
+ finishSystemAnimation();
+
+ mSysFinishRunnable = runnable;
+ mAnimator = getAnimator(targetCompats);
+ if (mAnimator == null) {
+ finishSystemAnimation();
+ return;
+ }
+ mAnimator.addListener(this);
+ mAnimator.start();
+ // Because t=0 has the app icon in its original spot, we can skip the
+ // first frame and have the same movement one frame earlier.
+ mAnimator.setCurrentPlayTime(REFRESH_RATE_MS);
+
+ });
+ }
+
+
+ @UiThread
+ public abstract AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats);
+
+ @UiThread
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (animation == mAnimator) {
+ mAnimator = null;
+ finishSystemAnimation();
+ }
+ }
+
+ /**
+ * Called by the system
+ */
+ @BinderThread
@Override
public void onAnimationCancelled() {
- postAtFrontOfQueueAsynchronously(mLauncher.getWindow().getDecorView().getHandler(), () -> {
+ postAtFrontOfQueueAsynchronously(mHandler, () -> {
if (mAnimator != null) {
- mAnimator.cancel();
+ mAnimator.removeListener(this);
+ mAnimator.end();
+ mAnimator = null;
}
});
}
+
+ @UiThread
+ private void finishSystemAnimation() {
+ if (mSysFinishRunnable != null) {
+ mSysFinishRunnable.run();
+ mSysFinishRunnable = null;
+ }
+ }
}
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index b97669b..0dbf404 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber;
import static com.android.systemui.shared.recents.utilities.Utilities.getSurface;
-import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
@@ -32,6 +31,7 @@
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityOptions;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -40,6 +40,7 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.Surface;
import android.view.View;
@@ -58,8 +59,9 @@
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.quickstep.RecentsAnimationInterpolator;
import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds;
-import com.android.quickstep.RecentsView;
-import com.android.quickstep.TaskView;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@@ -78,11 +80,14 @@
implements OnDeviceProfileChangeListener {
private static final String TAG = "LauncherTransition";
- private static final int REFRESH_RATE_MS = 16;
+ private static final int STATUS_BAR_TRANSITION_DURATION = 120;
private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
"android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
+ private static final int APP_LAUNCH_DURATION = 500;
+ // Use a shorter duration for x or y translation to create a curve effect
+ private static final int APP_LAUNCH_CURVED_DURATION = 233;
private static final int RECENTS_LAUNCH_DURATION = 336;
private static final int LAUNCHER_RESUME_START_DELAY = 100;
private static final int CLOSING_TRANSITION_DURATION_MS = 350;
@@ -93,7 +98,9 @@
private final DragLayer mDragLayer;
private final Launcher mLauncher;
- private DeviceProfile mDeviceProfile;
+
+ private final Handler mHandler;
+ private final boolean mIsRtl;
private final float mContentTransY;
private final float mWorkspaceTransY;
@@ -101,17 +108,35 @@
private final float mRecentsTransY;
private final float mRecentsScale;
+ private DeviceProfile mDeviceProfile;
private View mFloatingView;
- private boolean mIsRtl;
- private LauncherTransitionAnimator mCurrentAnimator;
+ private final AnimatorListenerAdapter mUiResetListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDragLayer.setAlpha(1f);
+ mDragLayer.setTranslationY(0f);
+
+ View appsView = mLauncher.getAppsView();
+ appsView.setAlpha(1f);
+ appsView.setTranslationY(0f);
+ }
+ };
+
+ private final AnimatorListenerAdapter mReapplyStateListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mLauncher.getStateManager().reapplyState();
+ }
+ };
public LauncherAppTransitionManagerImpl(Context context) {
mLauncher = Launcher.getLauncher(context);
mDragLayer = mLauncher.getDragLayer();
+ mHandler = new Handler(Looper.getMainLooper());
+ mIsRtl = Utilities.isRtl(mLauncher.getResources());
mDeviceProfile = mLauncher.getDeviceProfile();
- mIsRtl = Utilities.isRtl(mLauncher.getResources());
Resources res = mLauncher.getResources();
mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
@@ -129,26 +154,6 @@
mDeviceProfile = dp;
}
- private void setCurrentAnimator(LauncherTransitionAnimator animator) {
- if (isAnimating()) {
- mCurrentAnimator.cancel();
- }
- mCurrentAnimator = animator;
- }
-
- @Override
- public void finishLauncherAnimation() {
- if (isAnimating()) {
- mCurrentAnimator.finishLauncherAnimation();
- }
- mCurrentAnimator = null;
- }
-
- @Override
- public boolean isAnimating() {
- return mCurrentAnimator != null && mCurrentAnimator.isRunning();
- }
-
/**
* @return ActivityOptions with remote animations that controls how the window of the opening
* targets are displayed.
@@ -157,57 +162,37 @@
public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
if (hasControlRemoteAppTransitionPermission()) {
try {
- RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) {
- @Override
- public void onAnimationStart(RemoteAnimationTargetCompat[] targets,
- Runnable finishedCallback) {
- // Post at front of queue ignoring sync barriers to make sure it gets
- // processed before the next frame.
- postAtFrontOfQueueAsynchronously(v.getHandler(), () -> {
- final boolean removeTrackingView;
- LauncherTransitionAnimator animator =
- composeRecentsLaunchAnimator(v, targets);
- if (animator != null) {
- // We are animating the task view directly, do not remove it after
- removeTrackingView = false;
- } else {
- animator = composeAppLaunchAnimator(v, targets);
- // A new floating view is created for the animation, remove it after
- removeTrackingView = true;
- }
+ RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler) {
- setCurrentAnimator(animator);
- mAnimator = animator.getAnimatorSet();
- mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
+ Animator[] anims = composeRecentsLaunchAnimator(v, targetCompats);
+ AnimatorSet anim = new AnimatorSet();
+ if (anims != null) {
+ anim.playTogether(anims);
+ } else {
+ anim.play(getLauncherAnimators(v, targetCompats));
+ anim.play(getWindowAnimators(v, targetCompats));
+ anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// Reset launcher to normal state
v.setVisibility(View.VISIBLE);
- if (removeTrackingView) {
- ((ViewGroup) mDragLayer.getParent()).removeView(
- mFloatingView);
- }
-
- mDragLayer.setAlpha(1f);
- mDragLayer.setTranslationY(0f);
-
- View appsView = mLauncher.getAppsView();
- appsView.setAlpha(1f);
- appsView.setTranslationY(0f);
-
- finishedCallback.run();
+ ((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView);
}
});
- mAnimator.start();
- // Because t=0 has the app icon in its original spot, we can skip the
- // first frame and have the same movement one frame earlier.
- mAnimator.setCurrentPlayTime(REFRESH_RATE_MS);
- });
+ anim.addListener(mUiResetListener);
+ }
+ mLauncher.getStateManager().setCurrentAnimation(anim);
+ return anim;
}
};
- return ActivityOptionsCompat.makeRemoteAnimation(
- new RemoteAnimationAdapterCompat(runner, 500, 380));
+ int duration = findTaskViewToLaunch(launcher, v, null) != null
+ ? RECENTS_LAUNCH_DURATION : APP_LAUNCH_DURATION;
+ int statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION;
+ return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
+ runner, duration, statusBarTransitionDelay));
} catch (NoClassDefFoundError e) {
// Gracefully fall back to default launch options if the user's platform doesn't
// have the latest changes.
@@ -217,15 +202,40 @@
}
/**
- * Composes the animations for a launch from the recents list if possible.
+ * Try to find a TaskView that corresponds with the component of the launched view.
+ *
+ * If this method returns a non-null TaskView, it will be used in composeRecentsLaunchAnimation.
+ * Otherwise, we will assume we are using a normal app transition, but it's possible that the
+ * opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView.
*/
- private LauncherTransitionAnimator composeRecentsLaunchAnimator(View v,
- RemoteAnimationTargetCompat[] targets) {
- // Ensure recents is actually visible
- if (!mLauncher.getStateManager().getState().overviewUi) {
- return null;
+ private TaskView findTaskViewToLaunch(
+ BaseDraggingActivity activity, View v, RemoteAnimationTargetCompat[] targets) {
+ if (v instanceof TaskView) {
+ return (TaskView) v;
+ }
+ RecentsView recentsView = activity.getOverviewPanel();
+
+ // It's possible that the launched view can still be resolved to a visible task view, check
+ // the task id of the opening task and see if we can find a match.
+ if (v.getTag() instanceof ItemInfo) {
+ ItemInfo itemInfo = (ItemInfo) v.getTag();
+ ComponentName componentName = itemInfo.getTargetComponent();
+ if (componentName != null) {
+ for (int i = 0; i < recentsView.getChildCount(); i++) {
+ TaskView taskView = (TaskView) recentsView.getPageAt(i);
+ if (recentsView.isTaskViewVisible(taskView)) {
+ Task task = taskView.getTask();
+ if (componentName.equals(task.key.getComponent())) {
+ return taskView;
+ }
+ }
+ }
+ }
}
+ if (targets == null) {
+ return null;
+ }
// Resolve the opening task id
int openingTaskId = -1;
for (RemoteAnimationTargetCompat target : targets) {
@@ -242,25 +252,39 @@
// If the opening task id is not currently visible in overview, then fall back to normal app
// icon launch animation
- RecentsView recentsView = mLauncher.getOverviewPanel();
TaskView taskView = recentsView.getTaskView(openingTaskId);
if (taskView == null || !recentsView.isTaskViewVisible(taskView)) {
return null;
}
+ return taskView;
+ }
+
+ /**
+ * Composes the animations for a launch from the recents list if possible.
+ */
+ private Animator[] composeRecentsLaunchAnimator(View v,
+ RemoteAnimationTargetCompat[] targets) {
+ // Ensure recents is actually visible
+ if (!mLauncher.getStateManager().getState().overviewUi) {
+ return null;
+ }
+
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING);
+ boolean skipLauncherChanges = !launcherClosing;
+
+ TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets);
+ if (taskView == null) {
+ return null;
+ }
// Found a visible recents task that matches the opening app, lets launch the app from there
Animator launcherAnim;
- AnimatorListenerAdapter windowAnimEndListener;
- boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING);
+ final AnimatorListenerAdapter windowAnimEndListener;
if (launcherClosing) {
launcherAnim = getRecentsLauncherAnimator(recentsView, taskView);
- windowAnimEndListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Make sure recents gets fixed up by resetting task alphas and scales, etc.
- mLauncher.getStateManager().reapplyState();
- }
- };
+ // Make sure recents gets fixed up by resetting task alphas and scales, etc.
+ windowAnimEndListener = mReapplyStateListener;
} else {
AnimatorPlaybackController controller =
mLauncher.getStateManager()
@@ -275,10 +299,9 @@
};
}
- MutableBoolean skipLauncherChanges = new MutableBoolean(!launcherClosing);
Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, targets);
windowAnim.addListener(windowAnimEndListener);
- return new LauncherTransitionAnimator(launcherAnim, windowAnim, skipLauncherChanges);
+ return new Animator[] {launcherAnim, windowAnim};
}
/**
@@ -295,7 +318,7 @@
boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex;
boolean isRtl = recentsView.isRtl();
if (launchingCenterTask) {
- if (launchedTaskIndex - 1 >= recentsView.getFirstTaskIndex()) {
+ if (launchedTaskIndex - 1 >= 0) {
TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1);
ObjectAnimator adjacentTask1ScaleAndTranslate =
LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1,
@@ -317,29 +340,27 @@
.build());
launcherAnimator.play(adjacentTask2ScaleAndTranslate);
}
- } else if (centerTaskIndex >= recentsView.getFirstTaskIndex()) {
+ } else {
// We are launching an adjacent task, so parallax the center and other adjacent task.
TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex);
- float translationX = Math.abs(v.getTranslationX());
- ObjectAnimator centerTaskParallaxToRight =
+ float translationX = mRecentsTransX / 2;
+ ObjectAnimator centerTaskParallaxOffscreen =
LauncherAnimUtils.ofPropertyValuesHolder(centerTask,
new PropertyListBuilder()
- .scale(v.getScaleX())
.translationX(isRtl ? -translationX : translationX)
.build());
- launcherAnimator.play(centerTaskParallaxToRight);
+ launcherAnimator.play(centerTaskParallaxOffscreen);
int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex);
- if (otherAdjacentTaskIndex >= recentsView.getFirstTaskIndex()
+ if (otherAdjacentTaskIndex >= 0
&& otherAdjacentTaskIndex < recentsView.getPageCount()) {
TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt(
otherAdjacentTaskIndex);
- ObjectAnimator otherAdjacentTaskParallaxToRight =
+ ObjectAnimator otherAdjacentTaskParallaxOffscreen =
LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask,
new PropertyListBuilder()
- .translationX(otherAdjacentTask.getTranslationX()
- + (isRtl ? -translationX : translationX))
+ .translationX(isRtl ? -translationX : translationX)
.build());
- launcherAnimator.play(otherAdjacentTaskParallaxToRight);
+ launcherAnimator.play(otherAdjacentTaskParallaxOffscreen);
}
}
@@ -368,7 +389,7 @@
* @return Animator that controls the window of the opening targets for the recents launch
* animation.
*/
- private ValueAnimator getRecentsWindowAnimator(TaskView v, MutableBoolean skipLauncherChanges,
+ private ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipLauncherChanges,
RemoteAnimationTargetCompat[] targets) {
Rect taskViewBounds = new Rect();
mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds);
@@ -404,7 +425,7 @@
final float percent = animation.getAnimatedFraction();
TaskWindowBounds tw = recentsInterpolator.interpolate(percent);
- if (!skipLauncherChanges.value) {
+ if (!skipLauncherChanges) {
v.setScaleX(tw.taskScale);
v.setScaleY(tw.taskScale);
v.setTranslationX(tw.taskX);
@@ -419,9 +440,8 @@
crop.set(tw.winCrop);
// Fade in the app window.
- float alphaDelay = 0;
float alphaDuration = 75;
- float alpha = getValue(0f, 1f, alphaDelay, alphaDuration,
+ float alpha = getValue(0f, 1f, 0, alphaDuration,
appAnimator.getDuration() * percent, Interpolators.LINEAR);
TransactionCompat t = new TransactionCompat();
@@ -435,7 +455,7 @@
t.setMatrix(target.leash, matrix);
t.setWindowCrop(target.leash, crop);
- if (!skipLauncherChanges.value) {
+ if (!skipLauncherChanges) {
t.deferTransactionUntil(target.leash, surface, frameNumber);
}
}
@@ -453,15 +473,6 @@
}
/**
- * Composes the animations for a launch from an app icon.
- */
- private LauncherTransitionAnimator composeAppLaunchAnimator(View v,
- RemoteAnimationTargetCompat[] targets) {
- return new LauncherTransitionAnimator(getLauncherAnimators(v, targets),
- getWindowAnimators(v, targets));
- }
-
- /**
* @return Animators that control the movements of the Launcher and icon of the opening target.
*/
private AnimatorSet getLauncherAnimators(View v, RemoteAnimationTargetCompat[] targets) {
@@ -545,10 +556,8 @@
} else {
mDragLayer.getDescendantRectRelativeToSelf(v, rect);
}
- final int viewLocationStart = mIsRtl
- ? mDeviceProfile.widthPx - rect.right
- : rect.left;
- final int viewLocationTop = rect.top;
+ int viewLocationLeft = rect.left;
+ int viewLocationTop = rect.top;
float startScale = 1f;
if (isBubbleTextView && !isDeepShortcutTextView) {
@@ -561,12 +570,24 @@
} else {
rect.set(0, 0, rect.width(), rect.height());
}
+ viewLocationLeft += rect.left;
+ viewLocationTop += rect.top;
+ int viewLocationStart = mIsRtl
+ ? mDeviceProfile.widthPx - rect.right
+ : viewLocationLeft;
LayoutParams lp = new LayoutParams(rect.width(), rect.height());
lp.ignoreInsets = true;
- lp.setMarginStart(viewLocationStart + rect.left);
- lp.topMargin = viewLocationTop + rect.top;
+ lp.setMarginStart(viewLocationStart);
+ lp.topMargin = viewLocationTop;
mFloatingView.setLayoutParams(lp);
+ // Set the properties here already to make sure they'are available when running the first
+ // animation frame.
+ mFloatingView.setLeft(viewLocationLeft);
+ mFloatingView.setTop(viewLocationTop);
+ mFloatingView.setRight(viewLocationLeft + rect.width());
+ mFloatingView.setBottom(viewLocationTop + rect.height());
+
// Swap the two views in place.
((ViewGroup) mDragLayer.getParent()).addView(mFloatingView);
v.setVisibility(View.INVISIBLE);
@@ -587,8 +608,8 @@
// Adjust the duration to change the "curve" of the app icon to the center.
boolean isBelowCenterY = lp.topMargin < centerY;
- x.setDuration(isBelowCenterY ? 500 : 233);
- y.setDuration(isBelowCenterY ? 233 : 500);
+ x.setDuration(isBelowCenterY ? APP_LAUNCH_DURATION : APP_LAUNCH_CURVED_DURATION);
+ y.setDuration(isBelowCenterY ? APP_LAUNCH_CURVED_DURATION : APP_LAUNCH_DURATION);
x.setInterpolator(Interpolators.AGGRESSIVE_EASE);
y.setInterpolator(Interpolators.AGGRESSIVE_EASE);
appIconAnimatorSet.play(x);
@@ -601,7 +622,7 @@
float scale = Math.max(maxScaleX, maxScaleY);
ObjectAnimator scaleAnim = ObjectAnimator
.ofFloat(mFloatingView, SCALE_PROPERTY, startScale, scale);
- scaleAnim.setDuration(500).setInterpolator(Interpolators.EXAGGERATED_EASE);
+ scaleAnim.setDuration(APP_LAUNCH_DURATION).setInterpolator(Interpolators.EXAGGERATED_EASE);
appIconAnimatorSet.play(scaleAnim);
// Fade out the app icon.
@@ -619,7 +640,13 @@
*/
private ValueAnimator getWindowAnimators(View v, RemoteAnimationTargetCompat[] targets) {
Rect bounds = new Rect();
- if (v instanceof BubbleTextView) {
+ boolean isDeepShortcutTextView = v instanceof DeepShortcutTextView
+ && v.getParent() != null && v.getParent() instanceof DeepShortcutView;
+ if (isDeepShortcutTextView) {
+ // Deep shortcut views have their icon drawn in a sibling view.
+ DeepShortcutView view = (DeepShortcutView) v.getParent();
+ mDragLayer.getDescendantRectRelativeToSelf(view.getIconView(), bounds);
+ } else if (v instanceof BubbleTextView) {
((BubbleTextView) v).getIconBounds(bounds);
} else {
mDragLayer.getDescendantRectRelativeToSelf(v, bounds);
@@ -630,7 +657,7 @@
Matrix matrix = new Matrix();
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
- appAnimator.setDuration(500);
+ appAnimator.setDuration(APP_LAUNCH_DURATION);
appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
boolean isFirstFrame = true;
@@ -670,9 +697,8 @@
matrix.postTranslate(transX0, transY0);
// Fade in the app window.
- float alphaDelay = 0;
float alphaDuration = 60;
- float alpha = getValue(0f, 1f, alphaDelay, alphaDuration,
+ float alpha = getValue(0f, 1f, 0, alphaDuration,
appAnimator.getDuration() * percent, Interpolators.LINEAR);
// Animate the window crop so that it starts off as a square, and then reveals
@@ -717,6 +743,7 @@
try {
RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN,
+ WindowManagerWrapper.ACTIVITY_TYPE_STANDARD,
new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(),
CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
@@ -744,40 +771,25 @@
* ie. pressing home, swiping up from nav bar.
*/
private RemoteAnimationRunnerCompat getWallpaperOpenRunner() {
- return new LauncherAnimationRunner(mLauncher) {
+ return new LauncherAnimationRunner(mHandler) {
@Override
- public void onAnimationStart(RemoteAnimationTargetCompat[] targets,
- Runnable finishedCallback) {
- Handler handler = mLauncher.getWindow().getDecorView().getHandler();
- postAtFrontOfQueueAsynchronously(handler, () -> {
- if ((Utilities.getPrefs(mLauncher)
- .getBoolean("pref_use_screenshot_for_swipe_up", false)
- && mLauncher.getStateManager().getState().overviewUi)
- || !launcherIsATargetWithMode(targets, MODE_OPENING)) {
- // We use a separate transition for Overview mode. And we can skip the
- // animation in cases where Launcher is not in the set of opening targets.
- // This can happen when Launcher is already visible. ie. Closing a dialog.
- setCurrentAnimator(null);
- finishedCallback.run();
- return;
- }
+ public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
+ if (mLauncher.getStateManager().getState().overviewUi) {
+ // We use a separate transition for Overview mode.
+ return null;
+ }
- LauncherTransitionAnimator animator = new LauncherTransitionAnimator(
- getLauncherResumeAnimation(), getClosingWindowAnimators(targets));
- setCurrentAnimator(animator);
- mAnimator = animator.getAnimatorSet();
- mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finishedCallback.run();
- }
- });
- mAnimator.start();
+ AnimatorSet anim = new AnimatorSet();
+ anim.play(getClosingWindowAnimators(targetCompats));
- // Because t=0 has the app icon in its original spot, we can skip the
- // first frame and have the same movement one frame earlier.
- mAnimator.setCurrentPlayTime(REFRESH_RATE_MS);
- });
+ if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)) {
+ AnimatorSet contentAnimation = getLauncherResumeAnimation();
+ anim.play(contentAnimation);
+
+ // Only register the content animation for cancellation when state changes
+ mLauncher.getStateManager().setCurrentAnimation(contentAnimation);
+ }
+ return anim;
}
};
}
@@ -844,16 +856,22 @@
if (mLauncher.isInState(LauncherState.ALL_APPS)
|| mLauncher.getDeviceProfile().isVerticalBarLayout()) {
AnimatorSet contentAnimator = getLauncherContentAnimator(true /* show */);
+ contentAnimator.addListener(mUiResetListener);
contentAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY);
return contentAnimator;
} else {
AnimatorSet workspaceAnimator = new AnimatorSet();
+
mLauncher.getWorkspace().setTranslationY(mWorkspaceTransY);
- mLauncher.getWorkspace().setAlpha(0f);
workspaceAnimator.play(ObjectAnimator.ofFloat(mLauncher.getWorkspace(),
View.TRANSLATION_Y, mWorkspaceTransY, 0));
- workspaceAnimator.play(ObjectAnimator.ofFloat(mLauncher.getWorkspace(), View.ALPHA,
- 0, 1f));
+
+ View currentPage = ((CellLayout) mLauncher.getWorkspace()
+ .getChildAt(mLauncher.getWorkspace().getCurrentPage()))
+ .getShortcutsAndWidgets();
+ currentPage.setAlpha(0f);
+ workspaceAnimator.play(ObjectAnimator.ofFloat(currentPage, View.ALPHA, 0, 1f));
+
workspaceAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY);
workspaceAnimator.setDuration(333);
workspaceAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
@@ -881,6 +899,8 @@
AnimatorSet resumeLauncherAnimation = new AnimatorSet();
resumeLauncherAnimation.play(workspaceAnimator);
resumeLauncherAnimation.playSequentially(allAppsSlideIn, allAppsOvershoot);
+
+ resumeLauncherAnimation.addListener(mReapplyStateListener);
return resumeLauncherAnimation;
}
}
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
new file mode 100644
index 0000000..0d1038a
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3;
+
+import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+
+import com.android.launcher3.states.InternalStateHandler;
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+
+import java.util.function.BiPredicate;
+
+@TargetApi(Build.VERSION_CODES.P)
+public class LauncherInitListener extends InternalStateHandler implements ActivityInitListener {
+
+ private final BiPredicate<Launcher, Boolean> mOnInitListener;
+
+ public LauncherInitListener(BiPredicate<Launcher, Boolean> onInitListener) {
+ mOnInitListener = onInitListener;
+ }
+
+ @Override
+ protected boolean init(Launcher launcher, boolean alreadyOnHome) {
+ // For the duration of the gesture, lock the screen orientation to ensure that we do not
+ // rotate mid-quickscrub
+ launcher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
+ return mOnInitListener.test(launcher, alreadyOnHome);
+ }
+
+ @Override
+ public void register() {
+ initWhenReady();
+ }
+
+ @Override
+ public void unregister() {
+ clearReference();
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java b/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java
deleted file mode 100644
index ab9234b..0000000
--- a/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-
-/**
- * Creates an AnimatorSet consisting on one Animator for Launcher transition, and one Animator for
- * the Window transitions.
- *
- * Allows for ending the Launcher animator without ending the Window animator.
- */
-public class LauncherTransitionAnimator {
-
- private final MutableBoolean mLauncherAnimCancelState;
-
- private AnimatorSet mAnimatorSet;
- private Animator mLauncherAnimator;
- private Animator mWindowAnimator;
-
- LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator) {
- this(launcherAnimator, windowAnimator, new MutableBoolean(false));
- }
-
-
- LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator,
- MutableBoolean launcherAnimCancelState) {
- mLauncherAnimCancelState = launcherAnimCancelState;
- if (launcherAnimator != null) {
- mLauncherAnimator = launcherAnimator;
- }
- mWindowAnimator = windowAnimator;
-
- mAnimatorSet = new AnimatorSet();
- if (launcherAnimator != null) {
- mAnimatorSet.play(launcherAnimator);
- }
- mAnimatorSet.play(windowAnimator);
- }
-
- public AnimatorSet getAnimatorSet() {
- return mAnimatorSet;
- }
-
- public void cancel() {
- mAnimatorSet.cancel();
- mLauncherAnimCancelState.value = true;
- }
-
- public boolean isRunning() {
- return mAnimatorSet.isRunning();
- }
-
- public void finishLauncherAnimation() {
- if (mLauncherAnimator != null) {
- mLauncherAnimCancelState.value = true;
- mLauncherAnimator.end();
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/MutableBoolean.java b/quickstep/src/com/android/launcher3/MutableBoolean.java
deleted file mode 100644
index 7538217..0000000
--- a/quickstep/src/com/android/launcher3/MutableBoolean.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-public class MutableBoolean {
- public boolean value;
-
- public MutableBoolean(boolean value) {
- this.value = value;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index ea03a76..1fb3584 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -25,6 +25,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
@@ -58,7 +59,8 @@
@Override
public String getDescription(Launcher launcher) {
- return launcher.getString(R.string.all_apps_button_label);
+ AllAppsContainerView appsView = launcher.getAppsView();
+ return appsView.getDescription();
}
@Override
@@ -83,7 +85,12 @@
}
@Override
- public float getHoseatAlpha(Launcher launcher) {
+ public int getVisibleElements(Launcher launcher) {
+ return ALL_APPS_HEADER | ALL_APPS_CONTENT;
+ }
+
+ @Override
+ public float getOverviewTranslationX(Launcher launcher) {
return 0;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java b/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java
deleted file mode 100644
index 6df1aba..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.uioverrides;
-
-import com.android.launcher3.Alarm;
-import com.android.launcher3.OnAlarmListener;
-
-/**
- * Utility class to detect a pause during a drag.
- */
-public class DragPauseDetector implements OnAlarmListener {
-
- private static final float MAX_VELOCITY_TO_PAUSE = 0.2f;
- private static final long PAUSE_DURATION = 100;
-
- private final Alarm mAlarm;
- private final Runnable mOnPauseCallback;
-
- private boolean mTriggered = false;
- private int mDisabledFlags = 0;
-
- public DragPauseDetector(Runnable onPauseCallback) {
- mOnPauseCallback = onPauseCallback;
-
- mAlarm = new Alarm();
- mAlarm.setOnAlarmListener(this);
- mAlarm.setAlarm(PAUSE_DURATION);
- }
-
- public void onDrag(float velocity) {
- if (mTriggered || !isEnabled()) {
- return;
- }
-
- if (Math.abs(velocity) > MAX_VELOCITY_TO_PAUSE) {
- // Cancel any previous alarm and set a new alarm
- mAlarm.setAlarm(PAUSE_DURATION);
- }
- }
-
- @Override
- public void onAlarm(Alarm alarm) {
- if (!mTriggered && isEnabled()) {
- mTriggered = true;
- mOnPauseCallback.run();
- }
- }
-
- public boolean isTriggered () {
- return mTriggered;
- }
-
- public boolean isEnabled() {
- return mDisabledFlags == 0;
- }
-
- public void addDisabledFlags(int flags) {
- boolean wasEnabled = isEnabled();
- mDisabledFlags |= flags;
- resetAlarm(wasEnabled);
- }
-
- public void clearDisabledFlags(int flags) {
- boolean wasEnabled = isEnabled();
- mDisabledFlags &= ~flags;
- resetAlarm(wasEnabled);
- }
-
- private void resetAlarm(boolean wasEnabled) {
- boolean isEnabled = isEnabled();
- if (wasEnabled == isEnabled) {
- // Nothing has changed
- } if (isEnabled && !mTriggered) {
- mAlarm.setAlarm(PAUSE_DURATION);
- } else if (!isEnabled) {
- mAlarm.cancelAlarm();
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
deleted file mode 100644
index a55edfe..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.touch.SwipeDetector.DIRECTION_NEGATIVE;
-import static com.android.launcher3.touch.SwipeDetector.DIRECTION_POSITIVE;
-import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL;
-import static com.android.launcher3.touch.SwipeDetector.VERTICAL;
-import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
-
-import android.graphics.Rect;
-import android.metrics.LogMaker;
-import android.view.MotionEvent;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.util.VerticalSwipeController;
-import com.android.quickstep.RecentsView;
-
-class EventLogTags {
- private EventLogTags() {
- } // don't instantiate
-
- /** 524292 sysui_multi_action (content|4) */
- public static final int SYSUI_MULTI_ACTION = 524292;
-
- public static void writeSysuiMultiAction(Object[] content) {
- android.util.EventLog.writeEvent(SYSUI_MULTI_ACTION, content);
- }
-}
-
-class MetricsLogger {
- private static MetricsLogger sMetricsLogger;
-
- private static MetricsLogger getLogger() {
- if (sMetricsLogger == null) {
- sMetricsLogger = new MetricsLogger();
- }
- return sMetricsLogger;
- }
-
- protected void saveLog(Object[] rep) {
- EventLogTags.writeSysuiMultiAction(rep);
- }
-
- public void write(LogMaker content) {
- if (content.getType() == 0/*MetricsEvent.TYPE_UNKNOWN*/) {
- content.setType(4/*MetricsEvent.TYPE_ACTION*/);
- }
- saveLog(content.serialize());
- }
-}
-
-/**
- * Extension of {@link VerticalSwipeController} to go from NORMAL to OVERVIEW.
- */
-public class EdgeSwipeController extends VerticalSwipeController implements
- OnDeviceProfileChangeListener {
-
- private static final Rect sTempRect = new Rect();
-
- private final MetricsLogger mMetricsLogger = new MetricsLogger();
-
- public EdgeSwipeController(Launcher l) {
- super(l, NORMAL, OVERVIEW, l.getDeviceProfile().isVerticalBarLayout()
- ? HORIZONTAL : VERTICAL);
- l.addOnDeviceProfileChangeListener(this);
- }
-
- @Override
- public void onDeviceProfileChanged(DeviceProfile dp) {
- mDetector.updateDirection(dp.isVerticalBarLayout() ? HORIZONTAL : VERTICAL);
- }
-
- @Override
- protected boolean shouldInterceptTouch(MotionEvent ev) {
- return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
- }
-
- @Override
- protected int getSwipeDirection(MotionEvent ev) {
- return isTransitionFlipped() ? DIRECTION_NEGATIVE : DIRECTION_POSITIVE;
- }
-
- public EdgeSwipeController(Launcher l, LauncherState baseState) {
- super(l, baseState);
- }
-
- @Override
- protected boolean isTransitionFlipped() {
- return mLauncher.getDeviceProfile().isSeascape();
- }
-
- @Override
- protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
- if (stateChanged && mToState instanceof OverviewState) {
- // Mimic ActivityMetricsLogger.logAppTransitionMultiEvents() logging for
- // "Recents" activity for app transition tests.
- final LogMaker builder = new LogMaker(761/*APP_TRANSITION*/);
- builder.setPackageName("com.android.systemui");
- builder.addTaggedData(871/*FIELD_CLASS_NAME*/,
- "com.android.systemui.recents.RecentsActivity");
- builder.addTaggedData(319/*APP_TRANSITION_DELAY_MS*/,
- 0/* zero time */);
- mMetricsLogger.write(builder);
-
- // Add user event logging for launcher pipeline
- int direction = Direction.UP;
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- direction = Direction.LEFT;
- if (mLauncher.getDeviceProfile().isSeascape()) {
- direction = Direction.RIGHT;
- }
- }
- mLauncher.getUserEventDispatcher().logStateChangeAction(
- wasFling ? Touch.FLING : Touch.SWIPE, direction,
- ContainerType.NAVBAR, ContainerType.WORKSPACE, // src target
- ContainerType.TASKSWITCHER, // dst target
- mLauncher.getWorkspace().getCurrentPage());
- }
- }
-
- @Override
- protected float getShiftRange() {
- return getShiftRange(mLauncher);
- }
-
- public static float getShiftRange(Launcher launcher) {
- RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, sTempRect);
- DragLayer dl = launcher.getDragLayer();
- Rect insets = dl.getInsets();
- DeviceProfile dp = launcher.getDeviceProfile();
-
- if (dp.isVerticalBarLayout()) {
- if (dp.isSeascape()) {
- return insets.left + sTempRect.left;
- } else {
- return dl.getWidth() - sTempRect.right + insets.right;
- }
- } else {
- return dl.getHeight() - sTempRect.bottom + insets.bottom;
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
index acd4fc1..9e82b25 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
@@ -16,6 +16,8 @@
package com.android.launcher3.uioverrides;
import com.android.launcher3.Launcher;
+import com.android.quickstep.QuickScrubController;
+import com.android.quickstep.views.RecentsView;
/**
* Extension of overview state used for QuickScrub
@@ -23,19 +25,26 @@
public class FastOverviewState extends OverviewState {
private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_DISABLE_RESTORE
- | FLAG_PAGE_BACKGROUNDS | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI;
+ | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI;
private static final boolean DEBUG_DIFFERENT_UI = false;
public FastOverviewState(int id) {
- super(id, STATE_FLAGS);
+ super(id, QuickScrubController.QUICK_SWITCH_START_DURATION, STATE_FLAGS);
}
@Override
- public float getHoseatAlpha(Launcher launcher) {
+ public void onStateTransitionEnd(Launcher launcher) {
+ super.onStateTransitionEnd(launcher);
+ RecentsView recentsView = launcher.getOverviewPanel();
+ recentsView.getQuickScrubController().onFinishedTransitionToQuickScrub();
+ }
+
+ @Override
+ public int getVisibleElements(Launcher launcher) {
if (DEBUG_DIFFERENT_UI) {
- return 0;
+ return NONE;
}
- return super.getHoseatAlpha(launcher);
+ return super.getVisibleElements(launcher);
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
new file mode 100644
index 0000000..23add95
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
@@ -0,0 +1,71 @@
+package com.android.launcher3.uioverrides;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.quickstep.util.SysuiEventLogger;
+
+/**
+ * Touch controller for handling edge swipes in landscape/seascape UI
+ */
+public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchController {
+
+ public LandscapeEdgeSwipeController(Launcher l) {
+ super(l, SwipeDetector.HORIZONTAL);
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ if (mCurrentAnimation != null) {
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
+ return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
+ }
+
+ @Override
+ protected int getSwipeDirection(MotionEvent ev) {
+ mFromState = NORMAL;
+ mToState = OVERVIEW;
+ return SwipeDetector.DIRECTION_BOTH;
+ }
+
+ @Override
+ protected float getShiftRange() {
+ return mLauncher.getDragLayer().getWidth();
+ }
+
+ @Override
+ protected float initCurrentAnimation() {
+ float range = getShiftRange();
+ long maxAccuracy = (long) (2 * range);
+ mCurrentAnimation = mLauncher.getStateManager()
+ .createAnimationToNewWorkspace(mToState, maxAccuracy);
+ return (mLauncher.getDeviceProfile().isSeascape() ? 2 : -2) / range;
+ }
+
+ @Override
+ protected int getDirectionForLog() {
+ return mLauncher.getDeviceProfile().isSeascape() ? Direction.RIGHT : Direction.LEFT;
+ }
+
+ @Override
+ protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+ super.onSwipeInteractionCompleted(targetState, logAction);
+ if (mFromState == NORMAL && targetState == OVERVIEW) {
+ SysuiEventLogger.writeDummyRecentsTransition(0);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java
new file mode 100644
index 0000000..720b20a
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java
@@ -0,0 +1,70 @@
+/*
+ * 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.uioverrides;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.quickstep.TouchInteractionService;
+import com.android.quickstep.views.RecentsView;
+
+/**
+ * Touch controller from going from OVERVIEW to ALL_APPS
+ */
+public class LandscapeStatesTouchController extends PortraitStatesTouchController {
+
+ public LandscapeStatesTouchController(Launcher l) {
+ super(l);
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ if (mCurrentAnimation != null) {
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
+ if (mLauncher.isInState(ALL_APPS)) {
+ // In all-apps only listen if the container cannot scroll itself
+ return mLauncher.getAppsView().shouldContainerScroll(ev);
+ } else if (mLauncher.isInState(NORMAL)) {
+ return true;
+ } else if (mLauncher.isInState(OVERVIEW)) {
+ RecentsView rv = mLauncher.getOverviewPanel();
+ return ev.getY() > (rv.getBottom() - rv.getPaddingBottom());
+ } else {
+ return false;
+ }
+ }
+
+ protected LauncherState getTargetState() {
+ if (mLauncher.isInState(ALL_APPS)) {
+ // Should swipe down go to OVERVIEW instead?
+ return TouchInteractionService.isConnected() ?
+ mLauncher.getStateManager().getLastState() : NORMAL;
+ } else {
+ return ALL_APPS;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 854fb4f..d123dce 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -16,18 +16,18 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
-import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
import android.graphics.Rect;
import android.view.View;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.R;
import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.quickstep.RecentsView;
+import com.android.quickstep.views.RecentsView;
/**
* Definition for overview state
@@ -35,31 +35,31 @@
public class OverviewState extends LauncherState {
private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
- | FLAG_DISABLE_RESTORE | FLAG_PAGE_BACKGROUNDS | FLAG_OVERVIEW_UI;
+ | FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI;
public OverviewState(int id) {
- this(id, STATE_FLAGS);
+ this(id, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
}
- protected OverviewState(int id, int stateFlags) {
- super(id, ContainerType.TASKSWITCHER, OVERVIEW_TRANSITION_MS, stateFlags);
+ protected OverviewState(int id, int transitionDuration, int stateFlags) {
+ super(id, ContainerType.TASKSWITCHER, transitionDuration, stateFlags);
}
@Override
public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
Rect pageRect = new Rect();
- RecentsView.getScaledDownPageRect(launcher.getDeviceProfile(), launcher, pageRect);
- RecentsView rv = launcher.getOverviewPanel();
+ RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, pageRect);
if (launcher.getWorkspace().getNormalChildWidth() <= 0 || pageRect.isEmpty()) {
return super.getWorkspaceScaleAndTranslation(launcher);
}
- float overlap = 0;
- if (rv.getCurrentPage() >= rv.getFirstTaskIndex()) {
- overlap = launcher.getResources().getDimension(R.dimen.workspace_overview_offset_x);
- }
- return getScaleAndTranslationForPageRect(launcher, overlap, pageRect);
+ return getScaleAndTranslationForPageRect(launcher, pageRect);
+ }
+
+ @Override
+ public float getOverviewTranslationX(Launcher launcher) {
+ return 0;
}
@Override
@@ -85,40 +85,50 @@
}
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
- final int centerPage = launcher.getWorkspace().getNextPage();
- return new PageAlphaProvider(ACCEL_2) {
+ return new PageAlphaProvider(DEACCEL_2) {
@Override
public float getPageAlpha(int pageIndex) {
- return pageIndex != centerPage ? 0 : 1f;
+ return 0;
}
};
}
- public static float[] getScaleAndTranslationForPageRect(Launcher launcher, float offsetX,
- Rect pageRect) {
+ public static float[] getScaleAndTranslationForPageRect(Launcher launcher, Rect pageRect) {
Workspace ws = launcher.getWorkspace();
float childWidth = ws.getNormalChildWidth();
- float childHeight = ws.getNormalChildHeight();
- float scale = pageRect.height() / childHeight;
+ float scale = pageRect.width() / childWidth;
Rect insets = launcher.getDragLayer().getInsets();
float halfHeight = ws.getExpectedHeight() / 2;
float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
float translationY = pageRect.top - childTop;
- // Align the workspace horizontally centered with the task rect
- float halfWidth = ws.getExpectedWidth() / 2;
- float childCenter = halfWidth -
- scale * (halfWidth - ws.getPaddingLeft() - insets.left - childWidth / 2);
- float translationX = pageRect.centerX() - childCenter;
+ return new float[] {scale, 0, translationY};
+ }
- if (launcher.<RecentsView>getOverviewPanel().isRtl()) {
- translationX -= offsetX / scale;
+ @Override
+ public int getVisibleElements(Launcher launcher) {
+ if (launcher.getDeviceProfile().isVerticalBarLayout()) {
+ // TODO: Remove hotseat from overview
+ return HOTSEAT;
} else {
- translationX += offsetX / scale;
+ return launcher.getAppsView().getFloatingHeaderView().hasVisibleContent()
+ ? ALL_APPS_HEADER : HOTSEAT;
}
+ }
- return new float[] {scale, translationX, translationY};
+ @Override
+ public float getVerticalProgress(Launcher launcher) {
+ if (getVisibleElements(launcher) == HOTSEAT) {
+ return super.getVerticalProgress(launcher);
+ }
+ return 1 - (getDefaultSwipeHeight(launcher)
+ / launcher.getAllAppsController().getShiftRange());
+ }
+
+ public static float getDefaultSwipeHeight(Launcher launcher) {
+ DeviceProfile dp = launcher.getDeviceProfile();
+ return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java
deleted file mode 100644
index 4fb3886..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.uioverrides;
-
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
-import android.view.MotionEvent;
-
-import com.android.launcher3.Launcher;
-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.VerticalSwipeController;
-
-/**
- * Extension of {@link VerticalSwipeController} which allows swipe up from OVERVIEW to ALL_APPS
- * Note that the swipe down is handled by {@link TwoStepSwipeController}.
- */
-public class OverviewSwipeUpController extends VerticalSwipeController {
-
- public OverviewSwipeUpController(Launcher l) {
- super(l, OVERVIEW);
- }
-
- @Override
- protected boolean shouldInterceptTouch(MotionEvent ev) {
- if (!mLauncher.isInState(OVERVIEW)) {
- return false;
- }
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- return ev.getY() >
- mLauncher.getDragLayer().getHeight() * OVERVIEW.getVerticalProgress(mLauncher);
- } else {
- return mLauncher.getDragLayer().isEventOverHotseat(ev);
- }
- }
-
- @Override
- protected int getSwipeDirection(MotionEvent ev) {
- return SwipeDetector.DIRECTION_POSITIVE;
- }
-
- @Override
- protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
- if (stateChanged) {
- // Transition complete. log the action
- mLauncher.getUserEventDispatcher().logStateChangeAction(
- wasFling ? Touch.FLING : Touch.SWIPE,
- Direction.UP,
- ContainerType.HOTSEAT,
- ContainerType.TASKSWITCHER,
- ContainerType.ALLAPPS,
- mLauncher.getWorkspace().getCurrentPage());
- }
-
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
new file mode 100644
index 0000000..9f648ed
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
+import com.android.quickstep.TouchInteractionService;
+import com.android.quickstep.util.SysuiEventLogger;
+
+/**
+ * Touch controller for handling various state transitions in portrait UI.
+ */
+public class PortraitStatesTouchController extends AbstractStateChangeTouchController {
+
+ public PortraitStatesTouchController(Launcher l) {
+ super(l, SwipeDetector.VERTICAL);
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ if (mCurrentAnimation != null) {
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (mLauncher.isInState(ALL_APPS)) {
+ // In all-apps only listen if the container cannot scroll itself
+ if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
+ return false;
+ }
+ } else {
+ // For all other states, only listen if the event originated below the hotseat height
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ int hotseatHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
+ if (ev.getY() < (mLauncher.getDragLayer().getHeight() - hotseatHeight)) {
+ return false;
+ }
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected int getSwipeDirection(MotionEvent ev) {
+ final int directionsToDetectScroll;
+ if (mLauncher.isInState(ALL_APPS)) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
+ mStartContainerType = ContainerType.ALLAPPS;
+ } else if (mLauncher.isInState(NORMAL)) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ mStartContainerType = ContainerType.HOTSEAT;
+ } else if (mLauncher.isInState(OVERVIEW)) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ mStartContainerType = ContainerType.TASKSWITCHER;
+ } else {
+ return 0;
+ }
+ mFromState = mLauncher.getStateManager().getState();
+ mToState = getTargetState();
+ if (mFromState == mToState) {
+ return 0;
+ }
+ return directionsToDetectScroll;
+ }
+
+ protected LauncherState getTargetState() {
+ if (mLauncher.isInState(ALL_APPS)) {
+ // Should swipe down go to OVERVIEW instead?
+ return TouchInteractionService.isConnected() ?
+ mLauncher.getStateManager().getLastState() : NORMAL;
+ } else if (mLauncher.isInState(OVERVIEW)) {
+ return ALL_APPS;
+ } else {
+ return TouchInteractionService.isConnected() ? OVERVIEW : ALL_APPS;
+ }
+ }
+
+ @Override
+ protected float initCurrentAnimation() {
+ float range = getShiftRange();
+ long maxAccuracy = (long) (2 * range);
+ mCurrentAnimation = mLauncher.getStateManager()
+ .createAnimationToNewWorkspace(mToState, maxAccuracy);
+
+ float startVerticalShift = mFromState.getVerticalProgress(mLauncher) * range;
+ float endVerticalShift = mToState.getVerticalProgress(mLauncher) * range;
+
+ float totalShift = endVerticalShift - startVerticalShift;
+ if (totalShift == 0) {
+ totalShift = Math.signum(mFromState.ordinal - mToState.ordinal)
+ * OverviewState.getDefaultSwipeHeight(mLauncher);
+ }
+ return 1 / totalShift;
+ }
+
+ @Override
+ protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+ super.onSwipeInteractionCompleted(targetState, logAction);
+ if (mFromState == NORMAL && targetState == OVERVIEW) {
+ SysuiEventLogger.writeDummyRecentsTransition(0);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 92d071a..b68a3d8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -28,88 +27,80 @@
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.PagedView;
-import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.quickstep.AnimatedFloat;
-import com.android.quickstep.RecentsView;
-import com.android.quickstep.TaskView;
+import com.android.quickstep.views.RecentsView;
public class RecentsViewStateController implements StateHandler {
private final Launcher mLauncher;
private final RecentsView mRecentsView;
- private final WorkspaceCard mWorkspaceCard;
private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::onTransitionProgress);
// The fraction representing the visibility of the RecentsView. This allows delaying the
// overall transition while the RecentsView is being shown or hidden.
private final AnimatedFloat mVisibilityMultiplier = new AnimatedFloat(this::onVisibilityProgress);
- private boolean mIsRecentsScrollingToFirstTask;
-
public RecentsViewStateController(Launcher launcher) {
mLauncher = launcher;
mRecentsView = launcher.getOverviewPanel();
- mRecentsView.setStateController(this);
-
- mWorkspaceCard = (WorkspaceCard) mRecentsView.getChildAt(0);
- mWorkspaceCard.setup(launcher);
}
@Override
public void setState(LauncherState state) {
- mWorkspaceCard.setWorkspaceScrollingEnabled(state.overviewUi);
setVisibility(state.overviewUi);
setTransitionProgress(state.overviewUi ? 1 : 0);
if (state.overviewUi) {
- for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
- ((TaskView) mRecentsView.getPageAt(i)).resetVisualProperties();
- }
- mRecentsView.updateCurveProperties();
+ mRecentsView.resetTaskVisuals();
}
+ float overviewTranslationX = state.getOverviewTranslationX(mLauncher);
+ int direction = mRecentsView.isRtl() ? -1 : 1;
+ mRecentsView.setTranslationX(overviewTranslationX * direction);
}
@Override
public void setStateWithAnimation(final LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config) {
- boolean settingEnabled = Utilities.getPrefs(mLauncher)
- .getBoolean("pref_scroll_to_first_task_default_true", true);
- mIsRecentsScrollingToFirstTask = mLauncher.isInState(NORMAL) && toState == OVERVIEW
- && settingEnabled;
- // TODO: Instead of animating the workspace translationX, move the contents
- mWorkspaceCard.setWorkspaceScrollingEnabled(mIsRecentsScrollingToFirstTask);
// Scroll to the workspace card before changing to the NORMAL state.
- int currPage = mRecentsView.getCurrentPage();
LauncherState fromState = mLauncher.getStateManager().getState();
+ int currPage = mRecentsView.getCurrentPage();
if (fromState.overviewUi && toState == NORMAL && currPage != 0 && !config.userControlled) {
int maxSnapDuration = PagedView.SLOW_PAGE_SNAP_ANIMATION_DURATION;
int durationPerPage = maxSnapDuration / 10;
int snapDuration = Math.min(maxSnapDuration, durationPerPage * currPage);
mRecentsView.snapToPage(0, snapDuration);
- builder.setStartDelay(snapDuration);
+ // Let the snapping animation play for a bit before we translate off screen.
+ builder.setStartDelay(snapDuration / 4);
}
ObjectAnimator progressAnim =
mTransitionProgress.animateToValue(toState.overviewUi ? 1 : 0);
progressAnim.setDuration(config.duration);
progressAnim.setInterpolator(Interpolators.LINEAR);
- progressAnim.addListener(new AnimationSuccessListener() {
-
- @Override
- public void onAnimationSuccess(Animator animator) {
- mWorkspaceCard.setWorkspaceScrollingEnabled(toState.overviewUi);
- mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen());
- }
- });
builder.play(progressAnim);
ObjectAnimator visibilityAnim = animateVisibility(toState.overviewUi);
visibilityAnim.setDuration(config.duration);
visibilityAnim.setInterpolator(Interpolators.LINEAR);
builder.play(visibilityAnim);
+
+ int direction = mRecentsView.isRtl() ? -1 : 1;
+ float fromTranslationX = fromState.getOverviewTranslationX(mLauncher) * direction;
+ float toTranslationX = toState.getOverviewTranslationX(mLauncher) * direction;
+ ObjectAnimator translationXAnim = ObjectAnimator.ofFloat(mRecentsView, View.TRANSLATION_X,
+ fromTranslationX, toTranslationX);
+ translationXAnim.setDuration(config.duration);
+ translationXAnim.setInterpolator(Interpolators.ACCEL);
+ if (toState.overviewUi) {
+ translationXAnim.addUpdateListener(valueAnimator -> {
+ // While animating into recents, update the visible task data as needed
+ mRecentsView.loadVisibleTaskData();
+ });
+ }
+ builder.play(translationXAnim);
}
public void setVisibility(boolean isVisible) {
@@ -145,12 +136,6 @@
private void onTransitionProgress() {
applyProgress();
- if (mIsRecentsScrollingToFirstTask) {
- int scrollForFirstTask = mRecentsView.getScrollForPage(mRecentsView.getFirstTaskIndex());
- int scrollForPage0 = mRecentsView.getScrollForPage(0);
- mRecentsView.setScrollX((int) (mTransitionProgress.value * scrollForFirstTask
- + (1 - mTransitionProgress.value) * scrollForPage0));
- }
}
private void onVisibilityProgress() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java b/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java
deleted file mode 100644
index 651a753..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.uioverrides;
-
-import android.animation.Animator;
-import android.util.SparseArray;
-
-import com.android.launcher3.anim.AnimatorSetBuilder;
-
-import java.util.Collections;
-import java.util.List;
-
-public class TaggedAnimatorSetBuilder extends AnimatorSetBuilder {
-
- /**
- * Map of the index in {@link #mAnims} to tag. All the animations in {@link #mAnims} starting
- * from this index correspond to the tag (until a new tag is specified for an index)
- */
- private final SparseArray<Object> mTags = new SparseArray<>();
-
- @Override
- public void startTag(Object obj) {
- mTags.put(mAnims.size(), obj);
- }
-
- public List<Animator> getAnimationsForTag(Object tag) {
- int startIndex = mTags.indexOfValue(tag);
- if (startIndex < 0) {
- return Collections.emptyList();
- }
- int startPos = mTags.keyAt(startIndex);
-
- int endIndex = startIndex + 1;
- int endPos = endIndex >= mTags.size() ? mAnims.size() : mTags.keyAt(endIndex);
-
- return mAnims.subList(startPos, endPos);
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
similarity index 62%
rename from quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
rename to quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
index 468a561..d11547d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
@@ -15,10 +15,12 @@
*/
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.util.Log;
import android.view.MotionEvent;
@@ -26,30 +28,21 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
-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.launcher3.util.TouchController;
-import com.android.quickstep.RecentsView;
-import com.android.quickstep.TaskView;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+import com.android.quickstep.PendingAnimation;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
/**
- * Touch controller for swipe interaction in Overview state
+ * Touch controller for handling task view card swipes
*/
-public class OverviewSwipeController extends AnimatorListenerAdapter
+public class TaskViewTouchController extends AnimatorListenerAdapter
implements TouchController, SwipeDetector.Listener {
private static final String TAG = "OverviewSwipeController";
@@ -65,20 +58,19 @@
private final RecentsView mRecentsView;
private final int[] mTempCords = new int[2];
+ private PendingAnimation mPendingAnimation;
private AnimatorPlaybackController mCurrentAnimation;
private boolean mCurrentAnimationIsGoingUp;
private boolean mNoIntercept;
- private boolean mSwipeDownEnabled;
private float mDisplacementShift;
private float mProgressMultiplier;
private float mEndDisplacement;
- private int mStartingTarget;
private TaskView mTaskBeingDragged;
- public OverviewSwipeController(Launcher launcher) {
+ public TaskViewTouchController(Launcher launcher) {
mLauncher = launcher;
mRecentsView = launcher.getOverviewPanel();
mDetector = new SwipeDetector(launcher, this, SwipeDetector.VERTICAL);
@@ -95,15 +87,6 @@
return mLauncher.isInState(OVERVIEW);
}
- private boolean isEventOverHotseat(MotionEvent ev) {
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- return ev.getY() >
- mLauncher.getDragLayer().getHeight() * OVERVIEW.getVerticalProgress(mLauncher);
- } else {
- return mLauncher.getDragLayer().isEventOverHotseat(ev);
- }
- }
-
@Override
public void onAnimationCancel(Animator animation) {
if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) {
@@ -130,30 +113,15 @@
ignoreSlopWhenSettling = true;
} else {
mTaskBeingDragged = null;
- mSwipeDownEnabled = true;
- int currentPage = mRecentsView.getCurrentPage();
- if (currentPage == 0) {
- // User is on home tile
+ View view = mRecentsView.getChildAt(mRecentsView.getCurrentPage());
+ if (view instanceof TaskView && mLauncher.getDragLayer().isEventOverView(view, ev)) {
+ // The tile can be dragged down to open the task.
+ mTaskBeingDragged = (TaskView) view;
directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
} else {
- View view = mRecentsView.getChildAt(currentPage);
- if (mLauncher.getDragLayer().isEventOverView(view, ev) &&
- view instanceof TaskView) {
- // The tile can be dragged down to open the task.
- mTaskBeingDragged = (TaskView) view;
- directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
- mStartingTarget = LauncherLogProto.ItemType.TASK;
- } else if (isEventOverHotseat(ev)) {
- // The hotseat is being dragged
- directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
- mSwipeDownEnabled = false;
- mStartingTarget = ContainerType.HOTSEAT;
- } else {
- mNoIntercept = true;
- mStartingTarget = ContainerType.WORKSPACE;
- return false;
- }
+ mNoIntercept = true;
+ return false;
}
}
@@ -175,9 +143,6 @@
}
private void reInitAnimationController(boolean goingUp) {
- if (!goingUp && !mSwipeDownEnabled) {
- goingUp = true;
- }
if (mCurrentAnimation != null && mCurrentAnimationIsGoingUp == goingUp) {
// No need to init
return;
@@ -185,44 +150,30 @@
if (mCurrentAnimation != null) {
mCurrentAnimation.setPlayFraction(0);
}
+ if (mPendingAnimation != null) {
+ mPendingAnimation.finish(false);
+ mPendingAnimation = null;
+ }
+
mCurrentAnimationIsGoingUp = goingUp;
float range = mLauncher.getAllAppsController().getShiftRange();
long maxDuration = (long) (2 * range);
DragLayer dl = mLauncher.getDragLayer();
- if (mTaskBeingDragged == null) {
- // User is either going to all apps or home
- mCurrentAnimation = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(goingUp ? ALL_APPS : NORMAL, maxDuration);
- if (goingUp) {
- mEndDisplacement = -range;
- } else {
- mEndDisplacement = EdgeSwipeController.getShiftRange(mLauncher);
- }
+ if (goingUp) {
+ mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
+ true /* animateTaskView */, true /* removeTask */, maxDuration);
+ mCurrentAnimation = AnimatorPlaybackController
+ .wrap(mPendingAnimation.anim, maxDuration);
+ mEndDisplacement = -mTaskBeingDragged.getHeight();
} else {
- if (goingUp) {
- AnimatorSet anim = new AnimatorSet();
- ObjectAnimator translate = ObjectAnimator.ofFloat(
- mTaskBeingDragged, View.TRANSLATION_Y, -mTaskBeingDragged.getBottom());
- translate.setInterpolator(LINEAR);
- translate.setDuration(maxDuration);
- anim.play(translate);
+ AnimatorSet anim = new AnimatorSet();
+ // TODO: Setup a zoom animation
+ mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration);
- ObjectAnimator alpha = ObjectAnimator.ofFloat(mTaskBeingDragged, View.ALPHA, 0);
- alpha.setInterpolator(DEACCEL_1_5);
- alpha.setDuration(maxDuration);
- anim.play(alpha);
- mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration);
- mEndDisplacement = -mTaskBeingDragged.getBottom();
- } else {
- AnimatorSet anim = new AnimatorSet();
- // TODO: Setup a zoom animation
- mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration);
-
- mTempCords[1] = mTaskBeingDragged.getHeight();
- dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
- mEndDisplacement = dl.getHeight() - mTempCords[1];
- }
+ mTempCords[1] = mTaskBeingDragged.getHeight();
+ dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
+ mEndDisplacement = dl.getHeight() - mTempCords[1];
}
mCurrentAnimation.getTarget().addListener(this);
@@ -260,9 +211,7 @@
if (fling) {
logAction = Touch.FLING;
boolean goingUp = velocity < 0;
- if (!goingUp && !mSwipeDownEnabled) {
- goingToEnd = false;
- } else if (goingUp != mCurrentAnimationIsGoingUp) {
+ if (goingUp != mCurrentAnimationIsGoingUp) {
// In case the fling is in opposite direction, make sure if is close enough
// from the start position
if (mCurrentAnimation.getProgressFraction()
@@ -288,7 +237,6 @@
float nextFrameProgress = Utilities.boundToRange(
progress + velocity * SINGLE_FRAME_MS / Math.abs(mEndDisplacement), 0f, 1f);
-
mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd, logAction));
ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
@@ -299,27 +247,17 @@
}
private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) {
- if (mTaskBeingDragged == null) {
- LauncherState state = wasSuccess ?
- (mCurrentAnimationIsGoingUp ? ALL_APPS : NORMAL) : OVERVIEW;
- mLauncher.getStateManager().goToState(state, false);
-
- } else if (wasSuccess) {
- if (mCurrentAnimationIsGoingUp) {
- mRecentsView.onTaskDismissed(mTaskBeingDragged);
- } else {
+ if (mPendingAnimation != null) {
+ mPendingAnimation.finish(wasSuccess);
+ mPendingAnimation = null;
+ }
+ if (wasSuccess) {
+ if (!mCurrentAnimationIsGoingUp) {
mTaskBeingDragged.launchTask(false);
mLauncher.getUserEventDispatcher().logTaskLaunch(logAction,
Direction.DOWN, mTaskBeingDragged.getTask().getTopComponent());
}
}
- if (mTaskBeingDragged == null || (wasSuccess && mCurrentAnimationIsGoingUp)) {
- mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
- mCurrentAnimationIsGoingUp ? Direction.UP : Direction.DOWN,
- mStartingTarget, ContainerType.TASKSWITCHER,
- mLauncher.getStateManager().getState().containerType,
- mRecentsView.getCurrentPage());
- }
mDetector.finishedScrolling();
mTaskBeingDragged = null;
mCurrentAnimation = null;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
deleted file mode 100644
index c8d75dc..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * 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.uioverrides;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.launcher3.AbstractFloatingView;
-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.LauncherStateManager.StateHandler;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.config.FeatureFlags;
-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.FloatRange;
-import com.android.launcher3.util.TouchController;
-import com.android.quickstep.TouchInteractionService;
-
-/**
- * Handles vertical touch gesture on the DragLayer
- */
-public class TwoStepSwipeController extends AnimatorListenerAdapter
- implements TouchController, SwipeDetector.Listener {
-
- private static final String TAG = "TwoStepSwipeController";
-
- private static final float RECATCH_REJECTION_FRACTION = .0875f;
- private static final int SINGLE_FRAME_MS = 16;
- private static final long QUICK_SNAP_TO_OVERVIEW_DURATION = 250;
-
- // 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;
-
- /**
- * Index of the vertical swipe handles in {@link LauncherStateManager#getStateHandlers()}.
- */
- private static final int SWIPE_HANDLER_INDEX = 0;
-
- /**
- * Index of various UI handlers in {@link LauncherStateManager#getStateHandlers()} not related
- * to vertical swipe.
- */
- private static final int OTHER_HANDLERS_START_INDEX = SWIPE_HANDLER_INDEX + 1;
-
- // Swipe progress range (when starting from NORMAL state) where OVERVIEW state is allowed
- private static final float MIN_PROGRESS_TO_OVERVIEW = 0.1f;
- private static final float MAX_PROGRESS_TO_OVERVIEW = 0.4f;
-
- private static final int FLAG_OVERVIEW_DISABLED_OUT_OF_RANGE = 1 << 0;
- private static final int FLAG_OVERVIEW_DISABLED_FLING = 1 << 1;
- private static final int FLAG_OVERVIEW_DISABLED_CANCEL_STATE = 1 << 2;
- private static final int FLAG_OVERVIEW_DISABLED = 1 << 4;
- private static final int FLAG_DISABLED_TWO_TARGETS = 1 << 5;
- private static final int FLAG_DISABLED_BACK_TARGET = 1 << 6;
-
- private final Launcher mLauncher;
- private final SwipeDetector mDetector;
-
- private boolean mNoIntercept;
- private int mStartContainerType;
-
- private DragPauseDetector mDragPauseDetector;
- private FloatRange mOverviewProgressRange;
- private TaggedAnimatorSetBuilder mTaggedAnimatorSetBuilder;
- private AnimatorSet mQuickOverviewAnimation;
- private boolean mAnimatingToOverview;
- private CroppedAnimationController mCroppedAnimationController;
-
- private AnimatorPlaybackController mCurrentAnimation;
- private LauncherState mFromState;
- private LauncherState mToState;
-
- private float mStartProgress;
- // Ratio of transition process [0, 1] to drag displacement (px)
- private float mProgressMultiplier;
-
- public TwoStepSwipeController(Launcher l) {
- mLauncher = l;
- mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
- }
-
- private boolean canInterceptTouch(MotionEvent ev) {
- if (mCurrentAnimation != null) {
- // If we are already animating from a previous state, we can intercept.
- return true;
- }
- if (mLauncher.isInState(NORMAL)) {
- if ((ev.getEdgeFlags() & EDGE_NAV_BAR) != 0 &&
- !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- // On normal swipes ignore edge swipes
- return false;
- }
- } else if (mLauncher.isInState(ALL_APPS)) {
- if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
- return false;
- }
- } else {
- // Don't listen for the swipe gesture if we are already in some other state.
- return false;
- }
- if (mAnimatingToOverview) {
- return false;
- }
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
- return false;
- }
-
- return true;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- if (mCurrentAnimation != null && animation == mCurrentAnimation.getOriginalTarget()) {
- Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception());
- clearState();
- }
- }
-
- @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 (mNoIntercept) {
- return false;
- }
-
- onControllerTouchEvent(ev);
- return mDetector.isDraggingOrSettling();
- }
-
- @Override
- public boolean onControllerTouchEvent(MotionEvent ev) {
- return mDetector.onTouchEvent(ev);
- }
-
- @Override
- public void onDragStart(boolean start) {
- if (mCurrentAnimation == null) {
- float range = getShiftRange();
- long maxAccuracy = (long) (2 * range);
-
- mDragPauseDetector = new DragPauseDetector(this::onDragPauseDetected);
- mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED_OUT_OF_RANGE);
- if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) {
- mDragPauseDetector.addDisabledFlags(FLAG_DISABLED_TWO_TARGETS);
- }
-
- mOverviewProgressRange = new FloatRange();
- mOverviewProgressRange.start = mLauncher.isInState(NORMAL)
- ? MIN_PROGRESS_TO_OVERVIEW
- : 1 - MAX_PROGRESS_TO_OVERVIEW;
- mOverviewProgressRange.end = mOverviewProgressRange.start
- + MAX_PROGRESS_TO_OVERVIEW - MIN_PROGRESS_TO_OVERVIEW;
-
- // Build current animation
- mFromState = mLauncher.getStateManager().getState();
- mToState = mLauncher.isInState(ALL_APPS) ? NORMAL : ALL_APPS;
-
- if (mToState == NORMAL && mLauncher.getStateManager().getLastState() == OVERVIEW) {
- mToState = OVERVIEW;
- mDragPauseDetector.addDisabledFlags(FLAG_DISABLED_BACK_TARGET);
- }
-
- mTaggedAnimatorSetBuilder = new TaggedAnimatorSetBuilder();
- mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(
- mToState, mTaggedAnimatorSetBuilder, maxAccuracy);
-
- if (!TouchInteractionService.isConnected()) {
- mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED);
- }
-
- mCurrentAnimation.getTarget().addListener(this);
- mStartProgress = 0;
- mProgressMultiplier = (mLauncher.isInState(ALL_APPS) ? 1 : -1) / range;
- mCurrentAnimation.dispatchOnStart();
- } else {
- mCurrentAnimation.pause();
- mStartProgress = mCurrentAnimation.getProgressFraction();
-
- mDragPauseDetector.clearDisabledFlags(FLAG_OVERVIEW_DISABLED_FLING);
- updatePauseDetectorRangeFlag();
- }
- }
-
- private float getShiftRange() {
- return mLauncher.getAllAppsController().getShiftRange();
- }
-
- @Override
- public boolean onDrag(float displacement, float velocity) {
- float deltaProgress = mProgressMultiplier * displacement;
- mCurrentAnimation.setPlayFraction(deltaProgress + mStartProgress);
-
- updatePauseDetectorRangeFlag();
- mDragPauseDetector.onDrag(velocity);
-
- return true;
- }
-
- private void updatePauseDetectorRangeFlag() {
- if (mOverviewProgressRange.contains(mCurrentAnimation.getProgressFraction())) {
- mDragPauseDetector.clearDisabledFlags(FLAG_OVERVIEW_DISABLED_OUT_OF_RANGE);
- } else {
- mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED_OUT_OF_RANGE);
- }
- }
-
- @Override
- public void onDragEnd(float velocity, boolean fling) {
- mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED_FLING);
-
- final int logAction;
- LauncherState targetState;
- final float progress = mCurrentAnimation.getProgressFraction();
-
- if (fling) {
- logAction = Touch.FLING;
- targetState = velocity < 0 ? ALL_APPS : mLauncher.getStateManager().getLastState();
- // snap to top or bottom using the release velocity
- } else {
- logAction = Touch.SWIPE;
- targetState = (progress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState;
- }
-
- float endProgress;
-
- if (mDragPauseDetector.isTriggered() && targetState == NORMAL) {
- targetState = OVERVIEW;
- endProgress = OVERVIEW.getVerticalProgress(mLauncher);
- if (mFromState == NORMAL) {
- endProgress = 1 - endProgress;
- }
- } else if (targetState == mToState) {
- endProgress = 1;
- } else {
- endProgress = 0;
- }
-
- LauncherState targetStateFinal = targetState;
- mCurrentAnimation.setEndAction(() ->
- onSwipeInteractionCompleted(targetStateFinal, logAction));
-
- float nextFrameProgress = Utilities.boundToRange(
- progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
-
- ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
- anim.setFloatValues(nextFrameProgress, endProgress);
- anim.setDuration(
- SwipeDetector.calculateDuration(velocity, Math.abs(endProgress - progress)));
- anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
- anim.start();
- }
-
- private void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
- if (targetState != mFromState) {
- // Transition complete. log the action
- mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
- mToState == ALL_APPS ? Direction.UP : Direction.DOWN,
- mStartContainerType,
- mFromState.containerType,
- mToState.containerType,
- mLauncher.getWorkspace().getCurrentPage());
- }
- clearState();
-
- // TODO: mQuickOverviewAnimation might still be running in which changing a state instantly
- // may cause a jump. Animate the state change with a short duration in this case?
- mLauncher.getStateManager().goToState(targetState, false /* animated */);
- }
-
- private void onDragPauseDetected() {
- final ValueAnimator twoStepAnimator = ValueAnimator.ofFloat(0, 1);
- twoStepAnimator.setDuration(mCurrentAnimation.getDuration());
- StateHandler[] handlers = mLauncher.getStateManager().getStateHandlers();
-
- // Change the current animation to only play the vertical handle
- AnimatorSet anim = new AnimatorSet();
- anim.playTogether(mTaggedAnimatorSetBuilder.getAnimationsForTag(
- handlers[SWIPE_HANDLER_INDEX]));
- anim.play(twoStepAnimator);
- mCurrentAnimation = mCurrentAnimation.cloneFor(anim);
-
- AnimatorSetBuilder builder = new AnimatorSetBuilder();
- AnimationConfig config = new AnimationConfig();
- config.duration = QUICK_SNAP_TO_OVERVIEW_DURATION;
- for (int i = OTHER_HANDLERS_START_INDEX; i < handlers.length; i++) {
- handlers[i].setStateWithAnimation(OVERVIEW, builder, config);
- }
- mQuickOverviewAnimation = builder.build();
- mQuickOverviewAnimation.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- onQuickOverviewAnimationComplete(twoStepAnimator);
- }
- });
- mQuickOverviewAnimation.start();
- }
-
- private void onQuickOverviewAnimationComplete(ValueAnimator animator) {
- if (mAnimatingToOverview) {
- return;
- }
-
- // For the remainder to the interaction, the user can either go to the ALL_APPS state or
- // the OVERVIEW state.
- // The remaining state handlers are on the OVERVIEW state. Create one animation towards the
- // ALL_APPS state and only call it when the user moved above the current range.
- AnimationConfig config = new AnimationConfig();
- config.duration = (long) (2 * getShiftRange());
- config.userControlled = true;
-
- AnimatorSetBuilder builderToAllAppsState = new AnimatorSetBuilder();
- StateHandler[] handlers = mLauncher.getStateManager().getStateHandlers();
- for (int i = OTHER_HANDLERS_START_INDEX; i < handlers.length; i++) {
- handlers[i].setStateWithAnimation(ALL_APPS, builderToAllAppsState, config);
- }
-
- mCroppedAnimationController = new CroppedAnimationController(
- AnimatorPlaybackController.wrap(builderToAllAppsState.build(), config.duration),
- new FloatRange(animator.getAnimatedFraction(), mToState == ALL_APPS ? 1 : 0));
- animator.addUpdateListener(mCroppedAnimationController);
- }
-
- private void clearState() {
- mCurrentAnimation = null;
- mTaggedAnimatorSetBuilder = null;
- if (mDragPauseDetector != null) {
- mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED_CANCEL_STATE);
- }
- mDragPauseDetector = null;
-
- if (mQuickOverviewAnimation != null) {
- mQuickOverviewAnimation.cancel();
- mQuickOverviewAnimation = null;
- }
- mCroppedAnimationController = null;
- mAnimatingToOverview = false;
-
- mDetector.finishedScrolling();
- }
-
- /**
- * {@link AnimatorUpdateListener} which controls another animation for a fraction of range
- */
- private static class CroppedAnimationController implements AnimatorUpdateListener {
-
- private final AnimatorPlaybackController mTarget;
- private final FloatRange mRange;
-
- CroppedAnimationController(AnimatorPlaybackController target, FloatRange range) {
- mTarget = target;
- mRange = range;
- }
-
-
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- float fraction = valueAnimator.getAnimatedFraction();
-
- if (mRange.start < mRange.end) {
- if (fraction <= mRange.start) {
- mTarget.setPlayFraction(0);
- } else if (fraction >= mRange.end) {
- mTarget.setPlayFraction(1);
- } else {
- mTarget.setPlayFraction((fraction - mRange.start) / (mRange.end - mRange.start));
- }
- } else if (mRange.start > mRange.end) {
- if (fraction >= mRange.start) {
- mTarget.setPlayFraction(0);
- } else if (fraction <= mRange.end) {
- mTarget.setPlayFraction(1);
- } else {
- mTarget.setPlayFraction((fraction - mRange.start) / (mRange.end - mRange.start));
- }
- } else {
- // mRange.start == mRange.end
- mTarget.setPlayFraction(0);
- }
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index a8bcb11..49792ac 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -18,35 +18,33 @@
import static com.android.launcher3.LauncherState.NORMAL;
-import android.graphics.PointF;
+import android.content.Context;
import android.view.View;
import android.view.View.AccessibilityDelegate;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.RecentsModel;
-import com.android.quickstep.RecentsView;
+import com.android.quickstep.views.RecentsView;
public class UiFactory {
- private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
- "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
-
public static TouchController[] createTouchControllers(Launcher launcher) {
- if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) {
+ if (launcher.getDeviceProfile().isVerticalBarLayout()) {
return new TouchController[] {
- new EdgeSwipeController(launcher),
- new TwoStepSwipeController(launcher),
- new OverviewSwipeController(launcher)};
+ launcher.getDragController(),
+ new LandscapeStatesTouchController(launcher),
+ new LandscapeEdgeSwipeController(launcher),
+ new TaskViewTouchController(launcher)};
} else {
return new TouchController[] {
- new TwoStepSwipeController(launcher),
- new OverviewSwipeController(launcher)};
+ launcher.getDragController(),
+ new PortraitStatesTouchController(launcher),
+ new TaskViewTouchController(launcher)};
}
}
@@ -60,10 +58,6 @@
new RecentsViewStateController(launcher)};
}
- public static void onWorkspaceLongPress(Launcher launcher, PointF touchPoint) {
- OptionsPopupView.show(launcher, touchPoint.x, touchPoint.y);
- }
-
public static void onLauncherStateOrFocusChanged(Launcher launcher) {
boolean shouldBackButtonBeVisible = launcher == null
|| !launcher.isInState(NORMAL)
@@ -79,7 +73,8 @@
}
}
}
- OverviewInteractionState.setBackButtonVisible(launcher, shouldBackButtonBeVisible);
+ OverviewInteractionState.getInstance(launcher)
+ .setBackButtonVisible(shouldBackButtonBeVisible);
}
public static void resetOverview(Launcher launcher) {
@@ -87,15 +82,15 @@
recents.reset();
}
- public static void onStart(Launcher launcher) {
- RecentsModel model = RecentsModel.getInstance(launcher);
+ public static void onStart(Context context) {
+ RecentsModel model = RecentsModel.getInstance(context);
if (model != null) {
model.onStart();
}
}
- public static void onTrimMemory(Launcher launcher, int level) {
- RecentsModel model = RecentsModel.getInstance(launcher);
+ public static void onTrimMemory(Context context, int level) {
+ RecentsModel model = RecentsModel.getInstance(context);
if (model != null) {
model.onTrimMemory(level);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
deleted file mode 100644
index 8533502..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.uioverrides;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.Workspace;
-import com.android.quickstep.RecentsView;
-import com.android.quickstep.RecentsView.PageCallbacks;
-import com.android.quickstep.RecentsView.ScrollState;
-
-public class WorkspaceCard extends View implements PageCallbacks, OnClickListener {
-
- private final Rect mTempRect = new Rect();
-
- private Launcher mLauncher;
- private Workspace mWorkspace;
-
- private float mLinearInterpolationForPage2 = 1;
- private float mTranslateXPage0, mTranslateXPage1;
- private float mExtraScrollShift;
-
- private boolean mIsWorkspaceScrollingEnabled;
-
- public WorkspaceCard(Context context) {
- this(context, null);
- }
-
- public WorkspaceCard(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public WorkspaceCard(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- setOnClickListener(this);
- }
-
- /**
- * Draw nothing.
- */
- @Override
- public void draw(Canvas canvas) { }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- // Initiate data
- mLinearInterpolationForPage2 = RecentsView.getScaledDownPageRect(
- mLauncher.getDeviceProfile(), mLauncher, mTempRect);
-
- float[] scale = OverviewState.getScaleAndTranslationForPageRect(mLauncher, 0, mTempRect);
- mTranslateXPage0 = scale[1];
- mTranslateXPage1 = OverviewState
- .getScaleAndTranslationForPageRect(mLauncher,
- getResources().getDimension(R.dimen.workspace_overview_offset_x) / scale[0],
- mTempRect)[1];
-
- mExtraScrollShift = 0;
- if (mWorkspace != null && getWidth() > 0) {
- float workspaceWidth = mWorkspace.getNormalChildWidth() * scale[0];
- mExtraScrollShift = (workspaceWidth - getWidth()) / 2;
- setScaleX(workspaceWidth / getWidth());
- }
- }
-
- @Override
- public void onClick(View view) {
- mLauncher.getStateManager().goToState(NORMAL);
- }
-
- public void setup(Launcher launcher) {
- mLauncher = launcher;
- mWorkspace = mLauncher.getWorkspace();
- }
-
- public void setWorkspaceScrollingEnabled(boolean isEnabled) {
- mIsWorkspaceScrollingEnabled = isEnabled;
- }
-
- @Override
- public int onPageScroll(ScrollState scrollState) {
- float factor = scrollState.linearInterpolation;
- float translateX = scrollState.distanceFromScreenCenter;
- if (mIsWorkspaceScrollingEnabled) {
- float shift = factor * (mTranslateXPage1 - mTranslateXPage0);
- mWorkspace.setTranslationX(shift + mTranslateXPage0);
- translateX += shift;
- }
-
- setTranslationX(translateX);
-
- // If the workspace card is still the first page, shift all the other pages.
- if (scrollState.linearInterpolation > mLinearInterpolationForPage2) {
- scrollState.prevPageExtraWidth = 0;
- } else if (mLinearInterpolationForPage2 > 0) {
- scrollState.prevPageExtraWidth = mExtraScrollShift *
- (1 - scrollState.linearInterpolation / mLinearInterpolationForPage2);
- } else {
- scrollState.prevPageExtraWidth = mExtraScrollShift;
- }
- return SCROLL_TYPE_WORKSPACE;
- }
-}
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
new file mode 100644
index 0000000..b43352a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -0,0 +1,312 @@
+/*
+ * 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;
+
+import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherInitListener;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.util.ViewOnDrawExecutor;
+import com.android.quickstep.views.LauncherLayoutListener;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.AssistDataReceiver;
+import com.android.systemui.shared.system.RecentsAnimationListener;
+import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
+
+import java.util.function.BiPredicate;
+
+/**
+ * Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
+ */
+public interface ActivityControlHelper<T extends BaseDraggingActivity> {
+
+ LayoutListener createLayoutListener(T activity);
+
+ void onQuickstepGestureStarted(T activity, boolean activityVisible);
+
+ void onQuickInteractionStart(T activity, boolean activityVisible);
+
+ void executeOnNextDraw(T activity, TaskView targetView, Runnable action);
+
+ void onTransitionCancelled(T activity, boolean activityVisible);
+
+ int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect);
+
+ void onSwipeUpComplete(T activity);
+
+ void prepareRecentsUI(T activity, boolean activityVisible);
+
+ AnimatorPlaybackController createControllerForVisibleActivity(T activity);
+
+ AnimatorPlaybackController createControllerForHiddenActivity(T activity, int transitionLength);
+
+ ActivityInitListener createActivityInitListener(BiPredicate<T, Boolean> onInitListener);
+
+ void startRecents(Context context, Intent intent, AssistDataReceiver assistDataReceiver,
+ RecentsAnimationListener remoteAnimationListener);
+
+ class LauncherActivityControllerHelper implements ActivityControlHelper<Launcher> {
+
+ @Override
+ public LayoutListener createLayoutListener(Launcher activity) {
+ return new LauncherLayoutListener(activity);
+ }
+
+ @Override
+ public void onQuickstepGestureStarted(Launcher activity, boolean activityVisible) {
+ activity.onQuickstepGestureStarted(activityVisible);
+ }
+
+ @Override
+ public void onQuickInteractionStart(Launcher activity, boolean activityVisible) {
+ activity.getStateManager().goToState(FAST_OVERVIEW, activityVisible);
+ }
+
+ @Override
+ public void executeOnNextDraw(Launcher activity, TaskView targetView, Runnable action) {
+ ViewOnDrawExecutor executor = new ViewOnDrawExecutor() {
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ if (!isCompleted()) {
+ runAllTasks();
+ }
+ }
+ };
+ executor.attachTo(activity, targetView, false /* waitForLoadAnimation */);
+ executor.execute(action);
+ }
+
+ @Override
+ public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
+ RecentsView.getPageRect(dp, context, outRect);
+ if (dp.isVerticalBarLayout()) {
+ Rect targetInsets = dp.getInsets();
+ int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
+ return dp.hotseatBarSizePx + dp.hotseatBarSidePaddingPx + hotseatInset;
+ } else {
+ return dp.heightPx - outRect.bottom;
+ }
+ }
+
+ @Override
+ public void onTransitionCancelled(Launcher activity, boolean activityVisible) {
+ LauncherState startState = activity.getStateManager().getRestState();
+ activity.getStateManager().goToState(startState, activityVisible);
+ }
+
+ @Override
+ public void onSwipeUpComplete(Launcher activity) {
+ // Re apply state in case we did something funky during the transition.
+ activity.getStateManager().reapplyState();
+ }
+
+ @Override
+ public void prepareRecentsUI(Launcher activity, boolean activityVisible) {
+ LauncherState startState = activity.getStateManager().getState();
+ if (startState.disableRestore) {
+ startState = activity.getStateManager().getRestState();
+ }
+ activity.getStateManager().setRestState(startState);
+
+ if (!activityVisible) {
+ // Since the launcher is not visible, we can safely reset the scroll position.
+ // This ensures then the next swipe up to all-apps starts from scroll 0.
+ activity.getAppsView().reset(false /* animate */);
+ activity.getStateManager().goToState(OVERVIEW, false);
+
+ // Optimization, hide the all apps view to prevent layout while initializing
+ activity.getAppsView().getContentView().setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public AnimatorPlaybackController createControllerForVisibleActivity(Launcher activity) {
+ DeviceProfile dp = activity.getDeviceProfile();
+ long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
+ return activity.getStateManager().createAnimationToNewWorkspace(OVERVIEW, accuracy);
+ }
+
+ @Override
+ public AnimatorPlaybackController createControllerForHiddenActivity(
+ Launcher activity, int transitionLength) {
+ AllAppsTransitionController controller = activity.getAllAppsController();
+ AnimatorSet anim = new AnimatorSet();
+ if (activity.getDeviceProfile().isVerticalBarLayout()) {
+ // TODO:
+ } else {
+ float scrollRange = Math.max(controller.getShiftRange(), 1);
+ float progressDelta = (transitionLength / scrollRange);
+
+ float endProgress = OVERVIEW.getVerticalProgress(activity);
+ float startProgress = endProgress + progressDelta;
+ ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(
+ controller, ALL_APPS_PROGRESS, startProgress, endProgress);
+ shiftAnim.setInterpolator(LINEAR);
+ anim.play(shiftAnim);
+ }
+
+ // TODO: Link this animation to state animation, so that it is cancelled
+ // automatically on state change
+ anim.setDuration(transitionLength * 2);
+ return AnimatorPlaybackController.wrap(anim, transitionLength * 2);
+ }
+
+ @Override
+ public ActivityInitListener createActivityInitListener(
+ BiPredicate<Launcher, Boolean> onInitListener) {
+ return new LauncherInitListener(onInitListener);
+ }
+
+ @Override
+ public void startRecents(Context context, Intent intent,
+ AssistDataReceiver assistDataReceiver,
+ RecentsAnimationListener remoteAnimationListener) {
+ ActivityManagerWrapper.getInstance().startRecentsActivity(
+ intent, assistDataReceiver, remoteAnimationListener, null, null);
+ }
+ }
+
+ class FallbackActivityControllerHelper implements ActivityControlHelper<RecentsActivity> {
+
+ @Override
+ public void onQuickstepGestureStarted(RecentsActivity activity, boolean activityVisible) {
+ // TODO:
+ }
+
+ @Override
+ public void onQuickInteractionStart(RecentsActivity activity, boolean activityVisible) {
+ // TODO:
+ }
+
+ @Override
+ public void executeOnNextDraw(RecentsActivity activity, TaskView targetView,
+ Runnable action) {
+ // TODO:
+ new Handler(Looper.getMainLooper()).post(action);
+ }
+
+ @Override
+ public void onTransitionCancelled(RecentsActivity activity, boolean activityVisible) {
+ // TODO:
+ }
+
+ @Override
+ public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
+ FallbackRecentsView.getCenterPageRect(dp, context, outRect);
+ if (dp.isVerticalBarLayout()) {
+ Rect targetInsets = dp.getInsets();
+ int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
+ return dp.hotseatBarSizePx + dp.hotseatBarSidePaddingPx + hotseatInset;
+ } else {
+ return dp.heightPx - outRect.bottom;
+ }
+ }
+
+ @Override
+ public void onSwipeUpComplete(RecentsActivity activity) {
+ // TODO:
+ }
+
+ @Override
+ public void prepareRecentsUI(RecentsActivity activity, boolean activityVisible) {
+ // TODO:
+ }
+
+ @Override
+ public AnimatorPlaybackController createControllerForVisibleActivity(
+ RecentsActivity activity) {
+ DeviceProfile dp = activity.getDeviceProfile();
+ return createControllerForHiddenActivity(activity, Math.max(dp.widthPx, dp.heightPx));
+ }
+
+ @Override
+ public AnimatorPlaybackController createControllerForHiddenActivity(
+ RecentsActivity activity, int transitionLength) {
+ // We do not animate anything. Create a empty controller
+ AnimatorSet anim = new AnimatorSet();
+ return AnimatorPlaybackController.wrap(anim, transitionLength * 2);
+ }
+
+ @Override
+ public LayoutListener createLayoutListener(RecentsActivity activity) {
+ // We do not change anything as part of layout changes in fallback activity. Return a
+ // default layout listener.
+ return new LayoutListener() {
+ @Override
+ public void open() { }
+
+ @Override
+ public void setHandler(WindowTransformSwipeHandler handler) { }
+
+ @Override
+ public void finish() { }
+ };
+ }
+
+ @Override
+ public ActivityInitListener createActivityInitListener(
+ BiPredicate<RecentsActivity, Boolean> onInitListener) {
+ return new RecentsActivityTracker(onInitListener);
+ }
+
+ @Override
+ public void startRecents(Context context, Intent intent,
+ AssistDataReceiver assistDataReceiver,
+ final RecentsAnimationListener remoteAnimationListener) {
+ ActivityOptions options =
+ ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
+ new FallbackActivityOptions(remoteAnimationListener), 10000, 10000));
+ context.startActivity(intent, options.toBundle());
+ }
+ }
+
+ interface LayoutListener {
+
+ void open();
+
+ void setHandler(WindowTransformSwipeHandler handler);
+
+ void finish();
+ }
+
+ interface ActivityInitListener {
+
+ void register();
+
+ void unregister();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java
index 214b3f3..84dfa45 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java
@@ -77,6 +77,12 @@
}
}
+ public void finishAnimation() {
+ if (mValueAnimator != null && mValueAnimator.isRunning()) {
+ mValueAnimator.end();
+ }
+ }
+
public ObjectAnimator getCurrentAnimation() {
return mValueAnimator;
}
diff --git a/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
deleted file mode 100644
index b3ebd77..0000000
--- a/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import android.support.annotation.WorkerThread;
-
-import com.android.launcher3.states.InternalStateHandler;
-import com.android.quickstep.TouchConsumer.InteractionType;
-
-public abstract class BaseSwipeInteractionHandler extends InternalStateHandler {
-
- protected Runnable mGestureEndCallback;
-
- public void setGestureEndCallback(Runnable gestureEndCallback) {
- mGestureEndCallback = gestureEndCallback;
- }
-
- public void reset() {}
-
- @WorkerThread
- public abstract void onGestureStarted();
-
- @WorkerThread
- public abstract void onGestureEnded(float endVelocity);
-
- public abstract void updateInteractionType(@InteractionType int interactionType);
-
- @WorkerThread
- public abstract void onQuickScrubEnd();
-
- @WorkerThread
- public abstract void onQuickScrubProgress(float progress);
-
- @WorkerThread
- public abstract void updateDisplacement(float displacement);
-}
diff --git a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
new file mode 100644
index 0000000..b92678a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.view.Choreographer;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+
+/**
+ * A TouchConsumer which defers all events on the UIThread until the consumer is created.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class DeferredTouchConsumer implements TouchConsumer {
+
+ private final VelocityTracker mVelocityTracker;
+ private final DeferredTouchProvider mTouchProvider;
+
+ private MotionEventQueue mMyQueue;
+ private TouchConsumer mTarget;
+
+ public DeferredTouchConsumer(DeferredTouchProvider touchProvider) {
+ mVelocityTracker = VelocityTracker.obtain();
+ mTouchProvider = touchProvider;
+ }
+
+ @Override
+ public void accept(MotionEvent event) {
+ mTarget.accept(event);
+ }
+
+ @Override
+ public void reset() {
+ mTarget.reset();
+ }
+
+ @Override
+ public void updateTouchTracking(int interactionType) {
+ mTarget.updateTouchTracking(interactionType);
+ }
+
+ @Override
+ public void onQuickScrubEnd() {
+ mTarget.onQuickScrubEnd();
+ }
+
+ @Override
+ public void onQuickScrubProgress(float progress) {
+ mTarget.onQuickScrubProgress(progress);
+ }
+
+ @Override
+ public void preProcessMotionEvent(MotionEvent ev) {
+ mVelocityTracker.addMovement(ev);
+ }
+
+ @Override
+ public Choreographer getIntrimChoreographer(MotionEventQueue queue) {
+ mMyQueue = queue;
+ return null;
+ }
+
+ @Override
+ public void deferInit() {
+ mTarget = mTouchProvider.createTouchConsumer(mVelocityTracker);
+ mTarget.getIntrimChoreographer(mMyQueue);
+ }
+
+ @Override
+ public boolean forceToLauncherConsumer() {
+ return mTarget.forceToLauncherConsumer();
+ }
+
+ @Override
+ public boolean deferNextEventToMainThread() {
+ // If our target is still null, defer the next target as well
+ TouchConsumer target = mTarget;
+ return target == null ? true : target.deferNextEventToMainThread();
+ }
+
+ public interface DeferredTouchProvider {
+
+ TouchConsumer createTouchConsumer(VelocityTracker tracker);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityOptions.java b/quickstep/src/com/android/quickstep/FallbackActivityOptions.java
new file mode 100644
index 0000000..3a7fb2d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/FallbackActivityOptions.java
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+import android.graphics.Rect;
+import android.util.Log;
+
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.systemui.shared.system.RecentsAnimationListener;
+import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.WindowManagerWrapper;
+
+/**
+ * Temporary class to create activity options to emulate recents transition for fallback activtiy.
+ */
+public class FallbackActivityOptions implements RemoteAnimationRunnerCompat {
+
+ private final RecentsAnimationListener mListener;
+
+ public FallbackActivityOptions(RecentsAnimationListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats,
+ Runnable runnable) {
+ DummyRecentsAnimationControllerCompat dummyRecentsAnim =
+ new DummyRecentsAnimationControllerCompat(runnable);
+
+ Rect insets = new Rect();
+ WindowManagerWrapper.getInstance().getStableInsets(insets);
+ mListener.onAnimationStart(dummyRecentsAnim, targetCompats, insets, null);
+ }
+
+ @Override
+ public void onAnimationCancelled() {
+ mListener.onAnimationCanceled();
+ }
+
+ private static class DummyRecentsAnimationControllerCompat
+ extends RecentsAnimationControllerCompat {
+
+ final Runnable mFinishCallback;
+
+ public DummyRecentsAnimationControllerCompat(Runnable finishCallback) {
+ mFinishCallback = finishCallback;
+ }
+
+ @Override
+ public ThumbnailData screenshotTask(int taskId) {
+ return new ThumbnailData();
+ }
+
+ @Override
+ public void setInputConsumerEnabled(boolean enabled) { }
+
+ @Override
+ public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) { }
+
+ @Override
+ public void finish(boolean toHome) {
+ if (toHome) {
+ mFinishCallback.run();
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/FallbackRecentsView.java
new file mode 100644
index 0000000..032d753
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/FallbackRecentsView.java
@@ -0,0 +1,68 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
+import com.android.quickstep.views.RecentsView;
+
+public class FallbackRecentsView extends RecentsView<RecentsActivity> implements Insettable {
+
+ public FallbackRecentsView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setOverviewStateEnabled(true);
+ }
+
+ @Override
+ protected void onAllTasksRemoved() {
+ mActivity.finish();
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ mInsets.set(insets);
+ DeviceProfile dp = mActivity.getDeviceProfile();
+ Rect padding = getPadding(dp, getContext());
+ verticalCenter(padding, dp);
+ setPadding(padding.left, padding.top, padding.right, padding.bottom);
+ }
+
+ private static void verticalCenter(Rect padding, DeviceProfile dp) {
+ Rect insets = dp.getInsets();
+ int totalSpace = (padding.top + padding.bottom - insets.top - insets.bottom) / 2;
+ padding.top = insets.top + totalSpace;
+ padding.bottom = insets.bottom + totalSpace;
+ }
+
+ public static void getCenterPageRect(DeviceProfile grid, Context context, Rect outRect) {
+ Rect targetPadding = getPadding(grid, context);
+ verticalCenter(targetPadding, grid);
+ Rect insets = grid.getInsets();
+ outRect.set(
+ targetPadding.left + insets.left,
+ targetPadding.top + insets.top,
+ grid.widthPx - targetPadding.right - insets.right,
+ grid.heightPx - targetPadding.bottom - insets.bottom);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
new file mode 100644
index 0000000..12757c0
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.InstantAppInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.util.InstantAppResolver;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of InstantAppResolver using platform APIs
+ */
+@SuppressWarnings("unused")
+public class InstantAppResolverImpl extends InstantAppResolver {
+
+ private static final String TAG = "InstantAppResolverImpl";
+ public static final String COMPONENT_CLASS_MARKER = "@instantapp";
+
+ private final PackageManager mPM;
+
+ public InstantAppResolverImpl(Context context)
+ throws NoSuchMethodException, ClassNotFoundException {
+ mPM = context.getPackageManager();
+ }
+
+ @Override
+ public boolean isInstantApp(ApplicationInfo info) {
+ return info.isInstantApp();
+ }
+
+ @Override
+ public boolean isInstantApp(AppInfo info) {
+ ComponentName cn = info.getTargetComponent();
+ return cn != null && cn.getClassName().equals(COMPONENT_CLASS_MARKER);
+ }
+
+ @Override
+ public List<ApplicationInfo> getInstantApps() {
+ try {
+ List<ApplicationInfo> result = new ArrayList<>();
+ for (InstantAppInfo iai : mPM.getInstantApps()) {
+ ApplicationInfo info = iai.getApplicationInfo();
+ if (info != null) {
+ result.add(info);
+ }
+ }
+ return result;
+ } catch (SecurityException se) {
+ Log.w(TAG, "getInstantApps failed. Launcher may not be the default home app.", se);
+ } catch (Exception e) {
+ Log.e(TAG, "Error calling API: getInstantApps", e);
+ }
+ return super.getInstantApps();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherSearchIndexablesProvider.java b/quickstep/src/com/android/quickstep/LauncherSearchIndexablesProvider.java
new file mode 100644
index 0000000..f5e1f6e
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/LauncherSearchIndexablesProvider.java
@@ -0,0 +1,96 @@
+/*
+ * 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;
+
+import android.annotation.TargetApi;
+import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ResolveInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.os.Build;
+import android.provider.SearchIndexablesContract.XmlResource;
+import android.provider.SearchIndexablesProvider;
+import android.util.Xml;
+
+import com.android.launcher3.R;
+import com.android.launcher3.graphics.IconShapeOverride;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
+import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS;
+import static android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS;
+
+@TargetApi(Build.VERSION_CODES.O)
+public class LauncherSearchIndexablesProvider extends SearchIndexablesProvider {
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor queryXmlResources(String[] strings) {
+ MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);
+ ResolveInfo settingsActivity = getContext().getPackageManager().resolveActivity(
+ new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
+ .setPackage(getContext().getPackageName()), 0);
+ cursor.newRow()
+ .add(XmlResource.COLUMN_XML_RESID, R.xml.indexable_launcher_prefs)
+ .add(XmlResource.COLUMN_INTENT_ACTION, Intent.ACTION_APPLICATION_PREFERENCES)
+ .add(XmlResource.COLUMN_INTENT_TARGET_PACKAGE, getContext().getPackageName())
+ .add(XmlResource.COLUMN_INTENT_TARGET_CLASS, settingsActivity.activityInfo.name);
+ return cursor;
+ }
+
+ @Override
+ public Cursor queryRawData(String[] projection) {
+ return new MatrixCursor(INDEXABLES_RAW_COLUMNS);
+ }
+
+ @Override
+ public Cursor queryNonIndexableKeys(String[] projection) {
+ MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS);
+ if (!getContext().getSystemService(LauncherApps.class).hasShortcutHostPermission()) {
+ // We are not the current launcher. Hide all preferences
+ try (XmlResourceParser parser = getContext().getResources()
+ .getXml(R.xml.indexable_launcher_prefs)) {
+ final int depth = parser.getDepth();
+ final int[] attrs = new int[] { android.R.attr.key };
+ int type;
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+ if (type == XmlPullParser.START_TAG) {
+ TypedArray a = getContext().obtainStyledAttributes(
+ Xml.asAttributeSet(parser), attrs);
+ cursor.addRow(new String[] {a.getString(0)});
+ a.recycle();
+ }
+ }
+ } catch (IOException |XmlPullParserException e) {
+ throw new RuntimeException(e);
+ }
+ } else if (!IconShapeOverride.isSupported(getContext())) {
+ cursor.addRow(new String[] {IconShapeOverride.KEY_PREFERENCE});
+ }
+ return cursor;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java
index 6e92d83..94b6faa 100644
--- a/quickstep/src/com/android/quickstep/MotionEventQueue.java
+++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java
@@ -53,6 +53,8 @@
ACTION_VIRTUAL | (4 << ACTION_POINTER_INDEX_SHIFT);
private static final int ACTION_RESET =
ACTION_VIRTUAL | (5 << ACTION_POINTER_INDEX_SHIFT);
+ private static final int ACTION_DEFER_INIT =
+ ACTION_VIRTUAL | (6 << ACTION_POINTER_INDEX_SHIFT);
private final EventArray mEmptyArray = new EventArray();
private final Object mExecutionLock = new Object();
@@ -76,10 +78,10 @@
public MotionEventQueue(Choreographer choreographer, TouchConsumer consumer) {
mMainChoreographer = choreographer;
mConsumer = consumer;
-
mCurrentChoreographer = mMainChoreographer;
mCurrentRunnable = mMainFrameCallback;
- setInterimChoreographerLocked(consumer.getIntrimChoreographer(this));
+
+ setInterimChoreographer(consumer.getIntrimChoreographer(this));
}
public void setInterimChoreographer(Choreographer choreographer) {
@@ -156,6 +158,9 @@
case ACTION_RESET:
mConsumer.reset();
break;
+ case ACTION_DEFER_INIT:
+ mConsumer.deferInit();
+ break;
default:
Log.e(TAG, "Invalid virtual event: " + event.getAction());
}
@@ -204,6 +209,14 @@
queueVirtualAction(ACTION_RESET, 0);
}
+ public void deferInit() {
+ queueVirtualAction(ACTION_DEFER_INIT, 0);
+ }
+
+ public TouchConsumer getConsumer() {
+ return mConsumer;
+ }
+
private static class EventArray extends ArrayList<MotionEvent> {
public int lastEventAction = ACTION_CANCEL;
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
deleted file mode 100644
index ff7d434..0000000
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * 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 static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
-import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
-import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SWITCH;
-import static com.android.quickstep.TouchConsumer.isInteractionQuick;
-
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.animation.RectEvaluator;
-import android.annotation.TargetApi;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.os.Build;
-import android.support.annotation.UiThread;
-import android.view.View;
-import android.view.ViewTreeObserver.OnPreDrawListener;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Hotseat;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.Launcher.OnResumeCallback;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
-import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.TraceHelper;
-import com.android.quickstep.TouchConsumer.InteractionType;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.WindowManagerWrapper;
-
-@TargetApi(Build.VERSION_CODES.O)
-public class NavBarSwipeInteractionHandler extends BaseSwipeInteractionHandler implements
- OnResumeCallback {
-
- private static final int STATE_LAUNCHER_READY = 1 << 0;
- private static final int STATE_ACTIVITY_MULTIPLIER_COMPLETE = 1 << 4;
- private static final int STATE_SCALED_SNAPSHOT_RECENTS = 1 << 5;
- private static final int STATE_SCALED_SNAPSHOT_APP = 1 << 6;
-
- private static final long MAX_SWIPE_DURATION = 200;
- private static final long MIN_SWIPE_DURATION = 80;
-
- // Ideal velocity for a smooth transition
- private static final float PIXEL_PER_MS = 2f;
-
- private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
-
- private final Rect mStableInsets = new Rect();
- private final Rect mSourceRect = new Rect();
- private final Rect mTargetRect = new Rect();
- private final Rect mCurrentRect = new Rect();
- private final RectEvaluator mRectEvaluator = new RectEvaluator(mCurrentRect);
-
- // Shift in the range of [0, 1].
- // 0 => preview snapShot is completely visible, and hotseat is completely translated down
- // 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
- // visible.
- private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
-
- // Activity multiplier in the range of [0, 1]. When the activity becomes visible, this is
- // animated to 1, so allow for a smooth transition.
- private final AnimatedFloat mActivityMultiplier = new AnimatedFloat(this::updateFinalShift);
-
- private final int mRunningTaskId;
- private final Context mContext;
-
- private final MultiStateCallback mStateCallback;
-
- private Launcher mLauncher;
- private SnapshotDragView mDragView;
- private RecentsView mRecentsView;
- private QuickScrubController mQuickScrubController;
- private Hotseat mHotseat;
-
- private boolean mWasLauncherAlreadyVisible;
-
- private boolean mLauncherReady;
- private boolean mTouchEndHandled;
- private float mCurrentDisplacement;
-
- private @InteractionType int mInteractionType;
- private boolean mStartedQuickScrubFromHome;
-
- private Bitmap mTaskSnapshot;
-
- NavBarSwipeInteractionHandler(RunningTaskInfo runningTaskInfo, Context context,
- @InteractionType int interactionType) {
- mContext = context;
- mInteractionType = interactionType;
- mRunningTaskId = runningTaskInfo.id;
- WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
-
- DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
- // TODO: If in multi window mode, dp = dp.getMultiWindowProfile()
- dp = dp.copy(mContext);
- // TODO: Use different insets for multi-window mode
- dp.updateInsets(mStableInsets);
- RecentsView.getPageRect(dp, mContext, mTargetRect);
- mSourceRect.set(0, 0, dp.widthPx - mStableInsets.left - mStableInsets.right,
- dp.heightPx - mStableInsets.top - mStableInsets.bottom);
-
- // Build the state callback
- mStateCallback = new MultiStateCallback();
- mStateCallback.addCallback(STATE_LAUNCHER_READY, this::onLauncherReady);
- mStateCallback.addCallback(STATE_SCALED_SNAPSHOT_APP, this::resumeLastTask);
- mStateCallback.addCallback(
- STATE_SCALED_SNAPSHOT_RECENTS | STATE_ACTIVITY_MULTIPLIER_COMPLETE,
- this::onAnimationToLauncherComplete);
- mStateCallback.addCallback(STATE_LAUNCHER_READY | STATE_SCALED_SNAPSHOT_APP,
- this::cleanupLauncher);
- }
-
- private void onLauncherReady() {
- mLauncherReady = true;
- executeFrameUpdate();
-
- long duration = Math.min(MAX_SWIPE_DURATION,
- Math.max((long) (-mCurrentDisplacement / PIXEL_PER_MS), MIN_SWIPE_DURATION));
- if (mCurrentShift.getCurrentAnimation() != null) {
- ObjectAnimator anim = mCurrentShift.getCurrentAnimation();
- long theirDuration = anim.getDuration() - anim.getCurrentPlayTime();
-
- // TODO: Find a better heuristic
- duration = (duration + theirDuration) / 2;
- }
- ObjectAnimator anim = mActivityMultiplier.animateToValue(1)
- .setDuration(duration);
- anim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE);
- }
- });
- anim.start();
- }
-
- public void setTaskSnapshot(Bitmap taskSnapshot) {
- mTaskSnapshot = taskSnapshot;
- }
-
- @Override
- public void onLauncherResume() {
- TraceHelper.partitionSection("TouchInt", "Launcher On resume");
- mDragView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- mDragView.getViewTreeObserver().removeOnPreDrawListener(this);
- mStateCallback.setState(STATE_LAUNCHER_READY);
- TraceHelper.partitionSection("TouchInt", "Launcher drawn");
- return true;
- }
- });
- }
-
- @Override
- protected boolean init(Launcher launcher, boolean alreadyOnHome) {
- launcher.setOnResumeCallback(this);
- mLauncher = launcher;
- mRecentsView = launcher.getOverviewPanel();
- mRecentsView.showTask(mRunningTaskId);
- mHotseat = mLauncher.getHotseat();
- mWasLauncherAlreadyVisible = alreadyOnHome;
-
- AbstractFloatingView.closeAllOpenViews(mLauncher, alreadyOnHome);
- mLauncher.getStateManager().goToState(LauncherState.OVERVIEW, alreadyOnHome);
-
- mDragView = new SnapshotDragView(mLauncher, mTaskSnapshot);
- mLauncher.getDragLayer().addView(mDragView);
- mDragView.setPivotX(0);
- mDragView.setPivotY(0);
-
- if (isInteractionQuick(mInteractionType)) {
- updateUiForQuickScrub();
- }
-
- // Optimization
- if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- // All-apps search box is visible in vertical bar layout.
- mLauncher.getAppsView().setVisibility(View.GONE);
- }
- TraceHelper.partitionSection("TouchInt", "Launcher on new intent");
- return false;
- }
-
- public void updateInteractionType(@InteractionType int interactionType) {
- Preconditions.assertUIThread();
- if (mInteractionType != INTERACTION_NORMAL) {
- throw new IllegalArgumentException(
- "Can't change interaction type from " + mInteractionType);
- }
- if (!isInteractionQuick(interactionType)) {
- throw new IllegalArgumentException(
- "Can't change interaction type to " + interactionType);
- }
- mInteractionType = interactionType;
-
- if (mLauncher != null) {
- updateUiForQuickScrub();
- }
- }
-
- private void updateUiForQuickScrub() {
- mStartedQuickScrubFromHome = mWasLauncherAlreadyVisible;
- mQuickScrubController = mRecentsView.getQuickScrubController();
- mQuickScrubController.onQuickScrubStart(mStartedQuickScrubFromHome);
- animateToProgress(1f, MAX_SWIPE_DURATION);
- if (mStartedQuickScrubFromHome) {
- mDragView.setVisibility(View.INVISIBLE);
- }
- }
-
- @UiThread
- public void updateDisplacement(float displacement) {
- mCurrentDisplacement = displacement;
- executeFrameUpdate();
- }
-
- private void executeFrameUpdate() {
- if (mLauncherReady) {
- final float displacement = -mCurrentDisplacement;
- int hotseatSize = getHotseatSize();
- float translation = Utilities.boundToRange(displacement, 0, hotseatSize);
- float shift = hotseatSize == 0 ? 0 : translation / hotseatSize;
- mCurrentShift.updateValue(shift);
- }
- }
-
- @UiThread
- private void updateFinalShift() {
- if (!mLauncherReady || mStartedQuickScrubFromHome) {
- return;
- }
-
- float shift = mCurrentShift.value * mActivityMultiplier.value;
-
- AllAppsTransitionController controller = mLauncher.getAllAppsController();
- float range = getHotseatSize() / controller.getShiftRange();
- controller.setProgress(1 + (1 - shift) * range);
-
- mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
-
- float scale = (float) mCurrentRect.width() / mSourceRect.width();
- mDragView.setTranslationX(mCurrentRect.left - mStableInsets.left * scale * shift);
- mDragView.setTranslationY(mCurrentRect.top - mStableInsets.top * scale * shift);
- mDragView.setScaleX(scale);
- mDragView.setScaleY(scale);
- // TODO: mDragView.getViewBounds().setClipLeft((int) (mStableInsets.left * shift));
- mDragView.getViewBounds().setClipTop((int) (mStableInsets.top * shift));
- // TODO: mDragView.getViewBounds().setClipRight((int) (mStableInsets.right * shift));
- mDragView.getViewBounds().setClipBottom((int) (mStableInsets.bottom * shift));
- }
-
- private int getHotseatSize() {
- return mLauncher.getDeviceProfile().isVerticalBarLayout()
- ? mHotseat.getWidth() : mHotseat.getHeight();
- }
-
- @Override
- public void onGestureStarted() { }
-
- @UiThread
- public void onGestureEnded(float endVelocity) {
- if (mTouchEndHandled) {
- return;
- }
- mTouchEndHandled = true;
-
- Resources res = mContext.getResources();
- float flingThreshold = res.getDimension(R.dimen.quickstep_fling_threshold_velocity);
- boolean isFling = Math.abs(endVelocity) > flingThreshold;
-
- long duration = MAX_SWIPE_DURATION;
- final float endShift;
- if (!isFling) {
- endShift = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW ? 1 : 0;
- } else {
- endShift = endVelocity < 0 ? 1 : 0;
- float minFlingVelocity = res.getDimension(R.dimen.quickstep_fling_min_velocity);
- if (Math.abs(endVelocity) > minFlingVelocity && mLauncherReady) {
- float distanceToTravel = (endShift - mCurrentShift.value) * getHotseatSize();
-
- // we want the page's snap velocity to approximately match the velocity at
- // which the user flings, so we scale the duration by a value near to the
- // derivative of the scroll interpolator at zero, ie. 5.
- duration = 5 * Math.round(1000 * Math.abs(distanceToTravel / endVelocity));
- }
- }
-
- animateToProgress(endShift, duration);
- }
-
- /** Animates to the given progress, where 0 is the current app and 1 is overview. */
- private void animateToProgress(float progress, long duration) {
- ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
- anim.setInterpolator(Interpolators.SCROLL);
- anim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- mStateCallback.setState((Float.compare(mCurrentShift.value, 0) == 0)
- ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS);
- }
- });
- anim.start();
- }
-
- @UiThread
- private void resumeLastTask() {
- RecentsTaskLoadPlan loadPlan = RecentsModel.getInstance(mContext).getLastLoadPlan();
- if (loadPlan != null) {
- Task task = loadPlan.getTaskStack().findTaskWithId(mRunningTaskId);
- if (task != null) {
- ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
- ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(task.key, opts,
- null, null);
- }
- }
- }
-
- public void reset() {
- mCurrentShift.cancelAnimation();
- if (mGestureEndCallback != null) {
- mGestureEndCallback.run();
- }
- }
-
- private void cleanupLauncher() {
- reset();
-
- // TODO: These should be done as part of ActivityOptions#OnAnimationStarted
- mLauncher.getStateManager().reapplyState();
- mLauncher.setOnResumeCallback(() -> mDragView.close(false));
- }
-
- private void onAnimationToLauncherComplete() {
- reset();
-
- mDragView.close(false);
- View currentRecentsPage = mRecentsView.getPageAt(mRecentsView.getCurrentPage());
- if (currentRecentsPage instanceof TaskView) {
- ((TaskView) currentRecentsPage).animateIconToScale(1f);
- }
- if (mInteractionType == INTERACTION_QUICK_SWITCH) {
- if (mQuickScrubController != null) {
- mQuickScrubController.onQuickSwitch();
- }
- }
- }
-
- public void onQuickScrubEnd() {
- if (mQuickScrubController != null) {
- mQuickScrubController.onQuickScrubEnd();
- } else {
- // TODO:
- }
- }
-
- public void onQuickScrubProgress(float progress) {
- if (mQuickScrubController != null) {
- mQuickScrubController.onQuickScrubProgress(progress);
- } else {
- // TODO:
- }
- }
-}
diff --git a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
index 431fb30..f875bb7 100644
--- a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
+++ b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
@@ -16,19 +16,20 @@
package com.android.quickstep;
import android.annotation.TargetApi;
+import android.app.ActivityManager.TaskDescription;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Build;
-import android.os.Build.VERSION_CODES;
import android.os.UserHandle;
import android.util.LruCache;
import android.util.SparseArray;
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.graphics.BitmapInfo;
+import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.systemui.shared.recents.model.IconLoader;
import com.android.systemui.shared.recents.model.TaskKeyLruCache;
@@ -40,11 +41,13 @@
public class NormalizedIconLoader extends IconLoader {
private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>();
+ private final DrawableFactory mDrawableFactory;
private LauncherIcons mLauncherIcons;
public NormalizedIconLoader(Context context, TaskKeyLruCache<Drawable> iconCache,
LruCache<ComponentName, ActivityInfo> activityInfoCache) {
super(context, iconCache, activityInfoCache);
+ mDrawableFactory = DrawableFactory.get(context);
}
@Override
@@ -53,7 +56,7 @@
BitmapInfo info = mDefaultIcons.get(userId);
if (info == null) {
info = getBitmapInfo(Resources.getSystem()
- .getDrawable(android.R.drawable.sym_def_app_icon), userId);
+ .getDrawable(android.R.drawable.sym_def_app_icon), userId, 0, false);
mDefaultIcons.put(userId, info);
}
@@ -62,23 +65,31 @@
}
@Override
- protected Drawable createBadgedDrawable(Drawable drawable, int userId) {
- return new FastBitmapDrawable(getBitmapInfo(drawable, userId));
+ protected Drawable createBadgedDrawable(Drawable drawable, int userId, TaskDescription desc) {
+ return new FastBitmapDrawable(getBitmapInfo(drawable, userId, desc.getPrimaryColor(),
+ false));
}
- private synchronized BitmapInfo getBitmapInfo(Drawable drawable, int userId) {
+ private synchronized BitmapInfo getBitmapInfo(Drawable drawable, int userId,
+ int primaryColor, boolean isInstantApp) {
if (mLauncherIcons == null) {
mLauncherIcons = LauncherIcons.obtain(mContext);
}
+ mLauncherIcons.setWrapperBackgroundColor(primaryColor);
// User version code O, so that the icon is always wrapped in an adaptive icon container.
return mLauncherIcons.createBadgedIconBitmap(drawable, UserHandle.of(userId),
- Build.VERSION_CODES.O);
+ Build.VERSION_CODES.O, isInstantApp);
}
@Override
- protected Drawable getBadgedActivityIcon(ActivityInfo activityInfo, int userId) {
- return createBadgedDrawable(
- activityInfo.loadUnbadgedIcon(mContext.getPackageManager()), userId);
+ protected Drawable getBadgedActivityIcon(ActivityInfo activityInfo, int userId,
+ TaskDescription desc) {
+ BitmapInfo bitmapInfo = getBitmapInfo(
+ activityInfo.loadUnbadgedIcon(mContext.getPackageManager()),
+ userId,
+ desc.getPrimaryColor(),
+ activityInfo.applicationInfo.isInstantApp());
+ return mDrawableFactory.newIcon(bitmapInfo, activityInfo);
}
}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 73cd503..ab19c6e 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -22,21 +22,17 @@
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
-import static com.android.quickstep.RemoteRunnable.executeSafely;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
-import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
+import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityOptions;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Color;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
@@ -49,9 +45,7 @@
import android.view.WindowManager;
import com.android.launcher3.MainThreadExecutor;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.TraceHelper;
-import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.AssistDataReceiver;
import com.android.systemui.shared.system.BackgroundExecutor;
@@ -61,51 +55,55 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Touch consumer for handling events originating from an activity other than Launcher
*/
+@TargetApi(Build.VERSION_CODES.P)
public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer {
- private static final String TAG = "ActivityTouchConsumer";
private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150;
+ private static final int[] DEFERRED_HIT_TARGETS = false
+ ? new int[] {HIT_TARGET_BACK, HIT_TARGET_OVERVIEW} : new int[] {HIT_TARGET_BACK};
private final RunningTaskInfo mRunningTask;
private final RecentsModel mRecentsModel;
private final Intent mHomeIntent;
- private final ISystemUiProxy mISystemUiProxy;
+ private final ActivityControlHelper mActivityControlHelper;
private final MainThreadExecutor mMainThreadExecutor;
private final Choreographer mBackgroundThreadChoreographer;
+ private final boolean mIsDeferredDownTarget;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private int mActivePointerId = INVALID_POINTER_ID;
private boolean mTouchThresholdCrossed;
private int mTouchSlop;
private float mStartDisplacement;
- private BaseSwipeInteractionHandler mInteractionHandler;
+ private WindowTransformSwipeHandler mInteractionHandler;
private int mDisplayRotation;
private Rect mStableInsets = new Rect();
- private @HitTarget int mDownHitTarget = HIT_TARGET_NONE;
private VelocityTracker mVelocityTracker;
private MotionEventQueue mEventQueue;
+ private boolean mIsGoingToHome;
public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo,
- RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy,
+ RecentsModel recentsModel, Intent homeIntent, ActivityControlHelper activityControl,
MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer,
- @HitTarget int downHitTarget) {
+ @HitTarget int downHitTarget, VelocityTracker velocityTracker) {
super(base);
mRunningTask = runningTaskInfo;
mRecentsModel = recentsModel;
mHomeIntent = homeIntent;
- mVelocityTracker = VelocityTracker.obtain();
- mISystemUiProxy = systemUiProxy;
+ mVelocityTracker = velocityTracker;
+ mActivityControlHelper = activityControl;
mMainThreadExecutor = mainThreadExecutor;
mBackgroundThreadChoreographer = backgroundThreadChoreographer;
- mDownHitTarget = downHitTarget;
+ mIsDeferredDownTarget = Arrays.binarySearch(DEFERRED_HIT_TARGETS, downHitTarget) >= 0;
}
@Override
@@ -124,7 +122,7 @@
// Start the window animation on down to give more time for launcher to draw if the
// user didn't start the gesture over the back button
- if (!isUsingScreenShot() && mDownHitTarget != HIT_TARGET_BACK) {
+ if (!mIsDeferredDownTarget) {
startTouchTrackingForWindowAnimation(ev.getEventTime());
}
@@ -164,14 +162,11 @@
if (mTouchThresholdCrossed) {
mStartDisplacement = Math.signum(displacement) * mTouchSlop;
- if (isUsingScreenShot()) {
- startTouchTrackingForScreenshotAnimation();
- } else if (mDownHitTarget == HIT_TARGET_BACK) {
+ if (mIsDeferredDownTarget) {
// If we deferred starting the window animation on touch down, then
// start tracking now
startTouchTrackingForWindowAnimation(ev.getEventTime());
}
-
notifyGestureStarted();
}
} else if (mInteractionHandler != null) {
@@ -197,11 +192,6 @@
}
// Notify the handler that the gesture has actually started
mInteractionHandler.onGestureStarted();
-
- // Notify the system that we have started tracking the event
- if (mISystemUiProxy != null) {
- executeSafely(mISystemUiProxy::onRecentsAnimationStarted);
- }
}
private boolean isNavBarOnRight() {
@@ -212,69 +202,10 @@
return mDisplayRotation == Surface.ROTATION_270 && mStableInsets.left > 0;
}
- private boolean isUsingScreenShot() {
- return Utilities.getPrefs(this).getBoolean("pref_use_screenshot_for_swipe_up", false);
- }
-
- /**
- * Called when the gesture has started.
- */
- private void startTouchTrackingForScreenshotAnimation() {
- // Create the shared handler
- final NavBarSwipeInteractionHandler handler =
- new NavBarSwipeInteractionHandler(mRunningTask, this, INTERACTION_NORMAL);
-
- TraceHelper.partitionSection("TouchInt", "Thershold crossed ");
-
- // Start the recents activity on a background thread
- BackgroundExecutor.get().submit(() -> {
- // Get the snap shot before
- handler.setTaskSnapshot(getCurrentTaskSnapshot());
-
- // Start the launcher activity with our custom handler
- Intent homeIntent = handler.addToIntent(new Intent(mHomeIntent));
- startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, 0).toBundle());
- TraceHelper.partitionSection("TouchInt", "Home started");
- });
-
- // Preload the plan
- mRecentsModel.loadTasks(mRunningTask.id, null);
- mInteractionHandler = handler;
- mInteractionHandler.setGestureEndCallback(mEventQueue::reset);
- }
-
- private Bitmap getCurrentTaskSnapshot() {
- TraceHelper.beginSection("TaskSnapshot");
- // TODO: We are using some hardcoded layers for now, to best approximate the activity layers
- Point displaySize = new Point();
- Display display = getSystemService(WindowManager.class).getDefaultDisplay();
- display.getRealSize(displaySize);
- int rotation = display.getRotation();
- // The rotation is backwards in landscape, so flip it.
- if (rotation == Surface.ROTATION_270) {
- rotation = Surface.ROTATION_90;
- } else if (rotation == Surface.ROTATION_90) {
- rotation = Surface.ROTATION_270;
- }
- try {
- return mISystemUiProxy.screenshot(new Rect(), displaySize.x, displaySize.y, 0, 100000,
- false, rotation).toBitmap();
- } catch (Exception e) {
- Log.e(TAG, "Error capturing snapshot", e);
-
- // Return a dummy bitmap
- Bitmap bitmap = Bitmap.createBitmap(displaySize.x, displaySize.y, Config.RGB_565);
- bitmap.eraseColor(Color.WHITE);
- return bitmap;
- } finally {
- TraceHelper.endSection("TaskSnapshot");
- }
- }
-
private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
// Create the shared handler
- final WindowTransformSwipeHandler handler =
- new WindowTransformSwipeHandler(mRunningTask, this, touchTimeMs);
+ final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler(
+ mRunningTask, this, touchTimeMs, mActivityControlHelper);
// Preload the plan
mRecentsModel.loadTasks(mRunningTask.id, null);
@@ -291,8 +222,7 @@
handler.initWhenReady();
TraceHelper.beginSection("RecentsController");
- Runnable startActivity = () -> ActivityManagerWrapper.getInstance()
- .startRecentsActivity(mHomeIntent,
+ Runnable startActivity = () -> mActivityControlHelper.startRecents(this, mHomeIntent,
new AssistDataReceiver() {
@Override
public void onHandleAssistData(Bundle bundle) {
@@ -321,7 +251,7 @@
handler.onRecentsAnimationCanceled();
}
}
- }, null, null);
+ });
if (Looper.myLooper() != Looper.getMainLooper()) {
startActivity.run();
@@ -350,7 +280,7 @@
: isNavBarOnLeft() ? -mVelocityTracker.getXVelocity(mActivePointerId)
: mVelocityTracker.getYVelocity(mActivePointerId);
mInteractionHandler.onGestureEnded(velocity);
- } else if (!isUsingScreenShot()) {
+ } else {
// Since we start touch tracking on DOWN, we may reach this state without actually
// starting the gesture. In that case, just cleanup immediately.
reset();
@@ -367,8 +297,9 @@
public void reset() {
// Clean up the old interaction handler
if (mInteractionHandler != null) {
- final BaseSwipeInteractionHandler handler = mInteractionHandler;
+ final WindowTransformSwipeHandler handler = mInteractionHandler;
mInteractionHandler = null;
+ mIsGoingToHome = handler.mIsGoingToHome;
mMainThreadExecutor.execute(handler::reset);
}
}
@@ -376,24 +307,15 @@
@Override
public void updateTouchTracking(int interactionType) {
notifyGestureStarted();
-
- if (isUsingScreenShot()) {
- mMainThreadExecutor.execute(() -> {
- if (mInteractionHandler != null) {
- mInteractionHandler.updateInteractionType(interactionType);
- }
- });
- } else {
- if (mInteractionHandler != null) {
- mInteractionHandler.updateInteractionType(interactionType);
- }
+ if (mInteractionHandler != null) {
+ mInteractionHandler.updateInteractionType(interactionType);
}
}
@Override
public Choreographer getIntrimChoreographer(MotionEventQueue queue) {
mEventQueue = queue;
- return isUsingScreenShot() ? null : mBackgroundThreadChoreographer;
+ return mBackgroundThreadChoreographer;
}
@Override
@@ -423,4 +345,15 @@
}
}
}
+
+ @Override
+ public boolean forceToLauncherConsumer() {
+ return mIsGoingToHome;
+ }
+
+ @Override
+ public boolean deferNextEventToMainThread() {
+ // TODO: Consider also check if the eventQueue is using mainThread of not.
+ return mInteractionHandler != null;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
new file mode 100644
index 0000000..38c25a3
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -0,0 +1,170 @@
+/*
+ * 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;
+
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.annotation.TargetApi;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.os.Build;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.states.InternalStateHandler;
+import com.android.quickstep.ActivityControlHelper.FallbackActivityControllerHelper;
+import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHelper;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+/**
+ * Helper class to handle various atomic commands for switching between Overview.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class OverviewCommandHelper extends InternalStateHandler {
+
+ private static final boolean DEBUG_START_FALLBACK_ACTIVITY = false;
+
+ private final Context mContext;
+ private final ActivityManagerWrapper mAM;
+
+ public final Intent homeIntent;
+ public final ComponentName launcher;
+
+ private long mLastToggleTime;
+
+ public OverviewCommandHelper(Context context) {
+ mContext = context;
+ mAM = ActivityManagerWrapper.getInstance();
+
+ homeIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setPackage(context.getPackageName())
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ ResolveInfo info = context.getPackageManager().resolveActivity(homeIntent, 0);
+
+ if (DEBUG_START_FALLBACK_ACTIVITY) {
+ launcher = new ComponentName(context, RecentsActivity.class);
+ homeIntent.addCategory(Intent.CATEGORY_DEFAULT)
+ .removeCategory(Intent.CATEGORY_HOME);
+ } else {
+ launcher = new ComponentName(context.getPackageName(), info.activityInfo.name);
+ }
+
+ // Clear the packageName as system can fail to dedupe it b/64108432
+ homeIntent.setComponent(launcher).setPackage(null);
+ }
+
+ private void openRecents() {
+ Intent intent = addToIntent(new Intent(homeIntent));
+ mContext.startActivity(intent);
+ initWhenReady();
+ }
+
+ public void onOverviewToggle() {
+ getLauncher().runOnUiThread(() -> {
+ if (isUsingFallbackActivity()) {
+ mContext.startActivity(new Intent(mContext, RecentsActivity.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent
+ .FLAG_ACTIVITY_CLEAR_TASK));
+ return;
+ }
+
+ long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
+ mLastToggleTime = SystemClock.elapsedRealtime();
+
+ if (isOverviewAlmostVisible()) {
+ boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout();
+ startNonLauncherTask(isQuickTap ? 2 : 1);
+ } else {
+ openRecents();
+ }
+ }
+ );
+ }
+
+ public void onOverviewShown() {
+ getLauncher().runOnUiThread(() -> {
+ if (isOverviewAlmostVisible()) {
+ final RecentsView rv = getLauncher().getOverviewPanel();
+ rv.snapToTaskAfterNext();
+ } else {
+ openRecents();
+ }
+ }
+ );
+ }
+
+ public void onOverviewHidden() {
+ getLauncher().runOnUiThread(() -> {
+ final RecentsView rv = getLauncher().getOverviewPanel();
+ rv.launchNextTask();
+ }
+ );
+ }
+
+ private void startNonLauncherTask(int backStackCount) {
+ for (RecentTaskInfo rti : mAM.getRecentTasks(backStackCount, UserHandle.myUserId())) {
+ backStackCount--;
+ if (backStackCount == 0) {
+ mAM.startActivityFromRecents(rti.id, null);
+ break;
+ }
+ }
+ }
+
+ private boolean isOverviewAlmostVisible() {
+ if (clearReference()) {
+ return true;
+ }
+ if (!mAM.getRunningTask().topActivity.equals(launcher)) {
+ return false;
+ }
+ Launcher launcher = getLauncher();
+ return launcher != null && launcher.isStarted() && launcher.isInState(OVERVIEW);
+ }
+
+ private Launcher getLauncher() {
+ return (Launcher) LauncherAppState.getInstance(mContext).getModel().getCallback();
+ }
+
+ @Override
+ protected boolean init(Launcher launcher, boolean alreadyOnHome) {
+ AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
+ launcher.getStateManager().goToState(OVERVIEW, alreadyOnHome);
+ clearReference();
+ return false;
+ }
+
+ public boolean isUsingFallbackActivity() {
+ return DEBUG_START_FALLBACK_ACTIVITY;
+ }
+
+ public ActivityControlHelper getActivityControlHelper() {
+ if (DEBUG_START_FALLBACK_ACTIVITY) {
+ return new FallbackActivityControllerHelper();
+ } else {
+ return new LauncherActivityControllerHelper();
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 3c68281..522a883 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -15,18 +15,28 @@
*/
package com.android.quickstep;
+import static com.android.launcher3.Utilities.getPrefs;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.support.annotation.WorkerThread;
import android.util.Log;
+import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.util.UiThreadHelper;
import com.android.systemui.shared.recents.ISystemUiProxy;
+import java.util.concurrent.ExecutionException;
+
/**
* Sets overview interaction flags, such as:
*
@@ -37,55 +47,109 @@
*
* @see com.android.systemui.shared.system.NavigationBarCompat.InteractionType and associated flags.
*/
-public class OverviewInteractionState {
+public class OverviewInteractionState implements OnSharedPreferenceChangeListener {
private static final String TAG = "OverviewFlags";
- private static final Handler sUiHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- updateOverviewInteractionFlag((Context) msg.obj, msg.what, msg.arg1 == 1);
- }
- };
- private static final Handler sBackgroundHandler = new Handler(
- UiThreadHelper.getBackgroundLooper()) {
- @Override
- public void handleMessage(Message msg) {
- ISystemUiProxy systemUiProxy = (ISystemUiProxy) msg.obj;
- int flags = msg.what;
- try {
- systemUiProxy.setInteractionState(flags);
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to update overview interaction flags", e);
+
+ // We do not need any synchronization for this variable as its only written on UI thread.
+ private static OverviewInteractionState INSTANCE;
+
+ public static OverviewInteractionState getInstance(final Context context) {
+ if (INSTANCE == null) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ INSTANCE = new OverviewInteractionState(context.getApplicationContext());
+ } else {
+ try {
+ return new MainThreadExecutor().submit(
+ () -> OverviewInteractionState.getInstance(context)).get();
+ } catch (InterruptedException|ExecutionException e) {
+ throw new RuntimeException(e);
+ }
}
}
- };
-
- private static int sFlags;
-
- public static void setBackButtonVisible(Context context, boolean visible) {
- updateFlagOnUi(context, FLAG_HIDE_BACK_BUTTON, !visible);
+ return INSTANCE;
}
- private static void updateFlagOnUi(Context context, int flag, boolean enabled) {
- sUiHandler.removeMessages(flag);
- sUiHandler.sendMessage(sUiHandler.obtainMessage(flag, enabled ? 1 : 0, 0, context));
+ private static final String KEY_SWIPE_UP_ENABLED = "pref_enable_quickstep";
+
+ private static final int MSG_SET_PROXY = 200;
+ private static final int MSG_SET_BACK_BUTTON_VISIBLE = 201;
+ private static final int MSG_SET_SWIPE_UP_ENABLED = 202;
+
+ private final Handler mUiHandler;
+ private final Handler mBgHandler;
+
+ // These are updated on the background thread
+ private ISystemUiProxy mISystemUiProxy;
+ private boolean mBackButtonVisible = true;
+ private boolean mSwipeUpEnabled = true;
+
+ private OverviewInteractionState(Context context) {
+ mUiHandler = new Handler(this::handleUiMessage);
+ mBgHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleBgMessage);
+
+ SharedPreferences prefs = getPrefs(context);
+ prefs.registerOnSharedPreferenceChangeListener(this);
+ onSharedPreferenceChanged(prefs, KEY_SWIPE_UP_ENABLED);
}
- private static void updateOverviewInteractionFlag(Context context, int flag, boolean enabled) {
- if (enabled) {
- sFlags |= flag;
- } else {
- sFlags &= ~flag;
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences prefs, String s) {
+ if (KEY_SWIPE_UP_ENABLED.equals(s)) {
+ mUiHandler.removeMessages(MSG_SET_SWIPE_UP_ENABLED);
+ boolean swipeUpEnabled = prefs.getBoolean(s, true);
+ mUiHandler.obtainMessage(MSG_SET_SWIPE_UP_ENABLED,
+ swipeUpEnabled ? 1 : 0, 0).sendToTarget();
}
+ }
- ISystemUiProxy systemUiProxy = RecentsModel.getInstance(context).getSystemUiProxy();
- if (systemUiProxy == null) {
- Log.w(TAG, "Unable to update overview interaction flags; not bound to service");
+ public void setBackButtonVisible(boolean visible) {
+ mUiHandler.removeMessages(MSG_SET_BACK_BUTTON_VISIBLE);
+ mUiHandler.obtainMessage(MSG_SET_BACK_BUTTON_VISIBLE, visible ? 1 : 0, 0)
+ .sendToTarget();
+ }
+
+ public void setSystemUiProxy(ISystemUiProxy proxy) {
+ mBgHandler.obtainMessage(MSG_SET_PROXY, proxy).sendToTarget();
+ }
+
+ private boolean handleUiMessage(Message msg) {
+ mBgHandler.obtainMessage(msg.what, msg.arg1, msg.arg2).sendToTarget();
+ return true;
+ }
+
+ private boolean handleBgMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_PROXY:
+ mISystemUiProxy = (ISystemUiProxy) msg.obj;
+ break;
+ case MSG_SET_BACK_BUTTON_VISIBLE:
+ mBackButtonVisible = msg.arg1 != 0;
+ break;
+ case MSG_SET_SWIPE_UP_ENABLED:
+ mSwipeUpEnabled = msg.arg1 != 0;
+ break;
+ }
+ applyFlags();
+ return true;
+ }
+
+ @WorkerThread
+ private void applyFlags() {
+ if (mISystemUiProxy == null) {
return;
}
- // If we aren't already setting these flags, do so now on the background thread.
- if (!sBackgroundHandler.hasMessages(sFlags)) {
- sBackgroundHandler.sendMessage(sBackgroundHandler.obtainMessage(sFlags, systemUiProxy));
+
+ int flags;
+ if (mSwipeUpEnabled) {
+ flags = mBackButtonVisible ? 0 : FLAG_HIDE_BACK_BUTTON;
+ } else {
+ flags = FLAG_DISABLE_SWIPE_UP | FLAG_DISABLE_QUICK_SCRUB | FLAG_SHOW_OVERVIEW_BUTTON;
+ }
+ try {
+ mISystemUiProxy.setInteractionState(flags);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to update overview interaction flags", e);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/PendingAnimation.java b/quickstep/src/com/android/quickstep/PendingAnimation.java
new file mode 100644
index 0000000..d22ef61
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/PendingAnimation.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import android.animation.AnimatorSet;
+import android.annotation.TargetApi;
+import android.os.Build;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+/**
+ * Utility class to keep track of a running animation.
+ *
+ * This class allows attaching end callbacks to an animation is intended to be used with
+ * {@link com.android.launcher3.anim.AnimatorPlaybackController}, since in that case
+ * AnimationListeners are not properly dispatched.
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public class PendingAnimation {
+
+ private final ArrayList<Consumer<Boolean>> mEndListeners = new ArrayList<>();
+
+ public final AnimatorSet anim;
+
+ public PendingAnimation(AnimatorSet anim) {
+ this.anim = anim;
+ }
+
+ public void finish(boolean isSuccess) {
+ for (Consumer<Boolean> listeners : mEndListeners) {
+ listeners.accept(isSuccess);
+ }
+ mEndListeners.clear();
+ }
+
+ public void addEndListener(Consumer<Boolean> listener) {
+ mEndListeners.add(listener);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index f28d51c..d263fbf 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -19,13 +19,14 @@
import android.view.HapticFeedbackConstants;
import com.android.launcher3.Alarm;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.BaseActivity;
import com.android.launcher3.OnAlarmListener;
import com.android.launcher3.Utilities;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
/**
* Responds to quick scrub callbacks to page through and launch recent tasks.
@@ -35,8 +36,7 @@
*/
public class QuickScrubController implements OnAlarmListener {
- public static final int QUICK_SWITCH_START_DURATION = 133;
- public static final int QUICK_SWITCH_SNAP_DURATION = 120;
+ public static final int QUICK_SWITCH_START_DURATION = 210;
private static final boolean ENABLE_AUTO_ADVANCE = true;
private static final int NUM_QUICK_SCRUB_SECTIONS = 3;
@@ -47,15 +47,17 @@
private final Alarm mAutoAdvanceAlarm;
private final RecentsView mRecentsView;
- private final Launcher mLauncher;
+ private final BaseActivity mActivity;
private boolean mInQuickScrub;
private int mQuickScrubSection;
- private int mStartPage;
+ private boolean mStartedFromHome;
private boolean mHasAlarmRun;
+ private boolean mQuickSwitched;
+ private boolean mFinishedTransitionToQuickScrub;
- public QuickScrubController(Launcher launcher, RecentsView recentsView) {
- mLauncher = launcher;
+ public QuickScrubController(BaseActivity activity, RecentsView recentsView) {
+ mActivity = activity;
mRecentsView = recentsView;
if (ENABLE_AUTO_ADVANCE) {
mAutoAdvanceAlarm = new Alarm();
@@ -65,10 +67,14 @@
public void onQuickScrubStart(boolean startingFromHome) {
mInQuickScrub = true;
- mStartPage = startingFromHome ? 0 : mRecentsView.getFirstTaskIndex();
+ mStartedFromHome = startingFromHome;
mQuickScrubSection = 0;
mHasAlarmRun = false;
- mLauncher.getUserEventDispatcher().resetActionDurationMillis();
+ mQuickSwitched = false;
+ mFinishedTransitionToQuickScrub = false;
+
+ snapToNextTaskIfAvailable();
+ mActivity.getUserEventDispatcher().resetActionDurationMillis();
}
public void onQuickScrubEnd() {
@@ -78,10 +84,9 @@
}
int page = mRecentsView.getNextPage();
Runnable launchTaskRunnable = () -> {
- if (page < mRecentsView.getFirstTaskIndex()) {
- mRecentsView.getPageAt(page).performClick();
- } else {
- ((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
+ TaskView taskView = ((TaskView) mRecentsView.getPageAt(page));
+ if (taskView != null) {
+ taskView.launchTask(true);
}
};
int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
@@ -93,8 +98,8 @@
// No page move needed, just launch it
launchTaskRunnable.run();
}
- mLauncher.getUserEventDispatcher().logActionOnControl(Touch.DRAGDROP,
- ControlType.QUICK_SCRUB_BUTTON, null, mStartPage == 0 ?
+ mActivity.getUserEventDispatcher().logActionOnControl(Touch.DRAGDROP,
+ ControlType.QUICK_SCRUB_BUTTON, null, mStartedFromHome ?
ContainerType.WORKSPACE : ContainerType.APP);
}
@@ -102,7 +107,9 @@
int quickScrubSection = Math.round(progress * NUM_QUICK_SCRUB_SECTIONS);
if (quickScrubSection != mQuickScrubSection) {
int pageToGoTo = mRecentsView.getNextPage() + quickScrubSection - mQuickScrubSection;
- goToPageWithHaptic(pageToGoTo);
+ if (mFinishedTransitionToQuickScrub) {
+ goToPageWithHaptic(pageToGoTo);
+ }
if (ENABLE_AUTO_ADVANCE) {
if (quickScrubSection == NUM_QUICK_SCRUB_SECTIONS || quickScrubSection == 0) {
mAutoAdvanceAlarm.setAlarm(mHasAlarmRun
@@ -116,36 +123,45 @@
}
public void onQuickSwitch() {
- for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
- TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
- if (taskView.getTask().key.id != mRecentsView.getRunningTaskId()) {
- Runnable launchTaskRunnable = () -> taskView.launchTask(true);
- if (mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION)) {
- // Snap to the new page then launch it
- mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable);
- } else {
- // No need to move page, just launch task directly
- launchTaskRunnable.run();
- }
- break;
- }
- }
- mLauncher.getUserEventDispatcher().logActionOnControl(Touch.FLING,
- ControlType.QUICK_SCRUB_BUTTON, null, mStartPage == 0 ?
- ContainerType.WORKSPACE : ContainerType.APP);
+ mQuickSwitched = true;
+ quickSwitchIfReady();
}
- public void snapToPageForCurrentQuickScrubSection() {
- if (mInQuickScrub) {
- goToPageWithHaptic(mRecentsView.getFirstTaskIndex() + mQuickScrubSection);
+ public void onFinishedTransitionToQuickScrub() {
+ mFinishedTransitionToQuickScrub = true;
+ quickSwitchIfReady();
+ }
+
+ /**
+ * Immediately launches the current task (which we snapped to in onQuickScrubStart) if we've
+ * gotten the onQuickSwitch callback and the transition to quick scrub has completed.
+ */
+ private void quickSwitchIfReady() {
+ if (mQuickSwitched && mFinishedTransitionToQuickScrub) {
+ onQuickScrubEnd();
+ mActivity.getUserEventDispatcher().logActionOnControl(Touch.FLING,
+ ControlType.QUICK_SCRUB_BUTTON, null, mStartedFromHome ?
+ ContainerType.WORKSPACE : ContainerType.APP);
+ }
+ }
+
+ public void snapToNextTaskIfAvailable() {
+ if (mInQuickScrub && mRecentsView.getChildCount() > 0) {
+ int toPage = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1;
+ goToPageWithHaptic(toPage, QUICK_SWITCH_START_DURATION);
}
}
private void goToPageWithHaptic(int pageToGoTo) {
- pageToGoTo = Utilities.boundToRange(pageToGoTo, mStartPage, mRecentsView.getPageCount() - 1);
+ goToPageWithHaptic(pageToGoTo, -1);
+ }
+
+ private void goToPageWithHaptic(int pageToGoTo, int overrideDuration) {
+ pageToGoTo = Utilities.boundToRange(pageToGoTo, 0, mRecentsView.getPageCount() - 1);
if (pageToGoTo != mRecentsView.getNextPage()) {
- int duration = Math.abs(pageToGoTo - mRecentsView.getNextPage())
- * QUICKSCRUB_SNAP_DURATION_PER_PAGE;
+ int duration = overrideDuration > -1 ? overrideDuration
+ : Math.abs(pageToGoTo - mRecentsView.getNextPage())
+ * QUICKSCRUB_SNAP_DURATION_PER_PAGE;
mRecentsView.snapToPage(pageToGoTo, duration);
mRecentsView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
@@ -158,7 +174,7 @@
if (mQuickScrubSection == NUM_QUICK_SCRUB_SECTIONS
&& currPage < mRecentsView.getPageCount() - 1) {
goToPageWithHaptic(currPage + 1);
- } else if (mQuickScrubSection == 0 && currPage > mStartPage) {
+ } else if (mQuickScrubSection == 0 && currPage > 0) {
goToPageWithHaptic(currPage - 1);
}
mHasAlarmRun = true;
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index f92d773..12e1a2b 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -15,34 +15,82 @@
*/
package com.android.quickstep;
-import android.app.ListActivity;
+import android.app.ActivityOptions;
import android.os.Bundle;
-import android.os.UserHandle;
-import android.support.annotation.Nullable;
-import android.widget.ArrayAdapter;
+import android.view.View;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions;
-import com.android.systemui.shared.recents.model.RecentsTaskLoader;
-import com.android.systemui.shared.recents.model.Task;
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
+import com.android.launcher3.badge.BadgeInfo;
+import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.views.BaseDragLayer;
/**
* A simple activity to show the recently launched tasks
*/
-public class RecentsActivity extends ListActivity {
+public class RecentsActivity extends BaseDraggingActivity {
- private ArrayAdapter<Task> mAdapter;
+ private RecentsRootView mRecentsRootView;
+ private FallbackRecentsView mFallbackRecentsView;
@Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
+ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(this);
- plan.preloadPlan(new PreloadOptions(), new RecentsTaskLoader(this, 1, 1, 0), -1,
- UserHandle.myUserId());
+ // In case we are reusing IDP, create a copy so that we dont conflict with Launcher
+ // activity.
+ LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
+ setDeviceProfile(appState != null
+ ? appState.getInvariantDeviceProfile().getDeviceProfile(this).copy(this)
+ : new InvariantDeviceProfile(this).getDeviceProfile(this));
- mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
- mAdapter.addAll(plan.getTaskStack().getTasks());
- setListAdapter(mAdapter);
+ setContentView(R.layout.fallback_recents_activity);
+ mRecentsRootView = findViewById(R.id.drag_layer);
+ mFallbackRecentsView = findViewById(R.id.overview_panel);
+
+ RecentsActivityTracker.onRecentsActivityCreate(this);
+ }
+
+ @Override
+ public BaseDragLayer getDragLayer() {
+ return mRecentsRootView;
+ }
+
+ @Override
+ public View getRootView() {
+ return mRecentsRootView;
+ }
+
+ @Override
+ public <T extends View> T getOverviewPanel() {
+ return (T) mFallbackRecentsView;
+ }
+
+ @Override
+ public BadgeInfo getBadgeInfoForItem(ItemInfo info) {
+ return null;
+ }
+
+ @Override
+ public ActivityOptions getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
+ return null;
+ }
+
+ @Override
+ public void invalidateParent(ItemInfo info) { }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ UiFactory.onStart(this);
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ super.onTrimMemory(level);
+ UiFactory.onTrimMemory(this, level);
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java
new file mode 100644
index 0000000..6a82dc0
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+
+import java.lang.ref.WeakReference;
+import java.util.function.BiPredicate;
+
+/**
+ * Utility class to track create/destroy for RecentsActivity
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class RecentsActivityTracker implements ActivityInitListener {
+
+ private static final Object LOCK = new Object();
+ private static WeakReference<RecentsActivityTracker> sTracker = new WeakReference<>(null);
+
+ private final BiPredicate<RecentsActivity, Boolean> mOnInitListener;
+
+ public RecentsActivityTracker(BiPredicate<RecentsActivity, Boolean> onInitListener) {
+ mOnInitListener = onInitListener;
+ }
+
+ @Override
+ public void register() {
+ synchronized (LOCK) {
+ sTracker = new WeakReference<>(this);
+ }
+ }
+
+ @Override
+ public void unregister() {
+ synchronized (LOCK) {
+ if (sTracker.get() == this) {
+ sTracker.clear();
+ }
+ }
+ }
+
+ public static void onRecentsActivityCreate(RecentsActivity activity) {
+ synchronized (LOCK) {
+ RecentsActivityTracker tracker = sTracker.get();
+ if (tracker != null && tracker.mOnInitListener.test(activity, false)) {
+ sTracker.clear();
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 3e3b3b2..392b73f 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -31,7 +31,6 @@
import android.util.LruCache;
import android.util.SparseArray;
-import com.android.launcher3.Launcher;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.util.Preconditions;
@@ -211,13 +210,13 @@
public void onStart() {
mRecentsTaskLoader.startLoader(mContext);
-// mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(true);
+ mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(true);
}
public void onTrimMemory(int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// We already stop the loader in UI_HIDDEN, so stop the high res loader as well
-// mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(false);
+ mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(false);
}
mRecentsTaskLoader.onTrimMemory(level);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsRootView.java b/quickstep/src/com/android/quickstep/RecentsRootView.java
new file mode 100644
index 0000000..24785f9
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentsRootView.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.BaseDragLayer;
+
+public class RecentsRootView extends BaseDragLayer<RecentsActivity> {
+
+ private final BaseActivity mActivity;
+
+ public RecentsRootView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mActivity = BaseActivity.fromContext(context);
+ mControllers = new TouchController[0];
+ }
+
+ @TargetApi(23)
+ @Override
+ protected boolean fitSystemWindows(Rect insets) {
+ // Update device profile before notifying the children.
+ mActivity.getDeviceProfile().updateInsets(insets);
+ setInsets(insets);
+ return true; // I'll take it from here
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ // If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by
+ // modifying child layout params.
+ if (!insets.equals(mInsets)) {
+ super.setInsets(insets);
+ }
+ setBackground(insets.top == 0 ? null
+ : Themes.getAttrDrawable(getContext(), R.attr.workspaceStatusBarScrim));
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
deleted file mode 100644
index 9ae41eb..0000000
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ /dev/null
@@ -1,664 +0,0 @@
-/*
- * 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 static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.quickstep.TaskView.CURVE_FACTOR;
-import static com.android.quickstep.TaskView.CURVE_INTERPOLATOR;
-
-import android.animation.LayoutTransition;
-import android.animation.LayoutTransition.TransitionListener;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.Shader;
-import android.graphics.Shader.TileMode;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.SparseBooleanArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.PagedView;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.uioverrides.OverviewState;
-import com.android.launcher3.uioverrides.RecentsViewStateController;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.RecentsTaskLoader;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.WindowManagerWrapper;
-
-import java.util.ArrayList;
-
-/**
- * A list of recent tasks.
- */
-public class RecentsView extends PagedView implements Insettable, OnSharedPreferenceChangeListener {
-
- private static final Rect sTempStableInsets = new Rect();
-
- public static final int SCROLL_TYPE_NONE = 0;
- public static final int SCROLL_TYPE_TASK = 1;
- public static final int SCROLL_TYPE_WORKSPACE = 2;
-
- private static final String PREF_FLIP_RECENTS = "pref_flip_recents";
-
- private final Launcher mLauncher;
- private QuickScrubController mQuickScrubController;
- private final ScrollState mScrollState = new ScrollState();
- private boolean mOverviewStateEnabled;
- private boolean mTaskStackListenerRegistered;
- private LayoutTransition mLayoutTransition;
- private Runnable mNextPageSwitchRunnable;
-
- private float mFastFlingVelocity;
-
- /**
- * TODO: Call reloadIdNeeded in onTaskStackChanged.
- */
- private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
- @Override
- public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
- for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
- final TaskView taskView = (TaskView) getChildAt(i);
- if (taskView.getTask().key.id == taskId) {
- taskView.getThumbnail().setThumbnail(taskView.getTask(), snapshot);
- return;
- }
- }
- }
- };
-
- private RecentsViewStateController mStateController;
- private int mFirstTaskIndex;
-
- private final RecentsModel mModel;
- private int mLoadPlanId = -1;
-
- // Only valid until the launcher state changes to NORMAL
- private int mRunningTaskId = -1;
-
- private Bitmap mScrim;
- private Paint mFadePaint;
- private Shader mFadeShader;
- private Matrix mFadeMatrix;
- private boolean mScrimOnLeft;
-
- private boolean mFirstTaskIconScaledDown = false;
- private SparseBooleanArray mPrevVisibleTasks = new SparseBooleanArray();
-
- public RecentsView(Context context) {
- this(context, null);
- }
-
- public RecentsView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
- enableFreeScroll(true);
- setupLayoutTransition();
- setClipToOutline(true);
-
- mLauncher = Launcher.getLauncher(context);
- mQuickScrubController = new QuickScrubController(mLauncher, this);
- mModel = RecentsModel.getInstance(context);
-
- onSharedPreferenceChanged(Utilities.getPrefs(context), PREF_FLIP_RECENTS);
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
- if (s.equals(PREF_FLIP_RECENTS)) {
- mIsRtl = Utilities.isRtl(getResources());
- if (sharedPreferences.getBoolean(PREF_FLIP_RECENTS, false)) {
- mIsRtl = !mIsRtl;
- }
- setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
- mScrollState.isRtl = mIsRtl;
- }
- }
-
- public boolean isRtl() {
- return mIsRtl;
- }
-
- public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData) {
- for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
- final TaskView taskView = (TaskView) getChildAt(i);
- if (taskView.getTask().key.id == taskId) {
- taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
- taskView.setAlpha(1);
- return taskView;
- }
- }
- return null;
- }
-
- private void setupLayoutTransition() {
- // We want to show layout transitions when pages are deleted, to close the gap.
- // TODO: We should this manually so we can control the animation (fill in the gap as the
- // dismissing task is being tracked, and also so we can update the visible task data during
- // the transition. For now, the workaround is to expand the visible tasks to load.
- mLayoutTransition = new LayoutTransition();
- mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);
- mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
-
- mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);
- mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
- mLayoutTransition.addTransitionListener(new TransitionListener() {
- @Override
- public void startTransition(LayoutTransition layoutTransition, ViewGroup viewGroup,
- View view, int i) {
- loadVisibleTaskData();
- }
-
- @Override
- public void endTransition(LayoutTransition layoutTransition, ViewGroup viewGroup,
- View view, int i) {
- loadVisibleTaskData();
- }
- });
- setLayoutTransition(mLayoutTransition);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- Resources res = getResources();
- mFirstTaskIndex = getPageCount();
- mFastFlingVelocity = res.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
- }
-
- @Override
- protected void onWindowVisibilityChanged(int visibility) {
- super.onWindowVisibilityChanged(visibility);
- updateTaskStackListenerState();
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- updateTaskStackListenerState();
- Utilities.getPrefs(getContext()).registerOnSharedPreferenceChangeListener(this);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- updateTaskStackListenerState();
- Utilities.getPrefs(getContext()).unregisterOnSharedPreferenceChangeListener(this);
- }
-
- @Override
- public void setInsets(Rect insets) {
- mInsets.set(insets);
- DeviceProfile dp = Launcher.getLauncher(getContext()).getDeviceProfile();
- Rect padding = getPadding(dp, getContext());
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
- lp.bottomMargin = padding.bottom;
- setLayoutParams(lp);
-
- setPadding(padding.left, padding.top, padding.right, 0);
-
- if (dp.isVerticalBarLayout()) {
- boolean wasScrimOnLeft = mScrimOnLeft;
- mScrimOnLeft = dp.isSeascape();
-
- if (mScrim == null || wasScrimOnLeft != mScrimOnLeft) {
- Drawable scrim = getContext().getDrawable(mScrimOnLeft
- ? R.drawable.recents_horizontal_scrim_left
- : R.drawable.recents_horizontal_scrim_right);
- if (scrim instanceof BitmapDrawable) {
- mScrim = ((BitmapDrawable) scrim).getBitmap();
- mFadePaint = new Paint();
- mFadePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
- mFadeShader = new BitmapShader(mScrim, TileMode.CLAMP, TileMode.REPEAT);
- mFadeMatrix = new Matrix();
- } else {
- mScrim = null;
- }
- }
- } else {
- mScrim = null;
- mFadePaint = null;
- mFadeShader = null;
- mFadeMatrix = null;
- }
- }
-
- public int getFirstTaskIndex() {
- return mFirstTaskIndex;
- }
-
- public boolean isTaskViewVisible(TaskView tv) {
- // For now, just check if it's the active task or an adjacent task
- return Math.abs(indexOfChild(tv) - getNextPage()) <= 1;
- }
-
- public TaskView getTaskView(int taskId) {
- for (int i = getFirstTaskIndex(); i < getChildCount(); i++) {
- TaskView tv = (TaskView) getChildAt(i);
- if (tv.getTask().key.id == taskId) {
- return tv;
- }
- }
- return null;
- }
-
- public void setStateController(RecentsViewStateController stateController) {
- mStateController = stateController;
- }
-
- public RecentsViewStateController getStateController() {
- return mStateController;
- }
-
- public void setOverviewStateEnabled(boolean enabled) {
- mOverviewStateEnabled = enabled;
- updateTaskStackListenerState();
- }
-
- public void setNextPageSwitchRunnable(Runnable r) {
- mNextPageSwitchRunnable = r;
- }
-
- @Override
- protected void onPageEndTransition() {
- super.onPageEndTransition();
- if (mNextPageSwitchRunnable != null) {
- mNextPageSwitchRunnable.run();
- mNextPageSwitchRunnable = null;
- }
- }
-
- private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) {
- final RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
- TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null;
- if (stack == null) {
- removeAllViews();
- return;
- }
-
- int oldChildCount = getChildCount();
-
- // Ensure there are as many views as there are tasks in the stack (adding and trimming as
- // necessary)
- final LayoutInflater inflater = LayoutInflater.from(getContext());
- final ArrayList<Task> tasks = new ArrayList<>(stack.getTasks());
- setLayoutTransition(null);
-
- final int requiredChildCount = tasks.size() + mFirstTaskIndex;
- for (int i = getChildCount(); i < requiredChildCount; i++) {
- final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false);
- addView(taskView);
- }
- while (getChildCount() > requiredChildCount) {
- final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1);
- final Task task = taskView.getTask();
- removeView(taskView);
- loader.unloadTaskData(task);
-// loader.getHighResThumbnailLoader().onTaskInvisible(task);
- }
- setLayoutTransition(mLayoutTransition);
-
- // Rebind and reset all task views
- for (int i = tasks.size() - 1; i >= 0; i--) {
- final int pageIndex = tasks.size() - i - 1 + mFirstTaskIndex;
- final Task task = tasks.get(i);
- final TaskView taskView = (TaskView) getChildAt(pageIndex);
- taskView.bind(task);
- taskView.resetVisualProperties();
- }
- updateCurveProperties();
- // Reload the set of visible task's data
- mPrevVisibleTasks.clear();
- loadVisibleTaskData();
- applyIconScale(false /* animate */);
-
- if (oldChildCount != getChildCount()) {
- mQuickScrubController.snapToPageForCurrentQuickScrubSection();
- }
- }
-
- private void updateTaskStackListenerState() {
- boolean registerStackListener = mOverviewStateEnabled && isAttachedToWindow()
- && getWindowVisibility() == VISIBLE;
- if (registerStackListener != mTaskStackListenerRegistered) {
- if (registerStackListener) {
- ActivityManagerWrapper.getInstance()
- .registerTaskStackListener(mTaskStackListener);
- reloadIfNeeded();
- } else {
- ActivityManagerWrapper.getInstance()
- .unregisterTaskStackListener(mTaskStackListener);
- }
- mTaskStackListenerRegistered = registerStackListener;
- }
- }
-
- private static Rect getPadding(DeviceProfile profile, Context context) {
- WindowManagerWrapper.getInstance().getStableInsets(sTempStableInsets);
- Rect padding = new Rect(profile.workspacePadding);
-
- float taskWidth = profile.widthPx - sTempStableInsets.left - sTempStableInsets.right;
- float taskHeight = profile.heightPx - sTempStableInsets.top - sTempStableInsets.bottom;
-
- float overviewHeight, overviewWidth;
- if (profile.isVerticalBarLayout()) {
- float scrimLength = context.getResources()
- .getDimension(R.dimen.recents_page_fade_length);
- float maxPadding = Math.max(padding.left, padding.right);
-
- // Use the same padding on both sides for symmetry.
- float availableWidth = taskWidth - 2 * Math.max(maxPadding, scrimLength);
- float availableHeight = profile.availableHeightPx - padding.top - padding.bottom
- - sTempStableInsets.top;
- float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
- overviewHeight = taskHeight * scaledRatio;
- overviewWidth = taskWidth * scaledRatio;
-
- } else {
- overviewHeight = profile.availableHeightPx - padding.top - padding.bottom
- - sTempStableInsets.top;
- overviewWidth = taskWidth * overviewHeight / taskHeight;
- }
-
- padding.bottom = profile.availableHeightPx - padding.top - sTempStableInsets.top
- - Math.round(overviewHeight);
- padding.left = padding.right = (int) ((profile.availableWidthPx - overviewWidth) / 2);
- return padding;
- }
-
- /**
- * Sets the {@param outRect} to match the position of the first tile such that it is scaled
- * down to match the 2nd taskView.
- * @return returns the factor which determines the scaling factor for the second task.
- */
- public static float getScaledDownPageRect(DeviceProfile dp, Context context, Rect outRect) {
- getPageRect(dp, context, outRect);
-
- int pageSpacing = context.getResources()
- .getDimensionPixelSize(R.dimen.recents_page_spacing);
- float halfScreenWidth = dp.widthPx * 0.5f;
- float halfPageWidth = outRect.width() * 0.5f;
- float pageCenter = outRect.right + pageSpacing + halfPageWidth;
- float distanceFromCenter = Math.abs(halfScreenWidth - pageCenter);
- float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
- float linearInterpolation = Math.min(1, distanceFromCenter / distanceToReachEdge);
-
- float scale = 1 - CURVE_INTERPOLATOR.getInterpolation(linearInterpolation) * CURVE_FACTOR;
-
- int topMargin = context.getResources()
- .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
- outRect.top -= topMargin;
- Utilities.scaleRectAboutCenter(outRect, scale);
- outRect.top += (int) (scale * topMargin);
- return linearInterpolation;
- }
-
- public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) {
- Rect targetPadding = getPadding(grid, context);
- Rect insets = grid.getInsets();
- outRect.set(
- targetPadding.left + insets.left,
- targetPadding.top + insets.top,
- grid.widthPx - targetPadding.right - insets.right,
- grid.heightPx - targetPadding.bottom - insets.bottom);
- outRect.top += context.getResources()
- .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
- }
-
- @Override
- protected boolean computeScrollHelper() {
- boolean scrolling = super.computeScrollHelper();
- boolean isFlingingFast = false;
- updateCurveProperties();
- if (scrolling || (mTouchState == TOUCH_STATE_SCROLLING)) {
- if (scrolling) {
- // Check if we are flinging quickly to disable high res thumbnail loading
- isFlingingFast = mScroller.getCurrVelocity() > mFastFlingVelocity;
- }
-
- // After scrolling, update the visible task's data
- loadVisibleTaskData();
- }
-
- // Update the high res thumbnail loader
- RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
-// loader.getHighResThumbnailLoader().setFlingingFast(isFlingingFast);
- return scrolling;
- }
-
- /**
- * Scales and adjusts translation of adjacent pages as if on a curved carousel.
- */
- public void updateCurveProperties() {
- if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
- return;
- }
- final int halfPageWidth = mScrollState.halfPageWidth = getNormalChildWidth() / 2;
- mScrollState.lastScrollType = SCROLL_TYPE_NONE;
- final int screenCenter = mInsets.left + getPaddingLeft() + getScrollX() + halfPageWidth;
- final int halfScreenWidth = getMeasuredWidth() / 2;
- final int pageSpacing = mPageSpacing;
-
- final int pageCount = getPageCount();
- for (int i = 0; i < pageCount; i++) {
- View page = getPageAt(i);
- int pageCenter = page.getLeft() + halfPageWidth;
- mScrollState.distanceFromScreenCenter = screenCenter - pageCenter;
- float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
- mScrollState.linearInterpolation = Math.min(1,
- Math.abs(mScrollState.distanceFromScreenCenter) / distanceToReachEdge);
- mScrollState.lastScrollType = ((PageCallbacks) page).onPageScroll(mScrollState);
- }
- }
-
- /**
- * Iterates through all thet asks, and loads the associated task data for newly visible tasks,
- * and unloads the associated task data for tasks that are no longer visible.
- */
- private void loadVisibleTaskData() {
- RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
- int centerPageIndex = getPageNearestToCenterOfScreen();
- int lower = Math.max(mFirstTaskIndex, centerPageIndex - 2);
- int upper = Math.min(centerPageIndex + 2, getChildCount() - 1);
- for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
- TaskView taskView = (TaskView) getChildAt(i);
- Task task = taskView.getTask();
- boolean visible = lower <= i && i <= upper;
- if (visible) {
- if (!mPrevVisibleTasks.get(i)) {
- loader.loadTaskData(task);
-// loader.getHighResThumbnailLoader().onTaskVisible(task);
- }
- } else {
- if (mPrevVisibleTasks.get(i)) {
- loader.unloadTaskData(task);
-// loader.getHighResThumbnailLoader().onTaskInvisible(task);
- }
- }
- mPrevVisibleTasks.put(i, visible);
- }
- }
-
- public void onTaskDismissed(TaskView taskView) {
- ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
- removeView(taskView);
- if (getTaskCount() == 0) {
- mLauncher.getStateManager().goToState(NORMAL);
- }
- }
-
- public void reset() {
- mRunningTaskId = -1;
- setCurrentPage(0);
- }
-
- public int getTaskCount() {
- return getChildCount() - mFirstTaskIndex;
- }
-
- public int getRunningTaskId() {
- return mRunningTaskId;
- }
-
- /**
- * Reloads the view if anything in recents changed.
- */
- public void reloadIfNeeded() {
- if (!mModel.isLoadPlanValid(mLoadPlanId)) {
- mLoadPlanId = mModel.loadTasks(mRunningTaskId, this::applyLoadPlan);
- }
- }
-
- /**
- * Ensures that the first task in the view represents {@param task} and reloads the view
- * if needed. This allows the swipe-up gesture to assume that the first tile always
- * corresponds to the correct task.
- * All subsequent calls to reload will keep the task as the first item until {@link #reset()}
- * is called.
- * Also scrolls the view to this task
- */
- public void showTask(int runningTaskId) {
- boolean needsReload = false;
- if (getTaskCount() == 0) {
- needsReload = true;
- // Add an empty view for now
- setLayoutTransition(null);
- final TaskView taskView = (TaskView) LayoutInflater.from(getContext())
- .inflate(R.layout.task, this, false);
- addView(taskView, mFirstTaskIndex);
- setLayoutTransition(mLayoutTransition);
- }
- mRunningTaskId = runningTaskId;
- setCurrentPage(mFirstTaskIndex);
- if (!needsReload) {
- needsReload = !mModel.isLoadPlanValid(mLoadPlanId);
- }
- if (needsReload) {
- mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
- } else {
- loadVisibleTaskData();
- }
- if (mCurrentPage >= mFirstTaskIndex) {
- getPageAt(mCurrentPage).setAlpha(0);
- }
- }
-
- public QuickScrubController getQuickScrubController() {
- return mQuickScrubController;
- }
-
- public void setFirstTaskIconScaledDown(boolean isScaledDown, boolean animate) {
- if (mFirstTaskIconScaledDown == isScaledDown) {
- return;
- }
- mFirstTaskIconScaledDown = isScaledDown;
- applyIconScale(animate);
- }
-
- private void applyIconScale(boolean animate) {
- float scale = mFirstTaskIconScaledDown ? 0 : 1;
- TaskView firstTask = (TaskView) getChildAt(mFirstTaskIndex);
- if (firstTask != null) {
- if (animate) {
- firstTask.animateIconToScale(scale);
- } else {
- firstTask.setIconScale(scale);
- }
- }
- }
-
- @Override
- public void draw(Canvas canvas) {
- if (mScrim == null) {
- super.draw(canvas);
- return;
- }
-
- final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
-
- int length = mScrim.getWidth();
- int height = getHeight();
- int saveCount = canvas.getSaveCount();
-
- int scrimLeft;
- if (mScrimOnLeft) {
- scrimLeft = getScrollX();
- } else {
- scrimLeft = getScrollX() + getWidth() - length;
- }
- canvas.saveLayer(scrimLeft, 0, scrimLeft + length, height, null, flags);
- super.draw(canvas);
-
- mFadeMatrix.setTranslate(scrimLeft, 0);
- mFadeShader.setLocalMatrix(mFadeMatrix);
- mFadePaint.setShader(mFadeShader);
- canvas.drawRect(scrimLeft, 0, scrimLeft + length, height, mFadePaint);
- canvas.restoreToCount(saveCount);
- }
-
- public interface PageCallbacks {
-
- /**
- * Updates the page UI based on scroll params and returns the type of scroll
- * effect performed.
- *
- * @see #SCROLL_TYPE_NONE
- * @see #SCROLL_TYPE_TASK
- * @see #SCROLL_TYPE_WORKSPACE
- */
- int onPageScroll(ScrollState scrollState);
- }
-
- public static class ScrollState {
-
- public boolean isRtl;
- public int lastScrollType;
-
- public int halfPageWidth;
- public float distanceFromScreenCenter;
- public float linearInterpolation;
-
- public float prevPageExtraWidth;
- }
-}
diff --git a/quickstep/src/com/android/quickstep/SimpleTaskView.java b/quickstep/src/com/android/quickstep/SimpleTaskView.java
deleted file mode 100644
index 8425fa3..0000000
--- a/quickstep/src/com/android/quickstep/SimpleTaskView.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.content.Context;
-import android.graphics.Point;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.WindowManager;
-
-/**
- * A simple view which keeps its size proportional to the display size
- */
-public class SimpleTaskView extends View {
-
- private static final Point sTempPoint = new Point();
-
- public SimpleTaskView(Context context) {
- super(context);
- }
-
- public SimpleTaskView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public SimpleTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int height = MeasureSpec.getSize(heightMeasureSpec);
- getContext().getSystemService(WindowManager.class)
- .getDefaultDisplay().getRealSize(sTempPoint);
-
- int width = (int) ((float) height * sTempPoint.x / sTempPoint.y);
- setMeasuredDimension(width, height);
- }
-}
diff --git a/quickstep/src/com/android/quickstep/SnapshotDragView.java b/quickstep/src/com/android/quickstep/SnapshotDragView.java
deleted file mode 100644
index 2ef3942..0000000
--- a/quickstep/src/com/android/quickstep/SnapshotDragView.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.view.MotionEvent;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.systemui.shared.recents.view.AnimateableViewBounds;
-
-/**
- * Floating view which shows the task snapshot allowing it to be dragged and placed.
- */
-public class SnapshotDragView extends AbstractFloatingView implements Insettable {
-
- private final Launcher mLauncher;
- private final Bitmap mSnapshot;
- private final AnimateableViewBounds mViewBounds;
-
- public SnapshotDragView(Launcher launcher, Bitmap snapshot) {
- super(launcher, null);
- mLauncher = launcher;
- mSnapshot = snapshot;
- mViewBounds = new AnimateableViewBounds(this, 0);
- setWillNotDraw(false);
- setClipToOutline(true);
- setOutlineProvider(mViewBounds);
- }
-
- AnimateableViewBounds getViewBounds() {
- return mViewBounds;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (mSnapshot != null) {
- setMeasuredDimension(mSnapshot.getWidth(), mSnapshot.getHeight());
- } else {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- }
-
- @Override
- public void setInsets(Rect insets) {
-
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (mSnapshot != null) {
- canvas.drawBitmap(mSnapshot, 0, 0, null);
- }
- }
-
- @Override
- public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- return false;
- }
-
- @Override
- protected void handleClose(boolean animate) {
- // We dont suupport animate.
- mLauncher.getDragLayer().removeView(this);
- }
-
- @Override
- public void logActionCommand(int command) {
- // We should probably log the weather
- }
-
- @Override
- protected boolean isOfType(int type) {
- return (type & TYPE_QUICKSTEP_PREVIEW) != 0;
- }
-}
diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
index fb14fb8..08be0c8 100644
--- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
+++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
@@ -16,7 +16,8 @@
package com.android.quickstep;
-import android.app.ActivityOptions;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -31,12 +32,17 @@
import android.view.ViewTreeObserver.OnPreDrawListener;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.util.InstantAppResolver;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
@@ -56,6 +62,7 @@
public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut {
private static final String TAG = "TaskSystemShortcut";
+ private static final int DISMISS_TASK_DURATION = 300;
protected T mSystemShortcut;
@@ -69,11 +76,12 @@
}
@Override
- public View.OnClickListener getOnClickListener(Launcher launcher, ItemInfo itemInfo) {
+ public View.OnClickListener getOnClickListener(
+ BaseDraggingActivity activity, ItemInfo itemInfo) {
return null;
}
- public View.OnClickListener getOnClickListener(final Launcher launcher, final TaskView view) {
+ public View.OnClickListener getOnClickListener(BaseDraggingActivity activity, TaskView view) {
Task task = view.getTask();
ShortcutInfo dummyInfo = new ShortcutInfo();
@@ -81,14 +89,14 @@
ComponentName component = task.getTopComponent();
dummyInfo.intent.setComponent(component);
dummyInfo.user = UserHandle.of(task.key.userId);
- dummyInfo.title = TaskUtils.getTitle(launcher, task);
+ dummyInfo.title = TaskUtils.getTitle(activity, task);
- return getOnClickListenerForTask(launcher, task, dummyInfo);
+ return getOnClickListenerForTask(activity, task, dummyInfo);
}
- protected View.OnClickListener getOnClickListenerForTask(final Launcher launcher,
- final Task task, final ItemInfo dummyInfo) {
- return mSystemShortcut.getOnClickListener(launcher, dummyInfo);
+ protected View.OnClickListener getOnClickListenerForTask(
+ BaseDraggingActivity activity, Task task, ItemInfo dummyInfo) {
+ return mSystemShortcut.getOnClickListener(activity, dummyInfo);
}
public static class AppInfo extends TaskSystemShortcut<SystemShortcut.AppInfo> {
@@ -97,10 +105,13 @@
}
}
- public static class SplitScreen extends TaskSystemShortcut implements OnPreDrawListener {
+ public static class SplitScreen extends TaskSystemShortcut implements OnPreDrawListener,
+ DeviceProfile.OnDeviceProfileChangeListener, View.OnLayoutChangeListener {
private Handler mHandler;
+ private RecentsView mRecentsView;
private TaskView mTaskView;
+ private BaseDraggingActivity mActivity;
public SplitScreen() {
super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen);
@@ -108,22 +119,27 @@
}
@Override
- public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) {
- if (launcher.getDeviceProfile().isMultiWindowMode) {
+ public View.OnClickListener getOnClickListener(
+ BaseDraggingActivity activity, TaskView taskView) {
+ if (activity.getDeviceProfile().isMultiWindowMode) {
return null;
}
final Task task = taskView.getTask();
+ final int taskId = task.key.id;
if (!task.isDockable) {
return null;
}
+ mActivity = activity;
+ mRecentsView = activity.getOverviewPanel();
mTaskView = taskView;
+ final TaskThumbnailView thumbnailView = taskView.getThumbnail();
return (v -> {
- AbstractFloatingView.closeOpenViews(launcher, true,
+ AbstractFloatingView.closeOpenViews(activity, true,
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
- if (ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key.id,
+ if (ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId,
ActivityOptionsCompat.makeSplitScreenOptions(true))) {
- ISystemUiProxy sysUiProxy = RecentsModel.getInstance(launcher).getSystemUiProxy();
+ ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
try {
sysUiProxy.onSplitScreenInvoked();
} catch (RemoteException e) {
@@ -131,26 +147,35 @@
return;
}
+ // Add a device profile change listener to kick off animating the side tasks
+ // once we enter multiwindow mode and relayout
+ activity.addOnDeviceProfileChangeListener(this);
+
final Runnable animStartedListener = () -> {
+ // Hide the task view and wait for the window to be resized
+ // TODO: Consider animating in launcher and do an in-place start activity
+ // afterwards
+ mRecentsView.addIgnoreResetTask(mTaskView);
+ mTaskView.setAlpha(0f);
mTaskView.getViewTreeObserver().addOnPreDrawListener(SplitScreen.this);
- launcher.<RecentsView>getOverviewPanel().removeView(taskView);
};
final int[] position = new int[2];
- taskView.getLocationOnScreen(position);
- final int width = (int) (taskView.getWidth() * taskView.getScaleX());
- final int height = (int) (taskView.getHeight() * taskView.getScaleY());
+ thumbnailView.getLocationOnScreen(position);
+ final int width = (int) (thumbnailView.getWidth() * taskView.getScaleX());
+ final int height = (int) (thumbnailView.getHeight() * taskView.getScaleY());
final Rect taskBounds = new Rect(position[0], position[1],
position[0] + width, position[1] + height);
Bitmap thumbnail = RecentsTransition.drawViewIntoHardwareBitmap(
- taskBounds.width(), taskBounds.height(), taskView, 1f, Color.BLACK);
+ taskBounds.width(), taskBounds.height(), thumbnailView, 1f,
+ Color.BLACK);
AppTransitionAnimationSpecsFuture future =
new AppTransitionAnimationSpecsFuture(mHandler) {
@Override
public List<AppTransitionAnimationSpecCompat> composeSpecs() {
return Collections.singletonList(new AppTransitionAnimationSpecCompat(
- task.key.id, thumbnail, taskBounds));
+ taskId, thumbnail, taskBounds));
}
};
WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
@@ -165,6 +190,31 @@
WindowManagerWrapper.getInstance().endProlongedAnimations();
return true;
}
+
+ @Override
+ public void onDeviceProfileChanged(DeviceProfile dp) {
+ mActivity.removeOnDeviceProfileChangeListener(this);
+ if (dp.isMultiWindowMode) {
+ mTaskView.getRootView().addOnLayoutChangeListener(this);
+ }
+ }
+
+ @Override
+ public void onLayoutChange(View v, int l, int t, int r, int b,
+ int oldL, int oldT, int oldR, int oldB) {
+ mTaskView.getRootView().removeOnLayoutChangeListener(this);
+ mRecentsView.removeIgnoreResetTask(mTaskView);
+
+ // Start animating in the side pages once launcher has been resized
+ PendingAnimation pendingAnim = mRecentsView.createTaskDismissAnimation(mTaskView,
+ false, false, DISMISS_TASK_DURATION);
+ AnimatorPlaybackController controller = AnimatorPlaybackController.wrap(
+ pendingAnim.anim, DISMISS_TASK_DURATION);
+ controller.dispatchOnStart();
+ controller.setEndAction(() -> pendingAnim.finish(true));
+ controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN);
+ controller.start();
+ }
}
public static class Pin extends TaskSystemShortcut {
@@ -177,8 +227,9 @@
}
@Override
- public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) {
- ISystemUiProxy sysUiProxy = RecentsModel.getInstance(launcher).getSystemUiProxy();
+ public View.OnClickListener getOnClickListener(
+ BaseDraggingActivity activity, TaskView taskView) {
+ ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
if (sysUiProxy == null) {
return null;
}
@@ -210,11 +261,11 @@
}
@Override
- protected View.OnClickListener getOnClickListenerForTask(Launcher launcher, Task task,
- ItemInfo itemInfo) {
- if (InstantAppResolver.newInstance(launcher).isInstantApp(launcher,
+ protected View.OnClickListener getOnClickListenerForTask(
+ BaseDraggingActivity activity, Task task, ItemInfo itemInfo) {
+ if (InstantAppResolver.newInstance(activity).isInstantApp(activity,
task.getTopComponent().getPackageName())) {
- return mSystemShortcut.createOnClickListener(launcher, itemInfo);
+ return mSystemShortcut.createOnClickListener(activity, itemInfo);
}
return null;
}
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index b31d42f..2df951b 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -16,12 +16,12 @@
package com.android.quickstep;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.util.Log;
-import com.android.launcher3.Launcher;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.systemui.shared.recents.model.Task;
@@ -34,10 +34,10 @@
private static final String TAG = "TaskUtils";
- public static CharSequence getTitle(Launcher launcher, Task task) {
- LauncherAppsCompat launcherAppsCompat = LauncherAppsCompat.getInstance(launcher);
- UserManagerCompat userManagerCompat = UserManagerCompat.getInstance(launcher);
- PackageManager packageManager = launcher.getPackageManager();
+ public static CharSequence getTitle(Context context, Task task) {
+ LauncherAppsCompat launcherAppsCompat = LauncherAppsCompat.getInstance(context);
+ UserManagerCompat userManagerCompat = UserManagerCompat.getInstance(context);
+ PackageManager packageManager = context.getPackageManager();
UserHandle user = UserHandle.of(task.key.userId);
ApplicationInfo applicationInfo = launcherAppsCompat.getApplicationInfo(
task.getTopComponent().getPackageName(), 0, user);
diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java
index f35f6a6..768fbda 100644
--- a/quickstep/src/com/android/quickstep/TouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/TouchConsumer.java
@@ -21,8 +21,6 @@
import android.view.Choreographer;
import android.view.MotionEvent;
-import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.function.Consumer;
@@ -64,4 +62,14 @@
default Choreographer getIntrimChoreographer(MotionEventQueue queue) {
return null;
}
+
+ default void deferInit() { }
+
+ default boolean deferNextEventToMainThread() {
+ return false;
+ }
+
+ default boolean forceToLauncherConsumer() {
+ return false;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index e5af3e5..df7214e 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -21,17 +21,13 @@
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 com.android.launcher3.LauncherState.FAST_OVERVIEW;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION;
+import static com.android.launcher3.LauncherState.NORMAL;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.Service;
-import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.ResolveInfo;
import android.graphics.PointF;
import android.os.Build;
import android.os.Handler;
@@ -42,15 +38,17 @@
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.MotionEvent;
+import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.util.TraceHelper;
+import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -62,6 +60,8 @@
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
+ public static final boolean DEBUG_OPEN_OVERVIEW_VIA_ALT_TAB = false;
+
private static final SparseArray<String> sMotionEventNames;
static {
@@ -105,9 +105,7 @@
mRecentsModel.setSystemUiProxy(mISystemUiProxy);
RemoteRunnable.executeSafely(() -> mISystemUiProxy.setRecentsOnboardingText(
getResources().getString(R.string.recents_swipe_up_onboarding)));
- Launcher launcher = (Launcher) LauncherAppState.getInstance(
- TouchInteractionService.this).getModel().getCallback();
- UiFactory.onLauncherStateOrFocusChanged(launcher);
+ mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
}
@Override
@@ -132,6 +130,30 @@
mEventQueue.onQuickScrubEnd();
TraceHelper.endSection("SysUiBinder", "onQuickScrubEnd");
}
+
+ @Override
+ public void onOverviewToggle() {
+ mOverviewCommandHelper.onOverviewToggle();
+ }
+
+ @Override
+ public void onOverviewShown(boolean triggeredFromAltTab) {
+ if (DEBUG_OPEN_OVERVIEW_VIA_ALT_TAB) {
+ mOverviewCommandHelper.onOverviewShown();
+ }
+ }
+
+ @Override
+ public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+ if (DEBUG_OPEN_OVERVIEW_VIA_ALT_TAB) {
+ mOverviewCommandHelper.onOverviewHidden();
+ }
+ }
+
+ @Override
+ public void onQuickStep(MotionEvent motionEvent) throws RemoteException {
+
+ }
};
private final TouchConsumer mNoOpTouchConsumer = (ev) -> {};
@@ -143,17 +165,15 @@
}
private ActivityManagerWrapper mAM;
- private RunningTaskInfo mRunningTask;
private RecentsModel mRecentsModel;
- private Intent mHomeIntent;
- private ComponentName mLauncher;
private MotionEventQueue mEventQueue;
private MainThreadExecutor mMainThreadExecutor;
private ISystemUiProxy mISystemUiProxy;
+ private OverviewCommandHelper mOverviewCommandHelper;
+ private OverviewInteractionState mOverviewInteractionState;
private Choreographer mMainThreadChoreographer;
private Choreographer mBackgroundThreadChoreographer;
- private MotionEventQueue mNoOpEventQueue;
@Override
public void onCreate() {
@@ -161,19 +181,10 @@
mAM = ActivityManagerWrapper.getInstance();
mRecentsModel = RecentsModel.getInstance(this);
mMainThreadExecutor = new MainThreadExecutor();
-
- mHomeIntent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .setPackage(getPackageName())
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- ResolveInfo info = getPackageManager().resolveActivity(mHomeIntent, 0);
- mLauncher = new ComponentName(getPackageName(), info.activityInfo.name);
- // Clear the packageName as system can fail to dedupe it b/64108432
- mHomeIntent.setComponent(mLauncher).setPackage(null);
-
+ mOverviewCommandHelper = new OverviewCommandHelper(this);
mMainThreadChoreographer = Choreographer.getInstance();
- mNoOpEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
- mEventQueue = mNoOpEventQueue;
+ mEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
+ mOverviewInteractionState = OverviewInteractionState.getInstance(this);
sConnected = true;
@@ -195,31 +206,46 @@
}
private void onBinderPreMotionEvent(@HitTarget int downHitTarget) {
- mRunningTask = mAM.getRunningTask();
-
mEventQueue.reset();
-
- if (mRunningTask == null) {
- mEventQueue = mNoOpEventQueue;
- } else if (mRunningTask.topActivity.equals(mLauncher)) {
- mEventQueue = getLauncherEventQueue();
- } else {
+ TouchConsumer oldConsumer = mEventQueue.getConsumer();
+ if (oldConsumer.deferNextEventToMainThread()) {
mEventQueue = new MotionEventQueue(mMainThreadChoreographer,
- new OtherActivityTouchConsumer(this, mRunningTask, mRecentsModel,
- mHomeIntent, mISystemUiProxy, mMainThreadExecutor,
- mBackgroundThreadChoreographer, downHitTarget));
+ new DeferredTouchConsumer((v) -> getCurrentTouchConsumer(downHitTarget,
+ oldConsumer.forceToLauncherConsumer(), v)));
+ mEventQueue.deferInit();
+ } else {
+ mEventQueue = new MotionEventQueue(
+ mMainThreadChoreographer, getCurrentTouchConsumer(downHitTarget, false, null));
}
}
- private MotionEventQueue getLauncherEventQueue() {
+ private TouchConsumer getCurrentTouchConsumer(
+ @HitTarget int downHitTarget, boolean forceToLauncher, VelocityTracker tracker) {
+ RunningTaskInfo runningTaskInfo = mAM.getRunningTask();
+
+ if (runningTaskInfo == null && !forceToLauncher) {
+ return mNoOpTouchConsumer;
+ } else if (forceToLauncher ||
+ runningTaskInfo.topActivity.equals(mOverviewCommandHelper.launcher)) {
+ return getLauncherConsumer();
+ } else {
+ if (tracker == null) {
+ tracker = VelocityTracker.obtain();
+ }
+ return new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
+ mOverviewCommandHelper.homeIntent,
+ mOverviewCommandHelper.getActivityControlHelper(), mMainThreadExecutor,
+ mBackgroundThreadChoreographer, downHitTarget, tracker);
+ }
+ }
+
+ private TouchConsumer getLauncherConsumer() {
Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback();
if (launcher == null) {
- return mNoOpEventQueue;
+ return mNoOpTouchConsumer;
}
-
View target = launcher.getDragLayer();
- return new MotionEventQueue(mMainThreadChoreographer,
- new LauncherTouchConsumer(launcher, target));
+ return new LauncherTouchConsumer(launcher, target);
}
private static class LauncherTouchConsumer implements TouchConsumer {
@@ -304,13 +330,12 @@
if (TouchConsumer.isInteractionQuick(interactionType)) {
Runnable action = () -> {
Runnable onComplete = null;
- if (interactionType == INTERACTION_QUICK_SCRUB) {
- mQuickScrubController.onQuickScrubStart(true);
- } else if (interactionType == INTERACTION_QUICK_SWITCH) {
+ if (interactionType == INTERACTION_QUICK_SWITCH) {
onComplete = mQuickScrubController::onQuickSwitch;
}
- mLauncher.getStateManager().goToState(FAST_OVERVIEW, true, 0,
- QUICK_SWITCH_START_DURATION, onComplete);
+ LauncherState fromState = mLauncher.getStateManager().getState();
+ mLauncher.getStateManager().goToState(FAST_OVERVIEW, true, onComplete);
+ mQuickScrubController.onQuickScrubStart(fromState == NORMAL);
};
if (mLauncher.getWorkspace().runOnOverlayHidden(action)) {
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index ede0ad2..2d2a483 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -15,22 +15,16 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
-import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION;
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SWITCH;
import static com.android.quickstep.TouchConsumer.isInteractionQuick;
-import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
+import static com.android.systemui.shared.recents.utilities.Utilities
+ .postAtFrontOfQueueAsynchronously;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.animation.Animator;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
@@ -41,7 +35,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.metrics.LogMaker;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
@@ -53,14 +46,12 @@
import android.view.ViewTreeObserver.OnDrawListener;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
@@ -69,11 +60,16 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.util.ViewOnDrawExecutor;
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+import com.android.quickstep.ActivityControlHelper.LayoutListener;
import com.android.quickstep.TouchConsumer.InteractionType;
+import com.android.quickstep.util.SysuiEventLogger;
+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.recents.utilities.RectFEvaluator;
import com.android.systemui.shared.system.InputConsumerController;
+import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TransactionCompat;
@@ -81,42 +77,8 @@
import java.util.StringJoiner;
-class EventLogTags {
- private EventLogTags() {
- } // don't instantiate
-
- /** 524292 sysui_multi_action (content|4) */
- public static final int SYSUI_MULTI_ACTION = 524292;
-
- public static void writeSysuiMultiAction(Object[] content) {
- android.util.EventLog.writeEvent(SYSUI_MULTI_ACTION, content);
- }
-}
-
-class MetricsLogger {
- private static MetricsLogger sMetricsLogger;
-
- private static MetricsLogger getLogger() {
- if (sMetricsLogger == null) {
- sMetricsLogger = new MetricsLogger();
- }
- return sMetricsLogger;
- }
-
- protected void saveLog(Object[] rep) {
- EventLogTags.writeSysuiMultiAction(rep);
- }
-
- public void write(LogMaker content) {
- if (content.getType() == 0/*MetricsEvent.TYPE_UNKNOWN*/) {
- content.setType(4/*MetricsEvent.TYPE_ACTION*/);
- }
- saveLog(content.serialize());
- }
-}
-
@TargetApi(Build.VERSION_CODES.O)
-public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
+public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
private static final boolean DEBUG_STATES = false;
@@ -190,6 +152,8 @@
// The clip rect in source app window coordinates
private final Rect mClipRect = new Rect();
private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
+ protected Runnable mGestureEndCallback;
+ protected boolean mIsGoingToHome;
private DeviceProfile mDp;
private int mTransitionDragLength;
@@ -203,12 +167,14 @@
private final Context mContext;
private final int mRunningTaskId;
+ private final ActivityControlHelper<T> mActivityControlHelper;
+ private final ActivityInitListener mActivityInitListener;
private MultiStateCallback mStateCallback;
private AnimatorPlaybackController mLauncherTransitionController;
- private Launcher mLauncher;
- private LauncherLayoutListener mLauncherLayoutListener;
+ private T mActivity;
+ private LayoutListener mLayoutListener;
private RecentsView mRecentsView;
private QuickScrubController mQuickScrubController;
@@ -229,12 +195,16 @@
private Matrix mTmpMatrix = new Matrix();
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
- private final MetricsLogger mMetricsLogger = new MetricsLogger();
- WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs) {
+ WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs,
+ ActivityControlHelper<T> controller) {
mContext = context;
mRunningTaskId = runningTaskInfo.id;
mTouchTimeMs = touchTimeMs;
+ mActivityControlHelper = controller;
+ mActivityInitListener = mActivityControlHelper
+ .createActivityInitListener(this::onActivityInit);
+
// Register the input consumer on the UI thread, to ensure that it runs after any pending
// unregister calls
mMainExecutor.execute(mInputConsumer::registerInputConsumer);
@@ -307,7 +277,8 @@
mSourceStackBounds.height() - mSourceInsets.bottom);
Rect tempRect = new Rect();
- RecentsView.getPageRect(dp, mContext, tempRect);
+ mTransitionDragLength = mActivityControlHelper
+ .getSwipeUpDestinationAndLength(dp, mContext, tempRect);
mTargetRect.set(tempRect);
mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
@@ -328,14 +299,6 @@
Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0),
Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0));
mSourceRect.set(scaledTargetRect);
-
- Rect targetInsets = dp.getInsets();
- if (dp.isVerticalBarLayout()) {
- int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
- mTransitionDragLength = dp.hotseatBarSizePx + dp.hotseatBarSidePaddingPx + hotseatInset;
- } else {
- mTransitionDragLength = dp.heightPx - tempRect.bottom;
- }
}
private long getFadeInDuration() {
@@ -350,40 +313,39 @@
}
}
- @Override
- protected boolean init(final Launcher launcher, boolean alreadyOnHome) {
- if (launcher == mLauncher) {
+ public void initWhenReady() {
+ mActivityInitListener.register();
+ }
+
+ private boolean onActivityInit(final T activity, Boolean alreadyOnHome) {
+ if (mActivity == activity) {
return true;
}
- if (mLauncher != null) {
+ if (mActivity != null) {
// The launcher may have been recreated as a result of device rotation.
int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES;
initStateCallbacks();
mStateCallback.setState(oldState);
- mLauncherLayoutListener.setHandler(null);
+ mLayoutListener.setHandler(null);
}
mWasLauncherAlreadyVisible = alreadyOnHome;
- mLauncher = launcher;
+ mActivity = activity;
- // For the duration of the gesture, lock the screen orientation to ensure that we do not
- // rotate mid-quickscrub
- mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
-
- mRecentsView = mLauncher.getOverviewPanel();
+ mRecentsView = activity.getOverviewPanel();
mQuickScrubController = mRecentsView.getQuickScrubController();
- mLauncherLayoutListener = new LauncherLayoutListener(mLauncher);
+ mLayoutListener = mActivityControlHelper.createLayoutListener(mActivity);
mStateCallback.setState(STATE_LAUNCHER_PRESENT);
if (alreadyOnHome) {
- onLauncherStart(launcher);
+ onLauncherStart(activity);
} else {
- launcher.setOnStartCallback(this::onLauncherStart);
+ activity.setOnStartCallback(this::onLauncherStart);
}
return true;
}
- private void onLauncherStart(final Launcher launcher) {
- if (mLauncher != launcher) {
+ private void onLauncherStart(final T activity) {
+ if (mActivity != activity) {
return;
}
if ((mStateCallback.getState() & STATE_HANDLER_INVALIDATED) != 0) {
@@ -391,31 +353,21 @@
}
mStateCallback.setState(STATE_LAUNCHER_STARTED);
- LauncherState startState = mLauncher.getStateManager().getState();
- if (startState.disableRestore) {
- startState = mLauncher.getStateManager().getRestState();
- }
- mLauncher.getStateManager().setRestState(startState);
-
- AbstractFloatingView.closeAllOpenViews(mLauncher, mWasLauncherAlreadyVisible);
+ mActivityControlHelper.prepareRecentsUI(mActivity, mWasLauncherAlreadyVisible);
+ AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible);
- if (mWasLauncherAlreadyVisible && !mLauncher.getAppTransitionManager().isAnimating()) {
- DeviceProfile dp = mLauncher.getDeviceProfile();
- long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
- mLauncherTransitionController = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(OVERVIEW, accuracy);
+ if (mWasLauncherAlreadyVisible) {
+ mLauncherTransitionController = mActivityControlHelper
+ .createControllerForVisibleActivity(activity);
mLauncherTransitionController.dispatchOnStart();
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_DRAWN);
} else {
TraceHelper.beginSection("WTS-init");
- mLauncher.getStateManager().goToState(OVERVIEW, false);
- TraceHelper.partitionSection("WTS-init", "State changed");
-
// TODO: Implement a better animation for fading in
- View rootView = mLauncher.getRootView();
+ View rootView = activity.getRootView();
rootView.setAlpha(0);
rootView.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {
@@ -424,21 +376,18 @@
TraceHelper.endSection("WTS-init", "Launcher frame is drawn");
rootView.post(() ->
rootView.getViewTreeObserver().removeOnDrawListener(this));
- if (launcher != mLauncher) {
+ if (activity != mActivity) {
return;
}
mStateCallback.setState(STATE_LAUNCHER_DRAWN);
}
});
-
- // Optimization, hide the all apps view to prevent layout while initializing
- mLauncher.getAppsView().setVisibility(View.GONE);
}
mRecentsView.showTask(mRunningTaskId);
mRecentsView.setFirstTaskIconScaledDown(true /* isScaledDown */, false /* animate */);
- mLauncherLayoutListener.open();
+ mLayoutListener.open();
}
public void setLauncherOnDrawCallback(Runnable callback) {
@@ -446,7 +395,7 @@
}
private void launcherFrameDrawn() {
- View rootView = mLauncher.getRootView();
+ View rootView = mActivity.getRootView();
if (rootView.getAlpha() < 1) {
if (mGestureStarted) {
final MultiStateCallback callback = mStateCallback;
@@ -465,18 +414,15 @@
}
private void initializeLauncherAnimationController() {
- mLauncherLayoutListener.setHandler(this);
+ mLayoutListener.setHandler(this);
onLauncherLayoutChanged();
- // Mimic ActivityMetricsLogger.logAppTransitionMultiEvents() logging for
- // "Recents" activity for app transition tests for the app-to-recents case.
- final LogMaker builder = new LogMaker(761/*APP_TRANSITION*/);
- builder.setPackageName("com.android.systemui");
- builder.addTaggedData(871/*FIELD_CLASS_NAME*/,
- "com.android.systemui.recents.RecentsActivity");
- builder.addTaggedData(319/*APP_TRANSITION_DELAY_MS*/,
- mLauncherFrameDrawnTime - mTouchTimeMs);
- mMetricsLogger.write(builder);
+ final long transitionDelay = mLauncherFrameDrawnTime - mTouchTimeMs;
+ SysuiEventLogger.writeDummyRecentsTransition(transitionDelay);
+
+ if (LatencyTrackerCompat.isEnabled(mContext)) {
+ LatencyTrackerCompat.logToggleRecents((int) transitionDelay);
+ }
}
public void updateInteractionType(@InteractionType int interactionType) {
@@ -498,7 +444,7 @@
}
private void onQuickInteractionStart() {
- mLauncher.getStateManager().goToState(FAST_OVERVIEW,
+ mActivityControlHelper.onQuickInteractionStart(mActivity,
mWasLauncherAlreadyVisible || mGestureStarted);
mQuickScrubController.onQuickScrubStart(false);
}
@@ -513,32 +459,14 @@
}
/**
- * Called by {@link #mLauncherLayoutListener} when launcher layout changes
+ * Called by {@link #mLayoutListener} when launcher layout changes
*/
public void onLauncherLayoutChanged() {
- initTransitionEndpoints(mLauncher.getDeviceProfile());
+ initTransitionEndpoints(mActivity.getDeviceProfile());
if (!mWasLauncherAlreadyVisible) {
- float startProgress;
- AllAppsTransitionController controller = mLauncher.getAllAppsController();
-
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- startProgress = 1;
- } else {
- float scrollRange = Math.max(controller.getShiftRange(), 1);
- startProgress = (mTransitionDragLength / scrollRange) + 1;
- }
- AnimatorSet anim = new AnimatorSet();
- ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(controller, ALL_APPS_PROGRESS,
- startProgress, OVERVIEW.getVerticalProgress(mLauncher));
- shiftAnim.setInterpolator(LINEAR);
- anim.play(shiftAnim);
-
- // TODO: Link this animation to state animation, so that it is cancelled
- // automatically on state change
- anim.setDuration(mTransitionDragLength * 2);
- mLauncherTransitionController =
- AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
+ mLauncherTransitionController = mActivityControlHelper
+ .createControllerForHiddenActivity(mActivity, mTransitionDragLength);
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
}
}
@@ -588,9 +516,8 @@
mLauncherTransitionController.setPlayFraction(shift);
// Make sure the window follows the first task if it moves, e.g. during quick scrub.
- int firstTaskIndex = mRecentsView.getFirstTaskIndex();
- View firstTask = mRecentsView.getPageAt(firstTaskIndex);
- int scrollForFirstTask = mRecentsView.getScrollForPage(firstTaskIndex);
+ View firstTask = mRecentsView.getPageAt(0);
+ int scrollForFirstTask = mRecentsView.getScrollForPage(0);
int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX());
if (offsetFromFirstTask != 0) {
synchronized (mTargetRect) {
@@ -600,6 +527,12 @@
mTargetRect.offset(offsetX, 0);
}
}
+ if (mRecentsAnimationWrapper.controller != null) {
+
+ // TODO: This logic is spartanic!
+ mRecentsAnimationWrapper.controller.setAnimationTargetsBehindSystemBars(
+ shift < 0.12f);
+ }
};
if (Looper.getMainLooper() == Looper.myLooper()) {
runOnUi.run();
@@ -646,14 +579,13 @@
}
}
}
-
mRecentsAnimationWrapper.setController(controller, apps);
setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
}
public void onRecentsAnimationCanceled() {
mRecentsAnimationWrapper.setController(null, null);
- clearReference();
+ mActivityInitListener.unregister();
setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
}
@@ -669,9 +601,10 @@
* on both background and UI threads
*/
private void notifyGestureStarted() {
- final Launcher curLauncher = mLauncher;
- if (curLauncher != null) {
- curLauncher.onQuickstepGestureStarted(mWasLauncherAlreadyVisible);
+ final T curActivity = mActivity;
+ if (curActivity != null) {
+ mActivityControlHelper.onQuickstepGestureStarted(
+ curActivity, mWasLauncherAlreadyVisible);
}
}
@@ -721,13 +654,14 @@
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
private void animateToProgress(float progress, long duration) {
+ mIsGoingToHome = Float.compare(progress, 1) == 0;
ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
anim.setInterpolator(Interpolators.SCROLL);
anim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
- setStateOnUiThread((Float.compare(mCurrentShift.value, 0) == 0)
- ? STATE_SCALED_CONTROLLER_APP : STATE_SCALED_CONTROLLER_RECENTS);
+ setStateOnUiThread(mIsGoingToHome ?
+ STATE_SCALED_CONTROLLER_RECENTS : STATE_SCALED_CONTROLLER_APP);
}
});
anim.start();
@@ -748,31 +682,26 @@
}
private void invalidateHandler() {
- mCurrentShift.cancelAnimation();
+ mCurrentShift.finishAnimation();
if (mGestureEndCallback != null) {
mGestureEndCallback.run();
}
- clearReference();
+ mActivityInitListener.unregister();
mInputConsumer.unregisterInputConsumer();
}
private void invalidateHandlerWithLauncher() {
mLauncherTransitionController = null;
- mLauncherLayoutListener.setHandler(null);
- mLauncherLayoutListener.close(false);
-
- // Restore the requested orientation to the user preference after the gesture has ended
- mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_NONE);
+ mLayoutListener.finish();
mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, false /* animate */);
}
private void resetStateForAnimationCancel() {
- LauncherState startState = mLauncher.getStateManager().getRestState();
- boolean animate = mWasLauncherAlreadyVisible || mGestureStarted;
- mLauncher.getStateManager().goToState(startState, animate);
+ boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
+ mActivityControlHelper.onTransitionCancelled(mActivity, wasVisible);
}
public void layoutListenerClosed() {
@@ -801,17 +730,8 @@
if (taskView != null) {
// Defer finishing the animation until the next launcher frame with the
// new thumbnail
- ViewOnDrawExecutor executor = new ViewOnDrawExecutor() {
- @Override
- public void onViewDetachedFromWindow(View v) {
- if (!isCompleted()) {
- runAllTasks();
- }
- }
- };
- executor.attachTo(mLauncher, taskView,
- false /* waitForLoadAnimation */);
- executor.execute(finishTransitionRunnable);
+ mActivityControlHelper.executeOnNextDraw(mActivity, taskView,
+ finishTransitionRunnable);
finishTransitionPosted = true;
}
}
@@ -827,8 +747,7 @@
}
private void setupLauncherUiAfterSwipeUpAnimation() {
- // Re apply state in case we did something funky during the transition.
- mLauncher.getStateManager().reapplyState();
+ mActivityControlHelper.onSwipeUpComplete(mActivity);
// Animate the first icon.
mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, true /* animate */);
@@ -882,4 +801,8 @@
Log.d(TAG, "[" + System.identityHashCode(this) + "] Adding " + stateFlagStr + " to "
+ currentStateStr);
}
+
+ public void setGestureEndCallback(Runnable gestureEndCallback) {
+ mGestureEndCallback = gestureEndCallback;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/SysuiEventLogger.java b/quickstep/src/com/android/quickstep/util/SysuiEventLogger.java
new file mode 100644
index 0000000..d474ded
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SysuiEventLogger.java
@@ -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.util;
+
+import android.metrics.LogMaker;
+import android.util.EventLog;
+
+/**
+ * Utility class for writing logs on behalf of systemUI
+ */
+public class SysuiEventLogger {
+
+ /** 524292 sysui_multi_action (content|4) */
+ public static final int SYSUI_MULTI_ACTION = 524292;
+
+ private static void write(LogMaker content) {
+ if (content.getType() == 0/*MetricsEvent.TYPE_UNKNOWN*/) {
+ content.setType(4/*MetricsEvent.TYPE_ACTION*/);
+ }
+ EventLog.writeEvent(SYSUI_MULTI_ACTION, content.serialize());
+ }
+
+ public static void writeDummyRecentsTransition(long transitionDelay) {
+ // Mimic ActivityMetricsLogger.logAppTransitionMultiEvents() logging for
+ // "Recents" activity for app transition tests for the app-to-recents case.
+ final LogMaker builder = new LogMaker(761/*APP_TRANSITION*/);
+ builder.setPackageName("com.android.systemui");
+ builder.addTaggedData(871/*FIELD_CLASS_NAME*/,
+ "com.android.systemui.recents.RecentsActivity");
+ builder.addTaggedData(319/*APP_TRANSITION_DELAY_MS*/,
+ transitionDelay);
+ write(builder);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
similarity index 83%
rename from quickstep/src/com/android/quickstep/LauncherLayoutListener.java
rename to quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
index fbdbe7a..6b7143d 100644
--- a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
@@ -13,7 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.quickstep;
+package com.android.quickstep.views;
+
+import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import android.graphics.Rect;
import android.view.MotionEvent;
@@ -21,11 +23,14 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
+import com.android.quickstep.ActivityControlHelper.LayoutListener;
+import com.android.quickstep.WindowTransformSwipeHandler;
/**
* Floating view which shows the task snapshot allowing it to be dragged and placed.
*/
-public class LauncherLayoutListener extends AbstractFloatingView implements Insettable {
+public class LauncherLayoutListener extends AbstractFloatingView
+ implements Insettable, LayoutListener {
private final Launcher mLauncher;
private WindowTransformSwipeHandler mHandler;
@@ -36,6 +41,7 @@
setVisibility(INVISIBLE);
}
+ @Override
public void setHandler(WindowTransformSwipeHandler handler) {
mHandler = handler;
}
@@ -65,6 +71,7 @@
}
}
+ @Override
public void open() {
if (!mIsOpen) {
mLauncher.getDragLayer().addView(this);
@@ -86,4 +93,11 @@
protected boolean isOfType(int type) {
return (type & TYPE_QUICKSTEP_PREVIEW) != 0;
}
+
+ @Override
+ public void finish() {
+ setHandler(null);
+ close(false);
+ mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_NONE);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
new file mode 100644
index 0000000..7989e84
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -0,0 +1,134 @@
+/*
+ * 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.views;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.Shader.TileMode;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+
+/**
+ * {@link RecentsView} used in Launcher activity
+ */
+public class LauncherRecentsView extends RecentsView<Launcher> implements Insettable {
+
+ private Bitmap mScrim;
+ private Paint mFadePaint;
+ private Shader mFadeShader;
+ private Matrix mFadeMatrix;
+ private boolean mScrimOnLeft;
+
+ public LauncherRecentsView(Context context) {
+ this(context, null);
+ }
+
+ public LauncherRecentsView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public LauncherRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ mInsets.set(insets);
+ DeviceProfile dp = mActivity.getDeviceProfile();
+ Rect padding = getPadding(dp, getContext());
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+ lp.bottomMargin = padding.bottom;
+ setLayoutParams(lp);
+
+ setPadding(padding.left, padding.top, padding.right, 0);
+
+ if (dp.isVerticalBarLayout()) {
+ boolean wasScrimOnLeft = mScrimOnLeft;
+ mScrimOnLeft = dp.isSeascape();
+
+ if (mScrim == null || wasScrimOnLeft != mScrimOnLeft) {
+ Drawable scrim = getContext().getDrawable(mScrimOnLeft
+ ? R.drawable.recents_horizontal_scrim_left
+ : R.drawable.recents_horizontal_scrim_right);
+ if (scrim instanceof BitmapDrawable) {
+ mScrim = ((BitmapDrawable) scrim).getBitmap();
+ mFadePaint = new Paint();
+ mFadePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+ mFadeShader = new BitmapShader(mScrim, TileMode.CLAMP, TileMode.REPEAT);
+ mFadeMatrix = new Matrix();
+ } else {
+ mScrim = null;
+ }
+ }
+ } else {
+ mScrim = null;
+ mFadePaint = null;
+ mFadeShader = null;
+ mFadeMatrix = null;
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mScrim == null) {
+ super.draw(canvas);
+ return;
+ }
+
+ final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
+
+ int length = mScrim.getWidth();
+ int height = getHeight();
+ int saveCount = canvas.getSaveCount();
+
+ int scrimLeft;
+ if (mScrimOnLeft) {
+ scrimLeft = getScrollX();
+ } else {
+ scrimLeft = getScrollX() + getWidth() - length;
+ }
+ canvas.saveLayer(scrimLeft, 0, scrimLeft + length, height, null, flags);
+ super.draw(canvas);
+
+ mFadeMatrix.setTranslate(scrimLeft, 0);
+ mFadeShader.setLocalMatrix(mFadeMatrix);
+ mFadePaint.setShader(mFadeShader);
+ canvas.drawRect(scrimLeft, 0, scrimLeft + length, height, mFadePaint);
+ canvas.restoreToCount(saveCount);
+ }
+
+ @Override
+ protected void onAllTasksRemoved() {
+ mActivity.getStateManager().goToState(NORMAL);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
new file mode 100644
index 0000000..9c0e580
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -0,0 +1,633 @@
+/*
+ * 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.views;
+
+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;
+
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.SparseBooleanArray;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.PagedView;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.quickstep.PendingAnimation;
+import com.android.quickstep.QuickScrubController;
+import com.android.quickstep.RecentsModel;
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.WindowManagerWrapper;
+
+import java.util.ArrayList;
+
+/**
+ * A list of recent tasks.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public abstract class RecentsView<T extends BaseActivity>
+ extends PagedView implements OnSharedPreferenceChangeListener {
+
+ private static final String PREF_FLIP_RECENTS = "pref_flip_recents";
+
+ private static final Rect sTempStableInsets = new Rect();
+
+ protected final T mActivity;
+ private final QuickScrubController mQuickScrubController;
+ private final float mFastFlingVelocity;
+ private final RecentsModel mModel;
+
+ private final ScrollState mScrollState = new ScrollState();
+ // Keeps track of the previously known visible tasks for purposes of loading/unloading task data
+ private final SparseBooleanArray mHasVisibleTaskData = new SparseBooleanArray();
+
+ /**
+ * TODO: Call reloadIdNeeded in onTaskStackChanged.
+ */
+ private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+ @Override
+ public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
+ for (int i = 0; i < getChildCount(); i++) {
+ final TaskView taskView = (TaskView) getChildAt(i);
+ if (taskView.getTask().key.id == taskId) {
+ taskView.getThumbnail().setThumbnail(taskView.getTask(), snapshot);
+ return;
+ }
+ }
+ }
+ };
+
+ private int mLoadPlanId = -1;
+
+ // Only valid until the launcher state changes to NORMAL
+ private int mRunningTaskId = -1;
+
+ private boolean mFirstTaskIconScaledDown = false;
+
+ private boolean mOverviewStateEnabled;
+ private boolean mTaskStackListenerRegistered;
+ private Runnable mNextPageSwitchRunnable;
+
+ private PendingAnimation mPendingAnimation;
+
+ // Keeps track of task views whose visual state should not be reset
+ private ArraySet<TaskView> mIgnoreResetTaskViews = new ArraySet<>();
+
+ public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
+ enableFreeScroll(true);
+ setClipToOutline(true);
+
+ mFastFlingVelocity = getResources()
+ .getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
+ mActivity = (T) BaseActivity.fromContext(context);
+ mQuickScrubController = new QuickScrubController(mActivity, this);
+ mModel = RecentsModel.getInstance(context);
+
+ onSharedPreferenceChanged(Utilities.getPrefs(context), PREF_FLIP_RECENTS);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
+ if (s.equals(PREF_FLIP_RECENTS)) {
+ mIsRtl = Utilities.isRtl(getResources());
+ if (sharedPreferences.getBoolean(PREF_FLIP_RECENTS, false)) {
+ mIsRtl = !mIsRtl;
+ }
+ setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
+ }
+ }
+
+ public boolean isRtl() {
+ return mIsRtl;
+ }
+
+ public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData) {
+ for (int i = 0; i < getChildCount(); i++) {
+ final TaskView taskView = (TaskView) getChildAt(i);
+ if (taskView.getTask().key.id == taskId) {
+ taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
+ taskView.setAlpha(1);
+ return taskView;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ updateTaskStackListenerState();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ updateTaskStackListenerState();
+ Utilities.getPrefs(getContext()).registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ updateTaskStackListenerState();
+ Utilities.getPrefs(getContext()).unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onViewRemoved(View child) {
+ super.onViewRemoved(child);
+
+ // Clear the task data for the removed child if it was visible
+ Task task = ((TaskView) child).getTask();
+ if (mHasVisibleTaskData.get(task.key.id)) {
+ mHasVisibleTaskData.delete(task.key.id);
+ RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+ loader.unloadTaskData(task);
+ loader.getHighResThumbnailLoader().onTaskInvisible(task);
+ }
+ }
+
+ public boolean isTaskViewVisible(TaskView tv) {
+ // For now, just check if it's the active task or an adjacent task
+ return Math.abs(indexOfChild(tv) - getNextPage()) <= 1;
+ }
+
+ public TaskView getTaskView(int taskId) {
+ for (int i = 0; i < getChildCount(); i++) {
+ TaskView tv = (TaskView) getChildAt(i);
+ if (tv.getTask().key.id == taskId) {
+ return tv;
+ }
+ }
+ return null;
+ }
+
+ public void setOverviewStateEnabled(boolean enabled) {
+ mOverviewStateEnabled = enabled;
+ updateTaskStackListenerState();
+ }
+
+ public void setNextPageSwitchRunnable(Runnable r) {
+ mNextPageSwitchRunnable = r;
+ }
+
+ @Override
+ protected void onPageEndTransition() {
+ super.onPageEndTransition();
+ if (mNextPageSwitchRunnable != null) {
+ mNextPageSwitchRunnable.run();
+ mNextPageSwitchRunnable = null;
+ }
+ }
+
+ private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) {
+ if (mPendingAnimation != null) {
+ mPendingAnimation.addEndListener((b) -> applyLoadPlan(loadPlan));
+ return;
+ }
+ TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null;
+ if (stack == null) {
+ removeAllViews();
+ return;
+ }
+
+ int oldChildCount = getChildCount();
+
+ // Ensure there are as many views as there are tasks in the stack (adding and trimming as
+ // necessary)
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ final ArrayList<Task> tasks = new ArrayList<>(stack.getTasks());
+
+ final int requiredChildCount = tasks.size();
+ for (int i = getChildCount(); i < requiredChildCount; i++) {
+ final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false);
+ addView(taskView);
+ }
+ while (getChildCount() > requiredChildCount) {
+ final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1);
+ removeView(taskView);
+ }
+
+ // Unload existing visible task data
+ unloadVisibleTaskData();
+
+ // Rebind and reset all task views
+ for (int i = requiredChildCount - 1; i >= 0; i--) {
+ final int pageIndex = requiredChildCount - i - 1;
+ final Task task = tasks.get(i);
+ final TaskView taskView = (TaskView) getChildAt(pageIndex);
+ taskView.bind(task);
+ }
+ resetTaskVisuals();
+ applyIconScale(false /* animate */);
+
+ if (oldChildCount != getChildCount()) {
+ mQuickScrubController.snapToNextTaskIfAvailable();
+ }
+ }
+
+ public void resetTaskVisuals() {
+ for (int i = getChildCount() - 1; i >= 0; i--) {
+ TaskView taskView = (TaskView) getChildAt(i);
+ if (!mIgnoreResetTaskViews.contains(taskView)) {
+ taskView.resetVisualProperties();
+ }
+ }
+
+ updateCurveProperties();
+ // Update the set of visible task's data
+ loadVisibleTaskData();
+ }
+
+ private void updateTaskStackListenerState() {
+ boolean registerStackListener = mOverviewStateEnabled && isAttachedToWindow()
+ && getWindowVisibility() == VISIBLE;
+ if (registerStackListener != mTaskStackListenerRegistered) {
+ if (registerStackListener) {
+ ActivityManagerWrapper.getInstance()
+ .registerTaskStackListener(mTaskStackListener);
+ reloadIfNeeded();
+ } else {
+ ActivityManagerWrapper.getInstance()
+ .unregisterTaskStackListener(mTaskStackListener);
+ }
+ mTaskStackListenerRegistered = registerStackListener;
+ }
+ }
+
+ protected static Rect getPadding(DeviceProfile profile, Context context) {
+ WindowManagerWrapper.getInstance().getStableInsets(sTempStableInsets);
+ Rect padding = new Rect(profile.workspacePadding);
+
+ float taskWidth = profile.widthPx - sTempStableInsets.left - sTempStableInsets.right;
+ float taskHeight = profile.heightPx - sTempStableInsets.top - sTempStableInsets.bottom;
+
+ float overviewHeight, overviewWidth;
+ if (profile.isVerticalBarLayout()) {
+ float scrimLength = context.getResources()
+ .getDimension(R.dimen.recents_page_fade_length);
+ float maxPadding = Math.max(padding.left, padding.right);
+
+ // Use the same padding on both sides for symmetry.
+ float availableWidth = taskWidth - 2 * Math.max(maxPadding, scrimLength);
+ float availableHeight = profile.availableHeightPx - padding.top - padding.bottom
+ - sTempStableInsets.top;
+ float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
+ overviewHeight = taskHeight * scaledRatio;
+ overviewWidth = taskWidth * scaledRatio;
+
+ } else {
+ overviewHeight = profile.availableHeightPx - padding.top - padding.bottom
+ - sTempStableInsets.top;
+ overviewWidth = taskWidth * overviewHeight / taskHeight;
+ }
+
+ padding.bottom = profile.availableHeightPx - padding.top - sTempStableInsets.top
+ - Math.round(overviewHeight);
+ padding.left = padding.right = (int) ((profile.availableWidthPx - overviewWidth) / 2);
+ return padding;
+ }
+
+ public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) {
+ Rect targetPadding = getPadding(grid, context);
+ Rect insets = grid.getInsets();
+ outRect.set(
+ targetPadding.left + insets.left,
+ targetPadding.top + insets.top,
+ grid.widthPx - targetPadding.right - insets.right,
+ grid.heightPx - targetPadding.bottom - insets.bottom);
+ outRect.top += context.getResources()
+ .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+ }
+
+ @Override
+ protected boolean computeScrollHelper() {
+ boolean scrolling = super.computeScrollHelper();
+ boolean isFlingingFast = false;
+ updateCurveProperties();
+ if (scrolling || (mTouchState == TOUCH_STATE_SCROLLING)) {
+ if (scrolling) {
+ // Check if we are flinging quickly to disable high res thumbnail loading
+ isFlingingFast = mScroller.getCurrVelocity() > mFastFlingVelocity;
+ }
+
+ // After scrolling, update the visible task's data
+ loadVisibleTaskData();
+ }
+
+ // Update the high res thumbnail loader
+ RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+ loader.getHighResThumbnailLoader().setFlingingFast(isFlingingFast);
+ return scrolling;
+ }
+
+ /**
+ * Scales and adjusts translation of adjacent pages as if on a curved carousel.
+ */
+ public void updateCurveProperties() {
+ if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
+ return;
+ }
+ final int halfPageWidth = getNormalChildWidth() / 2;
+ final int screenCenter = mInsets.left + getPaddingLeft() + getScrollX() + halfPageWidth;
+ final int halfScreenWidth = getMeasuredWidth() / 2;
+ final int pageSpacing = mPageSpacing;
+
+ final int pageCount = getPageCount();
+ for (int i = 0; i < pageCount; i++) {
+ View page = getPageAt(i);
+ float pageCenter = page.getLeft() + page.getTranslationX() + halfPageWidth;
+ float distanceFromScreenCenter = screenCenter - pageCenter;
+ float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
+ mScrollState.linearInterpolation = Math.min(1,
+ Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
+ ((PageCallbacks) page).onPageScroll(mScrollState);
+ }
+ }
+
+ /**
+ * Iterates through all thet asks, 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() {
+ RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+ int centerPageIndex = getPageNearestToCenterOfScreen();
+ int lower = Math.max(0, centerPageIndex - 2);
+ int upper = Math.min(centerPageIndex + 2, getChildCount() - 1);
+ int numChildren = getChildCount();
+
+ // Update the task data for the in/visible children
+ for (int i = 0; i < numChildren; i++) {
+ TaskView taskView = (TaskView) getChildAt(i);
+ Task task = taskView.getTask();
+ boolean visible = lower <= i && i <= upper;
+ if (visible) {
+ if (!mHasVisibleTaskData.get(task.key.id)) {
+ loader.loadTaskData(task);
+ loader.getHighResThumbnailLoader().onTaskVisible(task);
+ }
+ mHasVisibleTaskData.put(task.key.id, visible);
+ } else {
+ if (mHasVisibleTaskData.get(task.key.id)) {
+ loader.unloadTaskData(task);
+ loader.getHighResThumbnailLoader().onTaskInvisible(task);
+ }
+ mHasVisibleTaskData.delete(task.key.id);
+ }
+ }
+ }
+
+ /**
+ * Unloads any associated data from the currently visible tasks
+ */
+ private void unloadVisibleTaskData() {
+ RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+ for (int i = 0; i < mHasVisibleTaskData.size(); i++) {
+ if (mHasVisibleTaskData.valueAt(i)) {
+ TaskView taskView = getTaskView(mHasVisibleTaskData.keyAt(i));
+ Task task = taskView.getTask();
+ loader.unloadTaskData(task);
+ loader.getHighResThumbnailLoader().onTaskInvisible(task);
+ }
+ }
+ mHasVisibleTaskData.clear();
+ }
+
+
+ protected abstract void onAllTasksRemoved();
+
+ public void reset() {
+ unloadVisibleTaskData();
+ mRunningTaskId = -1;
+ setCurrentPage(0);
+ }
+
+ /**
+ * Reloads the view if anything in recents changed.
+ */
+ public void reloadIfNeeded() {
+ if (!mModel.isLoadPlanValid(mLoadPlanId)) {
+ mLoadPlanId = mModel.loadTasks(mRunningTaskId, this::applyLoadPlan);
+ }
+ }
+
+ /**
+ * Ensures that the first task in the view represents {@param task} and reloads the view
+ * if needed. This allows the swipe-up gesture to assume that the first tile always
+ * corresponds to the correct task.
+ * All subsequent calls to reload will keep the task as the first item until {@link #reset()}
+ * is called.
+ * Also scrolls the view to this task
+ */
+ public void showTask(int runningTaskId) {
+ boolean needsReload = false;
+ if (getChildCount() == 0) {
+ needsReload = true;
+ // Add an empty view for now
+ final TaskView taskView = (TaskView) LayoutInflater.from(getContext())
+ .inflate(R.layout.task, this, false);
+ addView(taskView, 0);
+ }
+ mRunningTaskId = runningTaskId;
+ setCurrentPage(0);
+ if (!needsReload) {
+ needsReload = !mModel.isLoadPlanValid(mLoadPlanId);
+ }
+ if (needsReload) {
+ mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
+ } else {
+ loadVisibleTaskData();
+ }
+ getPageAt(mCurrentPage).setAlpha(0);
+ }
+
+ public QuickScrubController getQuickScrubController() {
+ return mQuickScrubController;
+ }
+
+ public void setFirstTaskIconScaledDown(boolean isScaledDown, boolean animate) {
+ if (mFirstTaskIconScaledDown == isScaledDown) {
+ return;
+ }
+ mFirstTaskIconScaledDown = isScaledDown;
+ applyIconScale(animate);
+ }
+
+ private void applyIconScale(boolean animate) {
+ float scale = mFirstTaskIconScaledDown ? 0 : 1;
+ TaskView firstTask = (TaskView) getChildAt(0);
+ if (firstTask != null) {
+ if (animate) {
+ firstTask.animateIconToScale(scale);
+ } else {
+ firstTask.setIconScale(scale);
+ }
+ }
+ }
+
+ public interface PageCallbacks {
+
+ /**
+ * Updates the page UI based on scroll params.
+ */
+ default void onPageScroll(ScrollState scrollState) {};
+ }
+
+ public static class ScrollState {
+
+ /**
+ * The progress from 0 to 1, where 0 is the center
+ * of the screen and 1 is the edge of the screen.
+ */
+ public float linearInterpolation;
+ }
+
+ public void addIgnoreResetTask(TaskView taskView) {
+ mIgnoreResetTaskViews.add(taskView);
+ }
+
+ public void removeIgnoreResetTask(TaskView taskView) {
+ mIgnoreResetTaskViews.remove(taskView);
+ }
+
+ public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
+ boolean removeTask, long duration) {
+ if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) {
+ throw new IllegalStateException("Another pending animation is still running");
+ }
+ AnimatorSet anim = new AnimatorSet();
+ PendingAnimation pendingAnimation = new PendingAnimation(anim);
+
+ int count = getChildCount();
+ if (count == 0) {
+ return pendingAnimation;
+ }
+
+ int[] oldScroll = new int[count];
+ getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
+
+ int[] newScroll = new int[count];
+ getPageScrolls(newScroll, false, (v) -> v.getVisibility() != GONE && v != taskView);
+
+ int maxScrollDiff = 0;
+ int lastPage = mIsRtl ? 0 : count - 1;
+ if (getChildAt(lastPage) == taskView) {
+ if (count > 1) {
+ int secondLastPage = mIsRtl ? 1 : count - 2;
+ maxScrollDiff = oldScroll[lastPage] - newScroll[secondLastPage];
+ }
+ }
+
+ boolean needsCurveUpdates = false;
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child == taskView) {
+ if (animateTaskView) {
+ addAnim(ObjectAnimator.ofFloat(taskView, ALPHA, 0), duration, ACCEL_2, anim);
+ addAnim(ObjectAnimator.ofFloat(taskView, TRANSLATION_Y, -taskView.getHeight()),
+ duration, LINEAR, anim);
+ }
+ } else {
+ int scrollDiff = newScroll[i] - oldScroll[i] + maxScrollDiff;
+ if (scrollDiff != 0) {
+ addAnim(ObjectAnimator.ofFloat(child, TRANSLATION_X, scrollDiff),
+ duration, ACCEL, anim);
+ needsCurveUpdates = true;
+ }
+ }
+ }
+
+ if (needsCurveUpdates) {
+ ValueAnimator va = ValueAnimator.ofFloat(0, 1);
+ va.addUpdateListener((a) -> updateCurveProperties());
+ anim.play(va);
+ }
+
+ // Add a tiny bit of translation Z, so that it draws on top of other views
+ if (animateTaskView) {
+ taskView.setTranslationZ(0.1f);
+ }
+
+ mPendingAnimation = pendingAnimation;
+ mPendingAnimation.addEndListener((isSuccess) -> {
+ if (isSuccess) {
+ if (removeTask) {
+ ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
+ }
+ removeView(taskView);
+ if (getChildCount() == 0) {
+ onAllTasksRemoved();
+ }
+ }
+ resetTaskVisuals();
+ mPendingAnimation = null;
+ });
+ return pendingAnimation;
+ }
+
+ private static void addAnim(ObjectAnimator anim, long duration,
+ TimeInterpolator interpolator, AnimatorSet set) {
+ anim.setDuration(duration).setInterpolator(interpolator);
+ set.play(anim);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_TAB
+ && event.getAction() == KeyEvent.ACTION_DOWN) {
+ snapToPage((getNextPage()
+ + (event.isShiftPressed() ? getPageCount() - 1 : 1)) % getPageCount());
+ loadVisibleTaskData();
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ public void snapToTaskAfterNext() {
+ snapToPage((getNextPage() + 1) % getPageCount());
+ loadVisibleTaskData();
+ }
+
+ public void launchNextTask() {
+ final TaskView nextTask = (TaskView) getChildAt(getNextPage());
+ nextTask.launchTask(true);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
similarity index 87%
rename from quickstep/src/com/android/quickstep/TaskMenuView.java
rename to quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 6bbcb37..30cbcdf 100644
--- a/quickstep/src/com/android/quickstep/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.quickstep;
+package com.android.quickstep.views;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -32,14 +32,16 @@
import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
-import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.shortcuts.DeepShortcutView;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.TaskSystemShortcut;
+import com.android.quickstep.TaskUtils;
/**
* Contains options for a recent task when long-pressing its icon.
@@ -58,7 +60,7 @@
private static final long OPEN_CLOSE_DURATION = 220;
- private Launcher mLauncher;
+ private BaseDraggingActivity mActivity;
private TextView mTaskIconAndName;
private AnimatorSet mOpenCloseAnimator;
private TaskView mTaskView;
@@ -70,7 +72,7 @@
public TaskMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
+ mActivity = BaseDraggingActivity.fromContext(context);
setClipToOutline(true);
setOutlineProvider(new ViewOutlineProvider() {
@Override
@@ -90,7 +92,7 @@
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- DragLayer dl = mLauncher.getDragLayer();
+ BaseDragLayer dl = mActivity.getDragLayer();
if (!dl.isEventOverView(this, ev)) {
// TODO: log this once we have a new container type for it?
close(true);
@@ -120,9 +122,9 @@
}
public static boolean showForTask(TaskView taskView) {
- Launcher launcher = Launcher.getLauncher(taskView.getContext());
- final TaskMenuView taskMenuView = (TaskMenuView) launcher.getLayoutInflater().inflate(
- R.layout.task_menu, launcher.getDragLayer(), false);
+ BaseDraggingActivity activity = BaseDraggingActivity.fromContext(taskView.getContext());
+ final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
+ R.layout.task_menu, activity.getDragLayer(), false);
return taskMenuView.populateAndShowForTask(taskView);
}
@@ -130,7 +132,7 @@
if (isAttachedToWindow()) {
return false;
}
- mLauncher.getDragLayer().addView(this);
+ mActivity.getDragLayer().addView(this);
mTaskView = taskView;
addMenuOptions(mTaskView);
orientAroundTaskView(mTaskView);
@@ -143,11 +145,11 @@
int iconSize = getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
icon.setBounds(0, 0, iconSize, iconSize);
mTaskIconAndName.setCompoundDrawables(null, icon, null, null);
- mTaskIconAndName.setText(TaskUtils.getTitle(mLauncher, taskView.getTask()));
+ mTaskIconAndName.setText(TaskUtils.getTitle(getContext(), taskView.getTask()));
mTaskIconAndName.setOnClickListener(v -> close(true));
for (TaskSystemShortcut menuOption : MENU_OPTIONS) {
- OnClickListener onClickListener = menuOption.getOnClickListener(mLauncher, taskView);
+ OnClickListener onClickListener = menuOption.getOnClickListener(mActivity, taskView);
if (onClickListener != null) {
addMenuOption(menuOption, onClickListener);
}
@@ -155,7 +157,7 @@
}
private void addMenuOption(TaskSystemShortcut menuOption, OnClickListener onClickListener) {
- DeepShortcutView menuOptionView = (DeepShortcutView) mLauncher.getLayoutInflater().inflate(
+ DeepShortcutView menuOptionView = (DeepShortcutView) mActivity.getLayoutInflater().inflate(
R.layout.system_shortcut, this, false);
menuOptionView.getIconView().setBackgroundResource(menuOption.iconResId);
menuOptionView.getBubbleText().setText(menuOption.labelResId);
@@ -165,8 +167,8 @@
private void orientAroundTaskView(TaskView taskView) {
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- mLauncher.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
- Rect insets = mLauncher.getDragLayer().getInsets();
+ mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
+ Rect insets = mActivity.getDragLayer().getInsets();
int x = sTempRect.left + (sTempRect.width() - getMeasuredWidth()) / 2 - insets.left;
setX(Utilities.isRtl(getResources()) ? -x : x);
setY(sTempRect.top - mTaskIconAndName.getPaddingTop() - insets.top);
@@ -209,7 +211,7 @@
private void closeComplete() {
mIsOpen = false;
- mLauncher.getDragLayer().removeView(this);
+ mActivity.getDragLayer().removeView(this);
}
private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
similarity index 96%
rename from quickstep/src/com/android/quickstep/TaskThumbnailView.java
rename to quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 9b9c6f2..87bb53b 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.quickstep;
+package com.android.quickstep.views;
import android.content.Context;
import android.content.res.Configuration;
@@ -33,9 +33,10 @@
import android.util.AttributeSet;
import android.view.View;
+import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -74,6 +75,7 @@
mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
mFadeLength = getResources().getDimension(R.dimen.task_fade_length);
mOverlay = TaskOverlayFactory.get(context).createOverlay(this);
+ mPaint.setFilterBitmap(true);
}
public void bind() {
@@ -151,7 +153,8 @@
} else {
final Configuration configuration =
getContext().getApplicationContext().getResources().getConfiguration();
- final DeviceProfile profile = Launcher.getLauncher(getContext()).getDeviceProfile();
+ final DeviceProfile profile = BaseActivity.fromContext(getContext())
+ .getDeviceProfile();
if (configuration.orientation == mThumbnailData.orientation) {
// If we are in the same orientation as the screenshot, just scale it to the
// width of the task view
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
similarity index 74%
rename from quickstep/src/com/android/quickstep/TaskView.java
rename to quickstep/src/com/android/quickstep/views/TaskView.java
index b407f75..c20b577 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -14,10 +14,7 @@
* limitations under the License.
*/
-package com.android.quickstep;
-
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
+package com.android.quickstep.views;
import android.animation.TimeInterpolator;
import android.app.ActivityOptions;
@@ -31,10 +28,11 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
-import com.android.quickstep.RecentsView.PageCallbacks;
-import com.android.quickstep.RecentsView.ScrollState;
+import com.android.quickstep.views.RecentsView.PageCallbacks;
+import com.android.quickstep.views.RecentsView.ScrollState;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -47,17 +45,15 @@
*/
public class TaskView extends FrameLayout implements TaskCallbacks, PageCallbacks {
- /** Designates how "curvy" the carousel is from 0 to 1, where 0 is a straight line. */
- public static final float CURVE_FACTOR = 0.25f;
- /** A circular curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
- public static final TimeInterpolator CURVE_INTERPOLATOR
- = x -> (float) (1 - Math.sqrt(1 - Math.pow(x, 2)));
+ /** A curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
+ private static final TimeInterpolator CURVE_INTERPOLATOR
+ = x -> (float) -Math.cos(x * Math.PI) / 2f + .5f;
/**
* The alpha of a black scrim on a page in the carousel as it leaves the screen.
* In the resting position of the carousel, the adjacent pages have about half this scrim.
*/
- private static final float MAX_PAGE_SCRIM_ALPHA = 0.8f;
+ private static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
private static final long SCALE_ICON_DURATION = 120;
@@ -115,7 +111,8 @@
if (mTask != null) {
final ActivityOptions opts;
if (animate) {
- opts = Launcher.getLauncher(getContext()).getActivityLaunchOptions(this, false);
+ opts = BaseDraggingActivity.fromContext(getContext())
+ .getActivityLaunchOptions(this, false);
} else {
opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0);
}
@@ -159,38 +156,16 @@
setScaleY(1f);
setTranslationX(0f);
setTranslationY(0f);
+ setTranslationZ(0);
setAlpha(1f);
}
@Override
- public int onPageScroll(ScrollState scrollState) {
+ public void onPageScroll(ScrollState scrollState) {
float curveInterpolation =
CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation);
- float scale = 1 - curveInterpolation * CURVE_FACTOR;
- setScaleX(scale);
- setScaleY(scale);
-
- // Make sure the biggest card (i.e. the one in front) shows on top of the adjacent ones.
- setTranslationZ(scale);
mSnapshotView.setDimAlpha(1 - curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
-
- float translation =
- scrollState.distanceFromScreenCenter * curveInterpolation * CURVE_FACTOR;
-
- if (scrollState.lastScrollType == SCROLL_TYPE_WORKSPACE) {
- // Make sure that the task cards do not overlap with the workspace card
- float min = scrollState.halfPageWidth * (1 - scale);
- if (scrollState.isRtl) {
- setTranslationX(Math.min(translation, min) - scrollState.prevPageExtraWidth);
- } else {
- setTranslationX(Math.max(translation, -min) + scrollState.prevPageExtraWidth);
- }
- } else {
- setTranslationX(translation);
- }
- scrollState.prevPageExtraWidth = 0;
- return SCROLL_TYPE_TASK;
}
private static final class TaskOutlineProvider extends ViewOutlineProvider {
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index d07ff81..4693917 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -44,13 +44,6 @@
layout="@layout/overview_panel"
android:visibility="gone" />
- <!-- DO NOT CHANGE THE ID -->
- <include
- android:id="@+id/hotseat"
- layout="@layout/hotseat"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
<!-- Keep these behind the workspace so that they are not visible when
we go into AllApps -->
<com.android.launcher3.pageindicators.WorkspacePageIndicator
@@ -69,6 +62,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
+
+ <!-- DO NOT CHANGE THE ID -->
+ <include
+ android:id="@+id/hotseat"
+ layout="@layout/hotseat"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
</com.android.launcher3.dragndrop.DragLayer>
</com.android.launcher3.LauncherRootView>
diff --git a/res/layout/launcher_preference.xml b/res/layout/launcher_preference.xml
new file mode 100644
index 0000000..ed0ea7c
--- /dev/null
+++ b/res/layout/launcher_preference.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<com.android.launcher3.views.HighlightableListView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:cacheColorHint="@android:color/transparent"
+ android:clipToPadding="false"
+ android:drawSelectorOnTop="false"
+ android:orientation="vertical"
+ android:scrollbarAlwaysDrawVerticalTrack="true"
+ android:scrollbarStyle="outsideOverlay" />
\ No newline at end of file
diff --git a/quickstep/res/layout/longpress_options_menu.xml b/res/layout/longpress_options_menu.xml
similarity index 96%
rename from quickstep/res/layout/longpress_options_menu.xml
rename to res/layout/longpress_options_menu.xml
index 9cf0fcf..71d117a 100644
--- a/quickstep/res/layout/longpress_options_menu.xml
+++ b/res/layout/longpress_options_menu.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.launcher3.uioverrides.OptionsPopupView
+<com.android.launcher3.views.OptionsPopupView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
@@ -94,4 +94,4 @@
</FrameLayout>
-</com.android.launcher3.uioverrides.OptionsPopupView>
\ No newline at end of file
+</com.android.launcher3.views.OptionsPopupView>
\ No newline at end of file
diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml
index c795b81..bdd5d23 100644
--- a/res/layout/overview_panel.xml
+++ b/res/layout/overview_panel.xml
@@ -14,61 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.launcher3.uioverrides.OverviewPanel
+<Space
xmlns:android="http://schemas.android.com/apk/res/android"
- android:theme="@style/HomeScreenElementTheme"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|bottom"
- android:gravity="top"
- android:orientation="horizontal">
-
- <TextView
- android:id="@+id/wallpaper_button"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:drawablePadding="4dp"
- android:drawableTop="@drawable/ic_wallpaper"
- android:drawableTint="?attr/workspaceTextColor"
- android:fontFamily="sans-serif-condensed"
- android:gravity="center_horizontal"
- android:stateListAnimator="@animator/overview_button_anim"
- android:text="@string/wallpaper_button_text"
- android:textAllCaps="true"
- android:textColor="?attr/workspaceTextColor"
- android:textSize="12sp" />
-
- <TextView
- android:id="@+id/widget_button"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:drawablePadding="4dp"
- android:drawableTop="@drawable/ic_widget"
- android:drawableTint="?attr/workspaceTextColor"
- android:fontFamily="sans-serif-condensed"
- android:gravity="center_horizontal"
- android:stateListAnimator="@animator/overview_button_anim"
- android:text="@string/widget_button_text"
- android:textAllCaps="true"
- android:textColor="?attr/workspaceTextColor"
- android:textSize="12sp" />
-
- <TextView
- android:id="@+id/settings_button"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:drawablePadding="4dp"
- android:drawableTop="@drawable/ic_setting"
- android:drawableTint="?attr/workspaceTextColor"
- android:fontFamily="sans-serif-condensed"
- android:gravity="center_horizontal"
- android:stateListAnimator="@animator/overview_button_anim"
- android:text="@string/settings_button_text"
- android:textAllCaps="true"
- android:textColor="?attr/workspaceTextColor"
- android:textSize="12sp" />
-
-</com.android.launcher3.uioverrides.OverviewPanel>
\ No newline at end of file
+ android:layout_width="0dp"
+ android:layout_height="0dp" />
\ No newline at end of file
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index 91baf7a..eec57a5 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -31,7 +31,6 @@
android:layout_height="@dimen/widget_section_height"
android:background="?android:attr/colorPrimary"
android:drawablePadding="@dimen/widget_section_horizontal_padding"
- android:ellipsize="end"
android:focusable="true"
android:gravity="start|center_vertical"
android:paddingBottom="@dimen/widget_section_vertical_padding"
diff --git a/res/layout/work_tab_bottom_user_education_view.xml b/res/layout/work_tab_bottom_user_education_view.xml
index dc6854e..ba6a939 100644
--- a/res/layout/work_tab_bottom_user_education_view.xml
+++ b/res/layout/work_tab_bottom_user_education_view.xml
@@ -20,6 +20,7 @@
android:layout_gravity="bottom"
android:background="?android:attr/colorAccent"
android:elevation="2dp"
+ android:focusable="true"
android:orientation="horizontal">
<ImageView
@@ -42,6 +43,7 @@
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:layout_gravity="right"
+ android:contentDescription="@string/bottom_work_tab_user_education_close_button"
android:src="@drawable/ic_close"/>
<TextView
diff --git a/res/layout/work_tab_footer.xml b/res/layout/work_tab_footer.xml
index 21ff55e..379e9d0 100644
--- a/res/layout/work_tab_footer.xml
+++ b/res/layout/work_tab_footer.xml
@@ -17,6 +17,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:focusable="true"
android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_bottom_padding"
android:paddingLeft="@dimen/dynamic_grid_cell_padding_x"
android:paddingRight="@dimen/dynamic_grid_cell_padding_x"
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 0aaedca..79fa9f1 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -43,6 +43,10 @@
<string name="out_of_space" msgid="4691004494942118364">"Der er ikke mere plads på denne startskærm."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Der er ikke mere plads i bakken Foretrukne"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Liste med apps"</string>
+ <!-- no translation found for all_apps_button_personal_label (1315764287305224468) -->
+ <skip />
+ <!-- no translation found for all_apps_button_work_label (7270707118948892488) -->
+ <skip />
<string name="all_apps_home_button_label" msgid="252062713717058851">"Startskærm"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Fjern"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Afinstaller"</string>
@@ -77,19 +81,18 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Baggrunde"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Indstillinger for startskærmen"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Deaktiveret af din administrator"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Oversigt"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Tillad rotation af startskærmen"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Når telefonen roteres"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Den aktuelle indstilling for visning tillader ikke rotation"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Underretningscirkler"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Til"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Fra"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Kræver adgang til underretninger"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Hvis du vil se underretningscirkler, skal du aktivere appunderretninger for <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Skift indstillinger"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Vis underretningscirkler"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Føj ikon til startskærmen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For nye apps"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Skift ikonform"</string>
+ <!-- no translation found for icon_shape_override_label_location (3841607380657692863) -->
+ <skip />
<string name="icon_shape_system_default" msgid="1709762974822753030">"Brug systemstandarden"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Kvadrat med runde hjørner"</string>
@@ -119,9 +122,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Opret mappe med: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Mappen blev oprettet"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Flyt til startskærmen"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Flyt skærmen til venstre"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Flyt skærmen til højre"</string>
- <string name="screen_moved" msgid="266230079505650577">"Skærmen er flyttet"</string>
<string name="action_resize" msgid="1802976324781771067">"Tilpas størrelse"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Øg bredden"</string>
<string name="action_increase_height" msgid="459390020612501122">"Øg højden"</string>
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Arbejde"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbejdsprofil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find arbejdsapps her"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Alle arbejdsapps har et badge og beskyttes af din organisation. Flyt apps til din startskærm, så du nemmere kan få adgang til dem."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Administreret af din organisation"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Underretninger og apps er slået fra"</string>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 21c9706..b07d9a2 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"Δεν υπάρχει χώρος σε αυτήν την αρχική οθόνη."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Δεν υπάρχει επιπλέον χώρος στην περιοχή Αγαπημένα"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Λίστα εφαρμογών"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Λίστα προσωπικών εφαρμογών"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Λίστα εφαρμογών εργασίας"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Αρχική οθόνη"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Κατάργηση"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Απεγκατάσταση"</string>
@@ -77,19 +79,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Ταπετσαρίες"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Ρυθμίσεις Αρχικής σελίδας"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Απενεργοποιήθηκε από τον διαχειριστή σας"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Επισκόπηση"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Να επιτρέπεται η περιστροφή της αρχικής οθόνης"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Όταν το τηλέφωνο περιστρέφεται"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Η τρέχουσα ρύθμιση οθόνης δεν επιτρέπει την περιστροφή"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Κουκκίδες ειδοποίησης"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Ενεργή"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Ανενεργή"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Απαιτείται πρόσβαση στις ειδοποιήσεις"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Για να εμφανιστούν οι Κουκκίδες ειδοποίησης, ενεργοποιήστε τις κουκκίδες εφαρμογής για την εφαρμογή <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Αλλαγή ρυθμίσεων"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Εμφάνιση κουκκίδων ειδοποίησης"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Προσθήκη εικονιδίου στην Αρχική οθόνη"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Για νέες εφαρμογές"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Αλλαγή σχήματος εικονιδίου"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"στην Αρχική οθόνη"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Χρήση προεπιλογής συστήματος"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Τετράγωνο"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Στρογγυλεμένο τετράγωνο"</string>
@@ -119,9 +119,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Δημιουργία φακέλου με: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Δημιουργήθηκε φάκελος"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Μετακίνηση Αρχικής οθόνης"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Μετακίνηση οθόνης αριστερά"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Μετακίνηση οθόνης δεξιά"</string>
- <string name="screen_moved" msgid="266230079505650577">"Η οθόνη μετακινήθηκε"</string>
<string name="action_resize" msgid="1802976324781771067">"Προσαρμογή μεγέθους"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Αύξηση του πλάτους"</string>
<string name="action_increase_height" msgid="459390020612501122">"Αύξηση του ύψους"</string>
@@ -137,8 +134,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Εργασίας"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Προφίλ εργασίας"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Βρείτε όλες τις εφαρμογές εργασίας εδώ"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Κάθε εφαρμογή εργασίας φέρει ένα σήμα και διατηρείται ασφαλής από τον οργανισμό σας. Μετακινήστε τις εφαρμογές εργασίας στην Αρχική οθόνη, για να έχετε πιο εύκολη πρόσβαση."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Διαχειριζόμενο από τον οργανισμό σας"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Οι ειδοποιήσεις και οι εφαρμογές είναι απενεργοποιημένες"</string>
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index c84efc7..0e1004a 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Apps list"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Personal apps list"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Work apps list"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
@@ -77,19 +79,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Overview"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Allow Homescreen rotation"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Current display setting doesn\'t permit rotation"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Show notification dots"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"on Home screen"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -119,9 +119,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Create folder with: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Folder created"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Move to Home screen"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Move screen to left"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Move screen to right"</string>
- <string name="screen_moved" msgid="266230079505650577">"Screen moved"</string>
<string name="action_resize" msgid="1802976324781771067">"Re-size"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Increase width"</string>
<string name="action_increase_height" msgid="459390020612501122">"Increase height"</string>
@@ -137,8 +134,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Each work app has a badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index c84efc7..0e1004a 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Apps list"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Personal apps list"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Work apps list"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
@@ -77,19 +79,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Overview"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Allow Homescreen rotation"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Current display setting doesn\'t permit rotation"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Show notification dots"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"on Home screen"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -119,9 +119,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Create folder with: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Folder created"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Move to Home screen"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Move screen to left"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Move screen to right"</string>
- <string name="screen_moved" msgid="266230079505650577">"Screen moved"</string>
<string name="action_resize" msgid="1802976324781771067">"Re-size"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Increase width"</string>
<string name="action_increase_height" msgid="459390020612501122">"Increase height"</string>
@@ -137,8 +134,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Each work app has a badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index c84efc7..0e1004a 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Apps list"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Personal apps list"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Work apps list"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
@@ -77,19 +79,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Overview"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Allow Homescreen rotation"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Current display setting doesn\'t permit rotation"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Show notification dots"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"on Home screen"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -119,9 +119,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Create folder with: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Folder created"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Move to Home screen"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Move screen to left"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Move screen to right"</string>
- <string name="screen_moved" msgid="266230079505650577">"Screen moved"</string>
<string name="action_resize" msgid="1802976324781771067">"Re-size"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Increase width"</string>
<string name="action_increase_height" msgid="459390020612501122">"Increase height"</string>
@@ -137,8 +134,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Each work app has a badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 0fb401a..b2be7c4 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"No queda espacio en la pantalla de inicio."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"La bandeja de favoritos está completa"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Lista de aplicaciones"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista de aplicaciones personales"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicaciones del trabajo"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Inicio"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
@@ -77,19 +79,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Ajustes de Home"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Inhabilitada por el administrador"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Visión general"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir rotación de la pantalla de inicio"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Al girar el teléfono"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"La configuración de pantalla actual no permite girar la pantalla"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Puntos de notificación"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Activada"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivada"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Se necesita acceso a las notificaciones"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar burbujas de notificación, activa las notificaciones de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Cambiar ajustes"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostrar burbujas de notificación"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Añadir icono a la pantalla de inicio"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para aplicaciones nuevas"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Cambiar forma de los iconos"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"en la pantalla de inicio"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Usar opción predeterminada del sistema"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Cuadrado"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Cuadrado con esquinas redondeadas"</string>
@@ -119,9 +119,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Crear carpeta con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Carpeta creada"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Mover a la pantalla de inicio"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Mover pantalla a la izquierda"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Mover pantalla a la derecha"</string>
- <string name="screen_moved" msgid="266230079505650577">"Pantalla movida"</string>
<string name="action_resize" msgid="1802976324781771067">"Modificar tamaño"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Aumentar ancho"</string>
<string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
@@ -137,8 +134,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Trabajo"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Aplicaciones de trabajo"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Cada aplicación de trabajo tiene una insignia y está protegida por tu organización. Mueve las aplicaciones a la pantalla de inicio para acceder a ellas más fácilmente."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Administrada por tu organización"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Las notificaciones y las aplicaciones están desactivadas"</string>
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 89e57e7..5794af1 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"Tidak ada ruang lagi pada layar Utama ini."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Tidak ada ruang tersisa di baki Favorit"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Daftar aplikasi"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Daftar aplikasi pribadi"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Daftar aplikasi kantor"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Layar Utama"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Hapus"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstal"</string>
@@ -77,19 +79,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpaper"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Setelan layar Utama"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dinonaktifkan oleh admin"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Ringkasan"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Izinkan layar Utama diputar"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Saat ponsel diputar"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Setelan Tampilan Saat Ini tidak memungkinkan putaran"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Titik notifikasi"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktif"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Nonaktif"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Perlu akses notifikasi"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Guna menampilkan Titik Notifikasi, aktifkan notifikasi aplikasi untuk <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Ubah setelan"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Tampilkan titik notifikasi"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Tambahkan ikon ke Layar utama"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Untuk aplikasi baru"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Ubah bentuk ikon"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"di layar Utama"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Gunakan default sistem"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Persegi"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Persegi bundar"</string>
@@ -119,9 +119,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Buat folder dengan: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Folder dibuat"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Pindahkan ke layar Utama"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Pindahkan layar ke kiri"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Pindahkan layar ke kanan"</string>
- <string name="screen_moved" msgid="266230079505650577">"Layar dipindahkan"</string>
<string name="action_resize" msgid="1802976324781771067">"Ubah ukuran"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Tambahi lebar"</string>
<string name="action_increase_height" msgid="459390020612501122">"Tambahi tinggi"</string>
@@ -137,8 +134,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Kantor"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Temukan aplikasi kerja di sini"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Setiap aplikasi kerja memiliki badge dan dibuat tetap aman oleh organisasi. Pindahkan aplikasi ke Layar utama untuk memudahkan akses."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Dikelola oleh organisasi"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifikasi dan aplikasi nonaktif"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 8584629..c220dec 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"Spazio nella schermata Home esaurito."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Spazio esaurito nella barra dei Preferiti"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Elenco di app"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Elenco di app personali"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Elenco di app di lavoro"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Home page"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Rimuovi"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Disinstalla"</string>
@@ -77,19 +79,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Sfondi"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Impostazioni Home"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disattivata dall\'amministratore"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Panoramica"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Consenti rotazione della schermata Home"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Con il telefono ruotato"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"L\'impostazione corrente del display non consente la rotazione"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Indicatori notifica"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Attiva"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Non attiva"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Accesso alle notifiche necessario"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Per mostrare gli indicatori di notifica, attiva le notifiche per l\'app <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Modifica impostazioni"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostra indicatori di notifica"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Aggiungi icone alla schermata Home"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Per le nuove app"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Cambia la forma delle icone"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"nella schermata Home"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Usa impostazione predefinita di sistema"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Quadrato"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Supercerchio"</string>
@@ -119,9 +119,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Crea cartella con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Cartella creata"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Sposta nella schermata Home"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Sposta schermata a sinistra"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Sposta schermata a destra"</string>
- <string name="screen_moved" msgid="266230079505650577">"Schermata spostata"</string>
<string name="action_resize" msgid="1802976324781771067">"Ridimensiona"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Aumenta larghezza"</string>
<string name="action_increase_height" msgid="459390020612501122">"Aumenta altezza"</string>
@@ -137,8 +134,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Lavoro"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profilo di lavoro"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Qui puoi trovare le tue app di lavoro"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Ogni app di lavoro è contrassegnata da un badge e viene tenuta al sicuro dalla tua organizzazione. Sposta le app nella schermata Home per accedervi più facilmente."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Gestito dalla tua organizzazione"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Le notifiche e le app non sono attive"</string>
</resources>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 40ffffe..6cf23ad 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -25,7 +25,6 @@
<dimen name="fastscroll_popup_text_size">24dp</dimen>
<!-- Dynamic grid -->
- <dimen name="dynamic_grid_overview_bar_item_width">120dp</dimen>
<dimen name="dynamic_grid_min_page_indicator_size">48dp</dimen>
<dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index c004318..e862116 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"ဤပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"အနှစ်သက်ဆုံးများ ထားရာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"အက်ပ်စာရင်း"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ကိုယ်ရေးကိုယ်တာ အက်ပ်စာရင်း"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"အလုပ်သုံး အက်ပ်စာရင်း"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"ပင်မစာမျက်နှာ"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"ဖယ်ရှားမည်"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ဖယ်ထုတ်မည်"</string>
@@ -77,19 +79,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"နောက်ခံများ"</string>
<string name="settings_button_text" msgid="8873672322605444408">"ပင်မဆက်တင်များ"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"သင့်စီမံခန့်ခွဲသူက ပိတ်လိုက်ပါသည်"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"ခြုံငုံသုံးသပ်ချက်"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"ပင်မစာမျက်နှာလှည့်ခြင်းကို ခွင့်ပြုပါ"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"ဖုန်းကိုလှည့်ထားစဉ်"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"လက်ရှိ မြင်ကွင်းဆက်တင်တွင် မြင်ကွင်းကို လှည့်ခွင့်မပေးပါ"</string>
<string name="icon_badging_title" msgid="874121399231955394">"အကြောင်းကြားချက်အမှတ်အသားများ"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"ဖွင့်ထားသည်"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"ပိတ်ထားသည်"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"အကြောင်းကြားချက် အသုံးပြုခွင့် လိုအပ်သည်"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"အကြောင်းကြားချက် အစက်များကို ပြသရန် <xliff:g id="NAME">%1$s</xliff:g> အတွက် အက်ပ်အကြောင်းကြားချက်များကို ဖွင့်ပါ"</string>
<string name="title_change_settings" msgid="1376365968844349552">"ဆက်တင်များ ပြောင်းရန်"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"အကြောင်းကြားချက် အမှတ်အသားများကို ပြရန်"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ပင်မစာမျက်နှာသို့ သင်္ကေတပုံ ထည့်ရန်"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"အက်ပ်အသစ်များအတွက်"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"သင်္ကေတပုံစံကို ပြောင်းရန်"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"\'ပင်မမျက်နှာပြင်\' ပေါ်တွင်"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"စနစ်၏ မူရင်းပုံကို အသုံးပြုရန်"</string>
<string name="icon_shape_square" msgid="633575066111622774">"လေးထောင့်"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"စတုရန်းမကျ စက်ဝိုင်းမကျပုံ"</string>
@@ -119,9 +119,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"ဖိုလ်ဒါ ပြုလုပ်ရန်- <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"ဖိုလ်ဒါ ပြုလုပ်ပြီး"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"ပင်မမျက်နှာပြင်သို့ ရွှေ့ပါ"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"မျက်နှာပြင် ဘယ်ဘက်သို့ ရွှေ့ပါ"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"မျက်နှာပြင် ညာဘက်သို့ ရွှေ့ပါ"</string>
- <string name="screen_moved" msgid="266230079505650577">"ဖန်မျက်နှာပြင် ပြောင်းရွှေ့ပြီး၏"</string>
<string name="action_resize" msgid="1802976324781771067">"အရွယ်အစားပြောင်းပါ"</string>
<string name="action_increase_width" msgid="8773715375078513326">"အကျယ်အား တိုးပါ"</string>
<string name="action_increase_height" msgid="459390020612501122">"အမြင့်အား တိုးပါ"</string>
@@ -137,8 +134,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"အလုပ်"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"အလုပ်ပရိုဖိုင်"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"အလုပ်အက်ပ်များကို ဤနေရာတွင်ရှာဖွေပါ"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"အလုပ်အက်ပ်တိုင်းတွင် တံဆိပ် တစ်ခုစီရှိပြီး သင်၏ အဖွဲ့အစည်းက လုံခြုံအောင် ထားရှိပါသည်။ အသုံးပြုရ ပိုမိုလွယ်ကူစေရန် အက်ပ်များကို သင်၏ ပင်မမျက်နှာပြင်သို့ ရွှေ့ပါ။"</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"သင်၏ အဖွဲ့အစည်းက စီမံခန့်ခွဲထားပါသည်"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"အကြောင်းကြားချက်များနှင့် အက်ပ်များကို ပိတ်ထားသည်"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 77aeee2..e9b4cc9 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"Brak miejsca na tym ekranie głównym."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Brak miejsca w Ulubionych"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Lista aplikacji"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista aplikacji osobistych"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista aplikacji do pracy"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Ekran główny"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Usuń"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstaluj"</string>
@@ -79,19 +81,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Ustawienia strony głównej"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Funkcja wyłączona przez administratora"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Przegląd"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Zezwalaj na obrót ekranu głównego"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Po obróceniu telefonu"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Obecne ustawienia wyświetlania nie pozwalają na obrót ekranu"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Plakietki z powiadomieniami"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Włączono"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Wyłączono"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Wymagany jest dostęp do powiadomień"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Aby pokazać plakietki z powiadomieniami, włącz powiadomienia aplikacji <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Zmień ustawienia"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Pokaż plakietki z powiadomieniami"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonę do ekranu głównego"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"W przypadku nowych aplikacji"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Zmień kształt ikon"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na ekranie głównym"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Użyj ustawienia domyślnego"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kwadrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Zaokrąglony kwadrat"</string>
@@ -121,9 +121,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Utwórz folder z: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Folder został utworzony"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Przenieś na ekran główny"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Przenieś ekran w lewo"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Przenieś ekran w prawo"</string>
- <string name="screen_moved" msgid="266230079505650577">"Ekran został przeniesiony"</string>
<string name="action_resize" msgid="1802976324781771067">"Zmień rozmiar"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Zwiększ szerokość"</string>
<string name="action_increase_height" msgid="459390020612501122">"Zwiększ wysokość"</string>
@@ -139,8 +136,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Praca"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil służbowy"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Aplikacje do pracy"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Każda aplikacja do pracy ma plakietkę, a o jej bezpieczeństwo dba Twoja organizacja. Aplikacje można przenieść na ekran główny, by były łatwiej dostępne."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Profil zarządzany przez Twoją organizację"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Powiadomienia i aplikacje są wyłączone"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index cd473fa..d6f67b3 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"Sem espaço suficiente neste Ecrã principal."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Não existe mais espaço no tabuleiro de Favoritos"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Lista de aplicações"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista de aplicações pessoais"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicações de trabalho"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Ecrã principal"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Remover"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
@@ -77,19 +79,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Imagens de fundo"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Definições da página inicial"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Desativada pelo gestor"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Vista geral"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir rotação do ecrã principal"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Quando o telemóvel é rodado"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"A definição de visualização atual não permite a rotação"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Pontos de notificação"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Ativada"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Desativada"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Acesso a notificações necessário"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar os Pontos de notificação, ative as notificações de aplicações para o <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Alterar definições"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostrar pontos de notificação"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adicionar ícone ao ecrã principal"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para novas aplicações"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Alterar forma do ícone"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"no ecrã principal"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Utilizar a predefinição do sistema"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Quadrado"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Quadrado e círculo"</string>
@@ -119,9 +119,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Criar pasta com: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Pasta criada"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Mover para o Ecrã principal"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Mover ecrã para a esquerda"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Mover ecrã para a direita"</string>
- <string name="screen_moved" msgid="266230079505650577">"Ecrã movido"</string>
<string name="action_resize" msgid="1802976324781771067">"Redimensionar"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Aumentar largura"</string>
<string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
@@ -137,8 +134,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Trabalho"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabalho"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Encontrar as aplicações de trabalho aqui"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Cada aplicação de trabalho apresenta um emblema, pelo que a sua entidade a mantém em segurança. Pode mover as aplicações para o ecrã principal para facilitar o acesso."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Gerido pela sua entidade"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"As notificações e as aplicações estão desativadas."</string>
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 495ba4c..fdbcd5b 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"Nu mai este loc pe acest Ecran de pornire."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Spațiu epuizat în bara Preferate"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Lista de aplicații"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista de aplicații personale"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicații de serviciu"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Ecran de pornire"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Eliminați"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Dezinstalați"</string>
@@ -78,19 +80,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Imagini de fundal"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Setări pentru ecranul de pornire"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dezactivată de administrator"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Prezentare generală"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Permiteți rotirea ecranului de pornire"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Când telefonul este rotit"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Setarea actuală a afișajului nu permite rotirea"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Puncte de notificare"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Activat"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Dezactivat"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Este necesar accesul la notificări"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Pentru a afișa punctele de notificare, activați notificările din aplicație pentru <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Modificați setările"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Afișați punctele de notificare"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adaugă pictograme în ecranul de pornire"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pentru aplicații noi"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Schimbați forma pictogramei"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"pe ecranul de pornire"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Folosiți setarea prestabilită a sistemului"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Pătrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Pătrat cu colțuri rotunjite"</string>
@@ -120,9 +120,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Creați dosar cu: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Dosar creat"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Mutați pe ecranul de pornire"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Mutați ecranul la stânga"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Mutați ecranul la dreapta"</string>
- <string name="screen_moved" msgid="266230079505650577">"Ecran mutat"</string>
<string name="action_resize" msgid="1802976324781771067">"Redimensionați"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Creșteți lățimea"</string>
<string name="action_increase_height" msgid="459390020612501122">"Creșteți înălțimea"</string>
@@ -138,8 +135,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Profesionale"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil de serviciu"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Găsiți aplicații de serviciu aici"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Fiecare aplicație de serviciu are o insignă și este păstrată în siguranță de organizația dvs. Mutați aplicațiile pe ecranul de pornire pentru acces mai ușor."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Gestionat de organizația dvs."</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Notificările și aplicațiile sunt dezactivate"</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 85e814b..9d153f4 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"Det finns inte plats för mer på den här startskärmen."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritfältet är fullt"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Applista"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Listan Personliga appar"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Listan Jobbappar"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Startskärm"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Ta bort"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstallera"</string>
@@ -77,19 +79,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Bakgrunder"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Inställningar för startsidan"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Inaktiverat av administratören"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Översikt"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Tillåt rotering av startskärmen"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"När mobilen vrids"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Rotering tillåts inte i de nuvarande skärminställningarna"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Aviseringsprickar"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"På"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Av"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Åtkomst till aviseringar krävs"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Aktivera appaviseringar för <xliff:g id="NAME">%1$s</xliff:g> om du vill att aviseringsprickar ska visas"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Ändra inställningar"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Visa aviseringsprickar"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Lägg till ikonen på startskärmen"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"För nya appar"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Ändra form på ikoner"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"på startskärmen"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Använd systemstandard"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Kvirkel"</string>
@@ -119,9 +119,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Skapa mapp med: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Mappen har skapats"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Flytta till startskärmen"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Flytta skärmen till vänster"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Flytta skärmen till höger"</string>
- <string name="screen_moved" msgid="266230079505650577">"Skärmen har flyttats"</string>
<string name="action_resize" msgid="1802976324781771067">"Ändra storlek"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Öka bredden"</string>
<string name="action_increase_height" msgid="459390020612501122">"Öka höjden"</string>
@@ -137,8 +134,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Arbete"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Jobbprofil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Här hittar du jobbappar"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Alla jobbappar har ett märke och organisationen ser till att de är skyddade. Flytta apparna till startskärmen så kommer du åt dem lättare."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Hanteras av organisationen"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Aviseringar och appar är inaktiverade"</string>
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index a9dc8a6..da0bb8e 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -43,6 +43,8 @@
<string name="out_of_space" msgid="4691004494942118364">"Hakuna nafasi katika skrini hii ya Mwanzo."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Hakuna nafasi zaidi katika treya ya Vipendeleo"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Orodha ya programu"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Orodha ya programu za binafsi"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Orodha ya programu za kazini"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Mwanzo"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Ondoa"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ondoa"</string>
@@ -79,19 +81,17 @@
<string name="wallpaper_button_text" msgid="8404103075899945851">"Mandhari"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Mipangilio ya ukurasa wa mwanzo"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Imezimwa na msimamizi wako"</string>
- <string name="accessibility_action_overview" msgid="6257665857640347026">"Muhtasari"</string>
- <string name="allow_rotation_title" msgid="7728578836261442095">"Ruhusu kuzungusha skrini ya Kwanza"</string>
- <string name="allow_rotation_desc" msgid="8662546029078692509">"Simu inapozungushwa"</string>
- <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Mipangilio ya sasa ya sehemu ya Onyesho hairuhusu kuzungusha"</string>
<string name="icon_badging_title" msgid="874121399231955394">"Vitone vya arifa"</string>
<string name="icon_badging_desc_on" msgid="2627952638544674079">"Imewashwa"</string>
<string name="icon_badging_desc_off" msgid="5503319969924580241">"Imezimwa"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Inahitaji idhini ya kufikia arifa"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Ili kuonyesha Vitone vya Arifa, washa kipengele cha arifa za programu katika <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Badilisha mipangilio"</string>
+ <string name="icon_badging_service_title" msgid="2309733118428242174">"Onyesha kitone cha arifa"</string>
<string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ongeza aikoni kwenye Skrini ya kwanza"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Kwa ajili ya programu mpya"</string>
<string name="icon_shape_override_label" msgid="2977264953998281004">"Badilisha umbo la aikoni"</string>
+ <string name="icon_shape_override_label_location" msgid="3841607380657692863">"kwenye Skrini ya mwanzo"</string>
<string name="icon_shape_system_default" msgid="1709762974822753030">"Tumia umbo chaguo-msingi la mfumo"</string>
<string name="icon_shape_square" msgid="633575066111622774">"Mraba"</string>
<string name="icon_shape_squircle" msgid="5658049910802669495">"Mstatili wenye pembe duara"</string>
@@ -121,9 +121,6 @@
<string name="create_folder_with" msgid="4050141361160214248">"Unda folda ukitumia: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_created" msgid="6409794597405184510">"Folda imeundwa"</string>
<string name="action_move_to_workspace" msgid="1603837886334246317">"Hamishia Skrini ya kwanza"</string>
- <string name="action_move_screen_left" msgid="8854216831569401665">"Sogeza skrini kushoto"</string>
- <string name="action_move_screen_right" msgid="329334910274311123">"Sogeza skrini kulia"</string>
- <string name="screen_moved" msgid="266230079505650577">"Skrini imesogezwa"</string>
<string name="action_resize" msgid="1802976324781771067">"Badilisha ukubwa"</string>
<string name="action_increase_width" msgid="8773715375078513326">"Ongeza upana"</string>
<string name="action_increase_height" msgid="459390020612501122">"Ongeza urefu"</string>
@@ -139,8 +136,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Kazini"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Wasifu wa kazini"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Pata programu za kazi hapa"</string>
- <!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) -->
- <skip />
+ <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Kila programu ya kazi ina beji na hulindwa na shirika lako. Hamishia programu kwenye skrini yako ya kwanza ili uzifikie kwa urahisi."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"Inasimamiwa na shirika lako"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Vipenge vya arifa na programu vimezimwa"</string>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 3f727cf..a40afe1 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -119,6 +119,10 @@
<!-- Tag id used for view scrim -->
<item type="id" name="view_scrim" />
+ <!-- View IDs to store item highlight information -->
+ <item type="id" name="view_unhighlight_background" />
+ <item type="id" name="view_highlighted" />
+
<!-- Popup items -->
<integer name="config_popupOpenCloseDuration">150</integer>
<integer name="config_popupArrowOpenDuration">80</integer>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9f4233c..f8f9c2a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -23,10 +23,6 @@
<dimen name="dynamic_grid_min_page_indicator_size">24dp</dimen>
<dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
<dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
- <dimen name="dynamic_grid_overview_min_icon_zone_height">80dp</dimen>
- <dimen name="dynamic_grid_overview_max_icon_zone_height">120dp</dimen>
- <dimen name="dynamic_grid_overview_bar_item_width">80dp</dimen>
- <dimen name="dynamic_grid_overview_bar_spacer_width">25dp</dimen>
<dimen name="dynamic_grid_workspace_top_padding">8dp</dimen>
<dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
<!-- Minimum space between workspace and hotseat in spring loaded mode -->
@@ -227,5 +223,5 @@
<dimen name="swipe_helper_falsing_threshold">70dp</dimen>
<!-- Overview -->
- <dimen name="options_menu_icon_size">48dp</dimen>
+ <dimen name="options_menu_icon_size">24dp</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d8b68e7..0b45b8e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -80,6 +80,9 @@
<!-- All applications label -->
<string name="all_apps_button_label">Apps list</string>
+ <string name="all_apps_button_personal_label">Personal apps list</string>
+ <string name="all_apps_button_work_label">Work apps list</string>
+
<!-- Label for button in all applications label to go back home (to the workspace / desktop)
for accessibilty (spoken when the button gets focus). -->
<string name="all_apps_home_button_label">Home</string>
@@ -169,8 +172,6 @@
<string name="settings_button_text">Home settings</string>
<!-- Message shown when a feature is disabled by the administrator -->
<string name="msg_disabled_by_admin">Disabled by your admin</string>
- <!-- Text for custom accessibility action to go to the overview mode, where users can look and change the overall UI of the launcher. -->
- <string name="accessibility_action_overview">Overview</string>
<!-- Strings for settings -->
<!-- Title for Notification dots setting. Tapping this will link to the system Notifications settings screen where the user can turn off notification dots globally. [CHAR LIMIT=50] -->
@@ -195,6 +196,8 @@
<!-- Developer setting to change the shape of icons on home screen. [CHAR LIMIT=50] -->
<string name="icon_shape_override_label">Change icon shape</string>
+ <!-- Subtext explaining that the icons will only be affected on the home screen. This text follows the actual icon action: Change icon shape, on Home screen [CHAR LIMIT=100] -->
+ <string name="icon_shape_override_label_location">on Home screen</string>
<!-- Option to not change the icon shape on home screen and use the system default setting instead. [CHAR LIMIT=50] -->
<string name="icon_shape_system_default">Use system default</string>
<!-- Option to change the shape of the home screen icons to a square. [CHAR LIMIT=50] -->
@@ -278,15 +281,6 @@
<!-- Accessibility action to move an item from folder to workspace. [CHAR_LIMIT=30] -->
<string name="action_move_to_workspace">Move to Home screen</string>
- <!-- Accessibility action to move an homescreen to the left. [CHAR_LIMIT=30] -->
- <string name="action_move_screen_left">Move screen to left</string>
-
- <!-- Accessibility action to move an homescreen to the right. [CHAR_LIMIT=30] -->
- <string name="action_move_screen_right">Move screen to right</string>
-
- <!-- Accessibility confirmation when a screen was moved. -->
- <string name="screen_moved">Screen moved</string>
-
<!-- Accessibility action to resize a widget. [CHAR_LIMIT=30] -->
<string name="action_resize">Resize</string>
@@ -336,5 +330,6 @@
<string name="work_mode_on_label">Managed by your organization</string>
<!-- This string appears under a the label of a toggle in the work profile tab on a user's phone. It describes the status of the toggle, "Work profile," when it's turned off. "Work profile" means a separate profile on a user's phone that's speficially for their work apps and is managed by their company.-->
<string name="work_mode_off_label">Notifications and apps are off</string>
-
+ <string name="bottom_work_tab_user_education_close_button">Close</string>
+ <string name="bottom_work_tab_user_education_closed">Closed</string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ac6a6b1..8076c80 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -112,7 +112,6 @@
<item name="android:focusable">true</item>
<item name="android:gravity">center_horizontal</item>
<item name="android:singleLine">true</item>
- <item name="android:ellipsize">marquee</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:fontFamily">sans-serif-condensed</item>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index fc5ce8f..f34cf0d 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -24,9 +24,9 @@
import android.view.View;
import android.widget.LinearLayout;
-import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.BaseDragLayer;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -92,7 +92,7 @@
public final void close(boolean animate) {
animate &= !Utilities.isPowerSaverOn(getContext());
handleClose(animate);
- Launcher.getLauncher(getContext()).getUserEventDispatcher()
+ BaseActivity.fromContext(getContext()).getUserEventDispatcher()
.resetElapsedContainerMillis("container closed");
}
@@ -120,8 +120,8 @@
}
protected static <T extends AbstractFloatingView> T getOpenView(
- Launcher launcher, @FloatingViewType int type) {
- DragLayer dragLayer = launcher.getDragLayer();
+ BaseDraggingActivity activity, @FloatingViewType int type) {
+ BaseDragLayer dragLayer = activity.getDragLayer();
// Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
// and will be one of the last views.
for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
@@ -136,16 +136,17 @@
return null;
}
- public static void closeOpenContainer(Launcher launcher, @FloatingViewType int type) {
- AbstractFloatingView view = getOpenView(launcher, type);
+ public static void closeOpenContainer(BaseDraggingActivity activity,
+ @FloatingViewType int type) {
+ AbstractFloatingView view = getOpenView(activity, type);
if (view != null) {
view.close(true);
}
}
- public static void closeOpenViews(Launcher launcher, boolean animate,
+ public static void closeOpenViews(BaseDraggingActivity activity, boolean animate,
@FloatingViewType int type) {
- DragLayer dragLayer = launcher.getDragLayer();
+ BaseDragLayer dragLayer = activity.getDragLayer();
// Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
// and will be one of the last views.
for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
@@ -159,16 +160,16 @@
}
}
- public static void closeAllOpenViews(Launcher launcher, boolean animate) {
- closeOpenViews(launcher, animate, TYPE_ALL);
- launcher.finishAutoCancelActionMode();
+ public static void closeAllOpenViews(BaseDraggingActivity activity, boolean animate) {
+ closeOpenViews(activity, animate, TYPE_ALL);
+ activity.finishAutoCancelActionMode();
}
- public static void closeAllOpenViews(Launcher launcher) {
- closeAllOpenViews(launcher, true);
+ public static void closeAllOpenViews(BaseDraggingActivity activity) {
+ closeAllOpenViews(activity, true);
}
- public static AbstractFloatingView getTopOpenView(Launcher launcher) {
- return getOpenView(launcher, TYPE_ALL);
+ public static AbstractFloatingView getTopOpenView(BaseDraggingActivity activity) {
+ return getOpenView(activity, TYPE_ALL);
}
}
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 12db3b6..02d70c4 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -20,6 +20,8 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
+import android.graphics.Point;
+import android.view.Display;
import android.view.View.AccessibilityDelegate;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
@@ -96,10 +98,26 @@
mDPChangeListeners.add(listener);
}
+ public void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
+ mDPChangeListeners.remove(listener);
+ }
+
protected void dispatchDeviceProfileChanged() {
- int count = mDPChangeListeners.size();
- for (int i = 0; i < count; i++) {
+ for (int i = mDPChangeListeners.size() - 1; i >= 0; i--) {
mDPChangeListeners.get(i).onDeviceProfileChanged(mDeviceProfile);
}
}
+
+ /**
+ * Sets the device profile, adjusting it accordingly in case of multi-window
+ */
+ protected void setDeviceProfile(DeviceProfile dp) {
+ mDeviceProfile = dp;
+ if (isInMultiWindowModeCompat()) {
+ Display display = getWindowManager().getDefaultDisplay();
+ Point mwSize = new Point();
+ display.getSize(mwSize);
+ mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
+ }
+ }
}
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
new file mode 100644
index 0000000..458f7b2
--- /dev/null
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.app.ActivityOptions;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.StrictMode;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.ActionMode;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.badge.BadgeInfo;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.views.BaseDragLayer;
+
+/**
+ * Extension of BaseActivity allowing support for drag-n-drop
+ */
+public abstract class BaseDraggingActivity extends BaseActivity {
+
+ private static final String TAG = "BaseDraggingActivity";
+
+ // The Intent extra that defines whether to ignore the launch animation
+ private static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
+ "com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
+
+ // When starting an action mode, setting this tag will cause the action mode to be cancelled
+ // automatically when user interacts with the launcher.
+ public static final Object AUTO_CANCEL_ACTION_MODE = new Object();
+
+ private ActionMode mCurrentActionMode;
+ protected boolean mIsSafeModeEnabled;
+
+ private OnStartCallback mOnStartCallback;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mIsSafeModeEnabled = getPackageManager().isSafeMode();
+ }
+
+ @Override
+ public void onActionModeStarted(ActionMode mode) {
+ super.onActionModeStarted(mode);
+ mCurrentActionMode = mode;
+ }
+
+ @Override
+ public void onActionModeFinished(ActionMode mode) {
+ super.onActionModeFinished(mode);
+ mCurrentActionMode = null;
+ }
+
+ public boolean finishAutoCancelActionMode() {
+ if (mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag()) {
+ mCurrentActionMode.finish();
+ return true;
+ }
+ return false;
+ }
+
+ public abstract BaseDragLayer getDragLayer();
+
+ public abstract <T extends View> T getOverviewPanel();
+
+ public abstract View getRootView();
+
+ public abstract BadgeInfo getBadgeInfoForItem(ItemInfo info);
+
+ public abstract void invalidateParent(ItemInfo info);
+
+ public static BaseDraggingActivity fromContext(Context context) {
+ if (context instanceof BaseDraggingActivity) {
+ return (BaseDraggingActivity) context;
+ }
+ return ((BaseDraggingActivity) ((ContextWrapper) context).getBaseContext());
+ }
+
+ public Rect getViewBounds(View v) {
+ int[] pos = new int[2];
+ v.getLocationOnScreen(pos);
+ return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
+ }
+
+ public final Bundle getActivityLaunchOptionsAsBundle(View v, boolean useDefaultLaunchOptions) {
+ ActivityOptions activityOptions = getActivityLaunchOptions(v, useDefaultLaunchOptions);
+ return activityOptions == null ? null : activityOptions.toBundle();
+ }
+
+ public abstract ActivityOptions getActivityLaunchOptions(
+ View v, boolean useDefaultLaunchOptions);
+
+ public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
+ if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
+ Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
+ return false;
+ }
+
+ // Only launch using the new animation if the shortcut has not opted out (this is a
+ // private contract between launcher and may be ignored in the future).
+ boolean useLaunchAnimation = (v != null) &&
+ !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
+ Bundle optsBundle = useLaunchAnimation
+ ? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat())
+ : null;
+
+ UserHandle user = item == null ? null : item.user;
+
+ // Prepare intent
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (v != null) {
+ intent.setSourceBounds(getViewBounds(v));
+ }
+ try {
+ boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
+ && (item instanceof ShortcutInfo)
+ && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
+ || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
+ && !((ShortcutInfo) item).isPromise();
+ if (isShortcut) {
+ // Shortcuts need some special checks due to legacy reasons.
+ startShortcutIntentSafely(intent, optsBundle, item);
+ } else if (user == null || user.equals(Process.myUserHandle())) {
+ // Could be launching some bookkeeping activity
+ startActivity(intent, optsBundle);
+ } else {
+ LauncherAppsCompat.getInstance(this).startActivityForProfile(
+ intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
+ }
+ getUserEventDispatcher().logAppLaunch(v, intent);
+ return true;
+ } catch (ActivityNotFoundException|SecurityException e) {
+ Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+ Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
+ }
+ return false;
+ }
+
+ private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
+ try {
+ StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
+ try {
+ // Temporarily disable deathPenalty on all default checks. For eg, shortcuts
+ // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
+ // is enabled by default on NYC.
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
+ .penaltyLog().build());
+
+ if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ String id = ((ShortcutInfo) info).getDeepShortcutId();
+ String packageName = intent.getPackage();
+ DeepShortcutManager.getInstance(this).startShortcut(
+ packageName, id, intent.getSourceBounds(), optsBundle, info.user);
+ } else {
+ // Could be launching some bookkeeping activity
+ startActivity(intent, optsBundle);
+ }
+ } finally {
+ StrictMode.setVmPolicy(oldPolicy);
+ }
+ } catch (SecurityException e) {
+ if (!onErrorStartingShortcut(intent, info)) {
+ throw e;
+ }
+ }
+ }
+
+ protected boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
+ return false;
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ if (mOnStartCallback != null) {
+ mOnStartCallback.onActivityStart(this);
+ mOnStartCallback = null;
+ }
+ }
+
+ public <T extends BaseDraggingActivity> void setOnStartCallback(OnStartCallback<T> callback) {
+ mOnStartCallback = callback;
+ }
+
+ /**
+ * Callback for listening for onStart
+ */
+ public interface OnStartCallback<T extends BaseDraggingActivity> {
+
+ void onActivityStart(T activity);
+ }
+}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 8b6d9f8..41bfcb7 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -28,6 +28,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.v4.graphics.ColorUtils;
+import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.Property;
import android.util.TypedValue;
@@ -44,7 +45,6 @@
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.badge.BadgeRenderer;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.folder.FolderIconPreviewVerifier;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.graphics.PreloadIconDrawable;
@@ -65,7 +65,7 @@
private static final int[] STATE_PRESSED = new int[] {android.R.attr.state_pressed};
- private final Launcher mLauncher;
+ private final BaseDraggingActivity mActivity;
private Drawable mIcon;
private final boolean mCenterVertically;
@@ -133,8 +133,8 @@
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mLauncher = Launcher.getLauncher(context);
- DeviceProfile grid = mLauncher.getDeviceProfile();
+ mActivity = BaseDraggingActivity.fromContext(context);
+ DeviceProfile grid = mActivity.getDeviceProfile();
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
TypedArray a = context.obtainStyledAttributes(attrs,
@@ -164,10 +164,18 @@
mLongPressHelper = new CheckLongPressHelper(this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
- setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
+ setEllipsize(TruncateAt.END);
+ setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
}
+ @Override
+ protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+ // Disable marques when not focused to that, so that updating text does not cause relayout.
+ setEllipsize(focused ? TruncateAt.MARQUEE : TruncateAt.END);
+ super.onFocusChanged(focused, direction, previouslyFocusedRect);
+ }
+
/**
* Resets the view so it can be recycled.
*/
@@ -420,7 +428,7 @@
}
}
- private void setTextAlpha(int alpha) {
+ public void setTextAlpha(int alpha) {
super.setTextColor(ColorUtils.setAlphaComponent(mTextColor, alpha));
}
@@ -493,10 +501,10 @@
public void applyBadgeState(ItemInfo itemInfo, boolean animate) {
if (mIcon instanceof FastBitmapDrawable) {
boolean wasBadged = mBadgeInfo != null;
- mBadgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo);
+ mBadgeInfo = mActivity.getBadgeInfoForItem(itemInfo);
boolean isBadged = mBadgeInfo != null;
float newBadgeScale = isBadged ? 1f : 0;
- mBadgeRenderer = mLauncher.getDeviceProfile().mBadgeRenderer;
+ mBadgeRenderer = mActivity.getDeviceProfile().mBadgeRenderer;
if (wasBadged || isBadged) {
// Animate when a badge is first added or when it is removed.
if (animate && (wasBadged ^ isBadged) && isShown()) {
@@ -522,31 +530,30 @@
* Sets the icon for this view based on the layout direction.
*/
private void setIcon(Drawable icon) {
- mIcon = icon;
- mIcon.setBounds(0, 0, mIconSize, mIconSize);
if (mIsIconVisible) {
- applyCompoundDrawables(mIcon);
+ applyCompoundDrawables(icon);
}
+ mIcon = icon;
}
public void setIconVisible(boolean visible) {
mIsIconVisible = visible;
- mDisableRelayout = true;
- Drawable icon = mIcon;
- if (!visible) {
- icon = new ColorDrawable(Color.TRANSPARENT);
- icon.setBounds(0, 0, mIconSize, mIconSize);
- }
+ Drawable icon = visible ? mIcon : new ColorDrawable(Color.TRANSPARENT);
applyCompoundDrawables(icon);
- mDisableRelayout = false;
}
protected void applyCompoundDrawables(Drawable icon) {
+ // If we had already set an icon before, disable relayout as the icon size is the
+ // same as before.
+ mDisableRelayout = mIcon != null;
+
+ icon.setBounds(0, 0, mIconSize, mIconSize);
if (mLayoutHorizontal) {
setCompoundDrawablesRelative(icon, null, null, null);
} else {
setCompoundDrawables(null, icon, null, null);
}
+ mDisableRelayout = false;
}
@Override
@@ -572,15 +579,7 @@
applyFromApplicationInfo((AppInfo) info);
} else if (info instanceof ShortcutInfo) {
applyFromShortcutInfo((ShortcutInfo) info);
- FolderIconPreviewVerifier verifier =
- new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv);
- if (verifier.isItemInPreview(info.rank) && (info.container >= 0)) {
- View folderIcon =
- mLauncher.getWorkspace().getHomescreenIconByItemId(info.container);
- if (folderIcon != null) {
- folderIcon.invalidate();
- }
- }
+ mActivity.invalidateParent(info);
} else if (info instanceof PackageItemInfo) {
applyFromPackageItemInfo((PackageItemInfo) info);
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 734aec3..7979082 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -292,7 +292,7 @@
ViewCompat.setAccessibilityDelegate(this, null);
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
- setOnClickListener(mLauncher);
+ setOnClickListener(null);
} else {
if (dragType == WORKSPACE_ACCESSIBILITY_DRAG &&
!(mTouchHelper instanceof WorkspaceAccessibilityHelper)) {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index ea52324..13971ad 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -515,12 +515,6 @@
}
}
- public boolean shouldIgnoreLongPressToOverview(float touchX) {
- boolean touchedLhsEdge = mInsets.left == 0 && touchX < edgeMarginPx;
- boolean touchedRhsEdge = mInsets.right == 0 && touchX > (widthPx - edgeMarginPx);
- return !isMultiWindowMode && (touchedLhsEdge || touchedRhsEdge);
- }
-
private static Context getContext(Context c, int orientation) {
Configuration context = new Configuration(c.getResources().getConfiguration());
context.orientation = orientation;
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index a3fe89a..dec6cb4 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -16,10 +16,10 @@
package com.android.launcher3;
-import static com.android.launcher3.AlphaUpdateListener.updateVisibility;
import static com.android.launcher3.ButtonDropTarget.TOOLTIP_DEFAULT;
import static com.android.launcher3.ButtonDropTarget.TOOLTIP_LEFT;
import static com.android.launcher3.ButtonDropTarget.TOOLTIP_RIGHT;
+import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.TimeInterpolator;
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 5354edf..3873a81 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -58,7 +58,7 @@
private static final ColorMatrix sTempFilterMatrix = new ColorMatrix();
protected final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
- private final Bitmap mBitmap;
+ protected Bitmap mBitmap;
protected final int mIconColor;
private boolean mIsPressed;
@@ -324,10 +324,9 @@
return new MyConstantState(mBitmap, mIconColor);
}
- private static class MyConstantState extends ConstantState {
- private final Bitmap mBitmap;
- private final int mIconColor;
-
+ protected static class MyConstantState extends ConstantState {
+ protected final Bitmap mBitmap;
+ protected final int mIconColor;
public MyConstantState(Bitmap bitmap, int color) {
mBitmap = bitmap;
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 03043f2..211a756 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -63,14 +63,6 @@
return mContent;
}
- /**
- * Registers the specified listener on the cell layout of the hotseat.
- */
- @Override
- public void setOnLongClickListener(OnLongClickListener l) {
- mContent.setOnLongClickListener(l);
- }
-
/* Get the orientation invariant order of the item in the hotseat for persistence. */
int getOrderInHotseat(int x, int y) {
return mHasVerticalHotseat ? (mContent.getCountY() - y - 1) : x;
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index f4ae62a..ab73074 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -641,11 +641,8 @@
// Load the full res icon for the application, but if useLowResIcon is set, then
// only keep the low resolution icon instead of the larger full-sized icon
BitmapInfo iconInfo = li.createBadgedIconBitmap(
- appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion);
- if (mInstantAppResolver.isInstantApp(appInfo)) {
- li.badgeWithDrawable(iconInfo.icon,
- mContext.getDrawable(R.drawable.ic_instant_app_badge));
- }
+ appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion,
+ mInstantAppResolver.isInstantApp(appInfo));
li.recycle();
Bitmap lowResIcon = generateLowResIcon(iconInfo.icon);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index e460911..f63cce5 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -22,6 +22,7 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Point;
+import android.support.annotation.VisibleForTesting;
import android.util.DisplayMetrics;
import android.util.Xml;
import android.view.Display;
@@ -88,17 +89,18 @@
public Point defaultWallpaperSize;
+ @VisibleForTesting
public InvariantDeviceProfile() {
}
- public InvariantDeviceProfile(InvariantDeviceProfile p) {
+ private InvariantDeviceProfile(InvariantDeviceProfile p) {
this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns,
p.numFolderRows, p.numFolderColumns,
p.iconSize, p.landscapeIconSize, p.iconTextSize, p.numHotseatIcons,
p.defaultLayoutId, p.demoModeLayoutId);
}
- InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc,
+ private InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc,
float is, float lis, float its, int hs, int dlId, int dmlId) {
name = n;
minWidthDps = w;
@@ -116,7 +118,7 @@
}
@TargetApi(23)
- InvariantDeviceProfile(Context context) {
+ public InvariantDeviceProfile(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 375deb7..e779b5e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -25,13 +25,11 @@
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
-import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
-import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.ActivityOptions;
import android.appwidget.AppWidgetHostView;
@@ -48,9 +46,6 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@@ -63,32 +58,25 @@
import android.text.method.TextKeyListener;
import android.util.Log;
import android.util.SparseArray;
-import android.view.ActionMode;
-import android.view.Display;
-import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
import android.widget.Toast;
import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
+import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.compat.AppWidgetManagerCompat;
-import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
@@ -96,6 +84,7 @@
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dynamicui.WallpaperColorInfo;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.folder.FolderIconPreviewVerifier;
import com.android.launcher3.keyboard.CustomActionsPopup;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.FileLog;
@@ -109,7 +98,6 @@
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.uioverrides.UiFactory;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -126,6 +114,7 @@
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.util.ViewOnDrawExecutor;
+import com.android.launcher3.views.OptionsPopupView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -147,10 +136,8 @@
/**
* Default launcher application.
*/
-public class Launcher extends BaseActivity
- implements LauncherExterns, OnClickListener, OnLongClickListener,
- LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener,
- WallpaperColorInfo.OnThemeChangeListener {
+public class Launcher extends BaseDraggingActivity implements LauncherExterns, LauncherModel.Callbacks,
+ LauncherProviderChangeListener, WallpaperColorInfo.OnThemeChangeListener {
public static final String TAG = "Launcher";
static final boolean LOGD = false;
@@ -176,10 +163,6 @@
*/
protected static final int REQUEST_LAST = 100;
- // The Intent extra that defines whether to ignore the launch animation
- static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
- "com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
-
// Type: int
private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
// Type: int
@@ -191,14 +174,8 @@
// Type: SparseArray<Parcelable>
private static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel";
- // When starting an action mode, setting this tag will cause the action mode to be cancelled
- // automatically when user interacts with the launcher.
- public static final Object AUTO_CANCEL_ACTION_MODE = new Object();
-
private LauncherStateManager mStateManager;
- private boolean mIsSafeModeEnabled;
-
private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
// How long to wait before the new-shortcut animation automatically pans the workspace
@@ -228,11 +205,10 @@
AllAppsTransitionController mAllAppsController;
// UI and state for the overview panel
- private ViewGroup mOverviewPanel;
+ private View mOverviewPanel;
@Thunk boolean mWorkspaceLoading = true;
- private OnStartCallback mOnStartCallback;
private OnResumeCallback mOnResumeCallback;
private ViewOnDrawExecutor mPendingExecutor;
@@ -261,13 +237,10 @@
*/
private PendingRequestArgs mPendingRequestArgs;
- private final PointF mLastDispatchTouchEvent = new PointF();
-
public ViewGroupFocusHelper mFocusHandler;
private boolean mAppLaunchSuccess;
private RotationHelper mRotationHelper;
- private ActionMode mCurrentActionMode;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -300,7 +273,6 @@
initDeviceProfile(app.getInvariantDeviceProfile());
mSharedPrefs = Utilities.getPrefs(this);
- mIsSafeModeEnabled = getPackageManager().isSafeMode();
mIconCache = app.getIconCache();
mAccessibilityDelegate = new LauncherAccessibilityDelegate(this);
@@ -392,6 +364,9 @@
getRootView().dispatchInsets();
getStateManager().reapplyState();
+ // Recreate touch controllers
+ mDragLayer.setup(mDragController);
+
// TODO: We can probably avoid rebind when only screen size changed.
rebindModel();
}
@@ -411,13 +386,7 @@
private void initDeviceProfile(InvariantDeviceProfile idp) {
// Load configuration-specific DeviceProfile
- mDeviceProfile = idp.getDeviceProfile(this);
- if (isInMultiWindowModeCompat()) {
- Display display = getWindowManager().getDefaultDisplay();
- Point mwSize = new Point();
- display.getSize(mwSize);
- mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
- }
+ setDeviceProfile(idp.getDeviceProfile(this));
mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout(), true);
}
@@ -434,10 +403,6 @@
return mStateManager;
}
- public LauncherAppTransitionManager getAppTransitionManager() {
- return mAppTransitionManager;
- }
-
protected void overrideTheme(boolean isDark, boolean supportsDarkText) {
if (isDark) {
setTheme(R.style.LauncherThemeDark);
@@ -500,6 +465,22 @@
return mPopupDataProvider;
}
+ @Override
+ public BadgeInfo getBadgeInfoForItem(ItemInfo info) {
+ return mPopupDataProvider.getBadgeInfoForItem(info);
+ }
+
+ @Override
+ public void invalidateParent(ItemInfo info) {
+ FolderIconPreviewVerifier verifier = new FolderIconPreviewVerifier(getDeviceProfile().inv);
+ if (verifier.isItemInPreview(info.rank) && (info.container >= 0)) {
+ View folderIcon = getWorkspace().getHomescreenIconByItemId(info.container);
+ if (folderIcon != null) {
+ folderIcon.invalidate();
+ }
+ }
+ }
+
/**
* Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
* a configuration step, this allows the proper animations to run after other transitions.
@@ -784,10 +765,6 @@
super.onStart();
FirstFrameAnimatorHelper.setIsVisible(true);
- if (mOnStartCallback != null) {
- mOnStartCallback.onLauncherStart(this);
- mOnStartCallback = null;
- }
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onStart();
}
@@ -952,23 +929,15 @@
mWorkspace = mDragLayer.findViewById(R.id.workspace);
mWorkspace.initParentViews(mDragLayer);
mOverviewPanel = findViewById(R.id.overview_panel);
+ mHotseat = findViewById(R.id.hotseat);
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
// Setup the drag layer
- mDragLayer.setup(this, mDragController);
+ mDragLayer.setup(mDragController);
- // Setup the hotseat
- mHotseat = (Hotseat) findViewById(R.id.hotseat);
- if (mHotseat != null) {
- mHotseat.setOnLongClickListener(this);
- }
-
- // Setup the workspace
- mWorkspace.setHapticFeedbackEnabled(false);
- mWorkspace.setOnLongClickListener(this);
mWorkspace.setup(mDragController);
// Until the workspace is bound, ensure that we keep the wallpaper offset locked to the
// default state, otherwise we will update to the wrong offsets in RTL
@@ -986,7 +955,7 @@
mDragController.setMoveTarget(mWorkspace);
mDropTargetBar.setup(mDragController);
- mAllAppsController.setupViews(mAppsView, mHotseat);
+ mAllAppsController.setupViews(mAppsView);
}
/**
@@ -1202,10 +1171,12 @@
return mAllAppsController;
}
+ @Override
public LauncherRootView getRootView() {
return (LauncherRootView) mLauncherView;
}
+ @Override
public DragLayer getDragLayer() {
return mDragLayer;
}
@@ -1222,7 +1193,7 @@
return mHotseat;
}
- public <T extends ViewGroup> T getOverviewPanel() {
+ public <T extends View> T getOverviewPanel() {
return (T) mOverviewPanel;
}
@@ -1282,11 +1253,15 @@
// In all these cases, only animate if we're already on home
AbstractFloatingView.closeAllOpenViews(this, isStarted());
- mStateManager.goToState(NORMAL);
+ if (!isInState(NORMAL)) {
+ // Only change state, if not already the same. This prevents cancelling any
+ // animations running as part of resume
+ mStateManager.goToState(NORMAL);
+ }
// Reset the apps view
if (!alreadyOnHome && mAppsView != null) {
- mAppsView.reset();
+ mAppsView.reset(isStarted() /* animate */);
}
if (shouldMoveToDefaultScreen && !mWorkspace.isTouchActive()) {
@@ -1659,51 +1634,6 @@
}
/**
- * Launches the intent referred by the clicked shortcut.
- *
- * @param v The view representing the clicked shortcut.
- */
- @Override
- public void onClick(View v) {
- // Make sure that rogue clicks don't get through while allapps is launching, or after the
- // view has detached (it's possible for this to happen if the view is removed mid touch).
- if (v.getWindowToken() == null) {
- return;
- }
-
- if (!mWorkspace.isFinishedSwitchingState()) {
- return;
- }
-
- if (v instanceof Workspace) {
- if (isInState(OVERVIEW)) {
- getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Touch.TAP,
- LauncherLogProto.Action.Direction.NONE,
- LauncherLogProto.ContainerType.OVERVIEW, mWorkspace.getCurrentPage());
- mStateManager.goToState(NORMAL);
- }
- return;
- }
-
- if (v instanceof CellLayout) {
- if (isInState(OVERVIEW)) {
- int page = mWorkspace.indexOfChild(v);
- getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Touch.TAP,
- LauncherLogProto.Action.Direction.NONE,
- LauncherLogProto.ContainerType.OVERVIEW, page);
- mWorkspace.snapToPageFromOverView(page);
- mStateManager.goToState(NORMAL);
- }
- return;
- }
- }
-
- @SuppressLint("ClickableViewAccessibility")
- public boolean onTouch(View v, MotionEvent event) {
- return false;
- }
-
- /**
* Event handler for the wallpaper picker button that appears after a long press
* on the home screen.
*/
@@ -1743,179 +1673,49 @@
}
}
- private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
- try {
- StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
- try {
- // Temporarily disable deathPenalty on all default checks. For eg, shortcuts
- // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
- // is enabled by default on NYC.
- StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
- .penaltyLog().build());
-
- if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- String id = ((ShortcutInfo) info).getDeepShortcutId();
- String packageName = intent.getPackage();
- DeepShortcutManager.getInstance(this).startShortcut(
- packageName, id, intent.getSourceBounds(), optsBundle, info.user);
- } else {
- // Could be launching some bookkeeping activity
- startActivity(intent, optsBundle);
- }
- } finally {
- StrictMode.setVmPolicy(oldPolicy);
- }
- } catch (SecurityException e) {
- // Due to legacy reasons, direct call shortcuts require Launchers to have the
- // corresponding permission. Show the appropriate permission prompt if that
- // is the case.
- if (intent.getComponent() == null
- && Intent.ACTION_CALL.equals(intent.getAction())
- && checkSelfPermission(Manifest.permission.CALL_PHONE) !=
- PackageManager.PERMISSION_GRANTED) {
-
- setWaitingForResult(PendingRequestArgs
- .forIntent(REQUEST_PERMISSION_CALL_PHONE, intent, info));
- requestPermissions(new String[]{Manifest.permission.CALL_PHONE},
- REQUEST_PERMISSION_CALL_PHONE);
- } else {
- // No idea why this was thrown.
- throw e;
- }
- }
- }
-
- public Bundle getActivityLaunchOptionsAsBundle(View v, boolean useDefaultLaunchOptions) {
- ActivityOptions activityOptions = getActivityLaunchOptions(v, useDefaultLaunchOptions);
- return activityOptions == null ? null : activityOptions.toBundle();
- }
-
@TargetApi(Build.VERSION_CODES.M)
+ @Override
public ActivityOptions getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
return useDefaultLaunchOptions
? mAppTransitionManager.getDefaultActivityLaunchOptions(this, v)
: mAppTransitionManager.getActivityLaunchOptions(this, v);
}
- public Rect getViewBounds(View v) {
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
+ @TargetApi(Build.VERSION_CODES.M)
+ @Override
+ protected boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
+ // Due to legacy reasons, direct call shortcuts require Launchers to have the
+ // corresponding permission. Show the appropriate permission prompt if that
+ // is the case.
+ if (intent.getComponent() == null
+ && Intent.ACTION_CALL.equals(intent.getAction())
+ && checkSelfPermission(android.Manifest.permission.CALL_PHONE) !=
+ PackageManager.PERMISSION_GRANTED) {
+
+ setWaitingForResult(PendingRequestArgs
+ .forIntent(REQUEST_PERMISSION_CALL_PHONE, intent, info));
+ requestPermissions(new String[]{android.Manifest.permission.CALL_PHONE},
+ REQUEST_PERMISSION_CALL_PHONE);
+ return true;
+ } else {
+ return false;
+ }
}
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
- mAppLaunchSuccess = false;
- if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
- Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
- return mAppLaunchSuccess;
- }
-
- // Only launch using the new animation if the shortcut has not opted out (this is a
- // private contract between launcher and may be ignored in the future).
- boolean useLaunchAnimation = (v != null) &&
- !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
- Bundle optsBundle = useLaunchAnimation
- ? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat())
- : null;
-
- UserHandle user = item == null ? null : item.user;
-
- // Prepare intent
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- if (v != null) {
- intent.setSourceBounds(getViewBounds(v));
- }
- try {
- boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
- && (item instanceof ShortcutInfo)
- && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
- || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
- && !((ShortcutInfo) item).isPromise();
- if (isShortcut) {
- // Shortcuts need some special checks due to legacy reasons.
- startShortcutIntentSafely(intent, optsBundle, item);
- } else if (user == null || user.equals(Process.myUserHandle())) {
- // Could be launching some bookkeeping activity
- startActivity(intent, optsBundle);
- } else {
- LauncherAppsCompat.getInstance(this).startActivityForProfile(
- intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
- }
-
- if (v instanceof BubbleTextView) {
- // This is set to the view that launched the activity that navigated the user away
- // from launcher. Since there is no callback for when the activity has finished
- // launching, enable the press state and keep this reference to reset the press
- // state when we return to launcher.
- BubbleTextView btv = (BubbleTextView) v;
- btv.setStayPressed(true);
- setOnResumeCallback(btv);
- }
- mAppLaunchSuccess = true;
- getUserEventDispatcher().logAppLaunch(v, intent); // TODO for discovered apps b/35802115
- } catch (ActivityNotFoundException|SecurityException e) {
- Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
+ mAppLaunchSuccess = super.startActivitySafely(v, intent, item);
+ if (mAppLaunchSuccess && v instanceof BubbleTextView) {
+ // This is set to the view that launched the activity that navigated the user away
+ // from launcher. Since there is no callback for when the activity has finished
+ // launching, enable the press state and keep this reference to reset the press
+ // state when we return to launcher.
+ BubbleTextView btv = (BubbleTextView) v;
+ btv.setStayPressed(true);
+ setOnResumeCallback(btv);
}
return mAppLaunchSuccess;
}
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- mLastDispatchTouchEvent.set(ev.getX(), ev.getY());
- return super.dispatchTouchEvent(ev);
- }
-
- @Override
- public boolean onLongClick(View v) {
- if (!isDraggingEnabled()) return false;
- if (isWorkspaceLocked()) return false;
- if (!isInState(NORMAL) && !isInState(OVERVIEW)) return false;
-
- boolean ignoreLongPressToOverview =
- mDeviceProfile.shouldIgnoreLongPressToOverview(mLastDispatchTouchEvent.x);
-
- if (v instanceof Workspace) {
- if (!isInState(OVERVIEW)) {
- if (!mWorkspace.isTouchActive() && !ignoreLongPressToOverview) {
- getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
- Action.Direction.NONE, ContainerType.WORKSPACE,
- mWorkspace.getCurrentPage());
- UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent);
- mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
- // The hotseat touch handling does not go through Workspace, and we always allow long press
- // on hotseat items.
- if (!mDragController.isDragging()) {
- // User long pressed on empty space
- if (mWorkspace.isPageRearrangeEnabled()) {
- mWorkspace.startReordering(v);
- getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
- Action.Direction.NONE, ContainerType.OVERVIEW);
- } else {
- if (ignoreLongPressToOverview) {
- return false;
- }
- getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
- Action.Direction.NONE, ContainerType.WORKSPACE,
- mWorkspace.getCurrentPage());
- UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent);
- }
- mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- }
- return true;
- }
-
boolean isHotseatLayout(View layout) {
// TODO: Remove this method
return mHotseat != null && layout != null &&
@@ -1974,10 +1774,6 @@
mOnResumeCallback = callback;
}
- public void setOnStartCallback(OnStartCallback callback) {
- mOnStartCallback = callback;
- }
-
/**
* Implementation of the method from LauncherModel.Callbacks.
*/
@@ -2628,8 +2424,7 @@
// Setting the touch point to (-1, -1) will show the options popup in the center of
// the screen.
- mLastDispatchTouchEvent.set(-1, -1);
- UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent);
+ OptionsPopupView.show(this, -1, -1);
}
return true;
}
@@ -2643,26 +2438,6 @@
return ((Launcher) ((ContextWrapper) context).getBaseContext());
}
- @Override
- public void onActionModeStarted(ActionMode mode) {
- super.onActionModeStarted(mode);
- mCurrentActionMode = mode;
- }
-
- @Override
- public void onActionModeFinished(ActionMode mode) {
- super.onActionModeFinished(mode);
- mCurrentActionMode = null;
- }
-
- public boolean finishAutoCancelActionMode() {
- if (mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag()) {
- mCurrentActionMode.finish();
- return true;
- }
- return false;
- }
-
/**
* Callback for listening for onResume
*/
@@ -2670,12 +2445,4 @@
void onLauncherResume();
}
-
- /**
- * Callback for listening for onStart
- */
- public interface OnStartCallback {
-
- void onLauncherStart(Launcher launcher);
- }
}
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 19fa3d4..04f9b3a 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -62,13 +62,4 @@
public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
return getDefaultActivityLaunchOptions(launcher, v);
}
-
- /** Cancels the current Launcher transition animation */
- public void finishLauncherAnimation() {
- }
-
- public boolean isAnimating() {
- // We don't know when the activity options are being used.
- return false;
- }
}
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index fc4de2d..b1273b6 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -29,6 +29,7 @@
private int mRightInsetBarWidth;
private View mAlignedView;
+ private WindowStateListener mWindowStateListener;
public LauncherRootView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -117,4 +118,31 @@
}
}
}
+
+ public void setWindowStateListener(WindowStateListener listener) {
+ mWindowStateListener = listener;
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ super.onWindowFocusChanged(hasWindowFocus);
+ if (mWindowStateListener != null) {
+ mWindowStateListener.onWindowFocusChanged(hasWindowFocus);
+ }
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (mWindowStateListener != null) {
+ mWindowStateListener.onWindowVisibilityChanged(visibility);
+ }
+ }
+
+ public interface WindowStateListener {
+
+ void onWindowFocusChanged(boolean hasFocus);
+
+ void onWindowVisibilityChanged(int visibility);
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 4e6bcdc..9fef64a 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -40,6 +40,16 @@
*/
public class LauncherState {
+
+ /**
+ * Set of elements indicating various workspace elements which change visibility across states
+ * Note that workspace is not included here as in that case, we animate individual pages
+ */
+ public static final int NONE = 0;
+ public static final int HOTSEAT = 1 << 0;
+ public static final int ALL_APPS_HEADER = 1 << 1;
+ public static final int ALL_APPS_CONTENT = 1 << 2;
+
protected static final int FLAG_SHOW_SCRIM = 1 << 0;
protected static final int FLAG_MULTI_PAGE = 1 << 1;
protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 2;
@@ -51,7 +61,6 @@
protected static final int FLAG_DISABLE_INTERACTION = 1 << 8;
protected static final int FLAG_OVERVIEW_UI = 1 << 9;
-
protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER =
new PageAlphaProvider(ACCEL_2) {
@Override
@@ -68,13 +77,13 @@
public static final LauncherState NORMAL = new LauncherState(0, ContainerType.WORKSPACE,
0, FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
- public static final LauncherState ALL_APPS = new AllAppsState(1);
-
- public static final LauncherState SPRING_LOADED = new SpringLoadedState(2);
-
- public static final LauncherState OVERVIEW = new OverviewState(3);
-
- public static final LauncherState FAST_OVERVIEW = new FastOverviewState(4);
+ /**
+ * Various Launcher states arranged in the increasing order of UI layers
+ */
+ public static final LauncherState SPRING_LOADED = new SpringLoadedState(1);
+ public static final LauncherState OVERVIEW = new OverviewState(2);
+ public static final LauncherState FAST_OVERVIEW = new FastOverviewState(3);
+ public static final LauncherState ALL_APPS = new AllAppsState(4);
public final int ordinal;
@@ -161,8 +170,8 @@
return new float[] {1, 0, 0};
}
- public float getHoseatAlpha(Launcher launcher) {
- return 1f;
+ public float getOverviewTranslationX(Launcher launcher) {
+ return launcher.getDragLayer().getMeasuredWidth();
}
public void onStateEnabled(Launcher launcher) {
@@ -175,6 +184,10 @@
return launcher.getWorkspace();
}
+ public int getVisibleElements(Launcher launcher) {
+ return HOTSEAT;
+ }
+
/**
* Fraction shift in the vertical translation UI and related properties
*
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index d5813f3..7d50a52 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -28,8 +29,12 @@
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.anim.PropertySetter.AnimatedPropertySetter;
import com.android.launcher3.uioverrides.UiFactory;
+import java.util.ArrayList;
+
/**
* TODO: figure out what kind of tests we can write for this
*
@@ -78,6 +83,7 @@
private final AnimationConfig mConfig = new AnimationConfig();
private final Handler mUiHandler;
private final Launcher mLauncher;
+ private final ArrayList<StateListener> mListeners = new ArrayList<>();
private StateHandler[] mStateHandlers;
private LauncherState mState = NORMAL;
@@ -87,8 +93,6 @@
private LauncherState mRestState;
- private StateListener mStateListener;
-
public LauncherStateManager(Launcher l) {
mUiHandler = new Handler(Looper.getMainLooper());
mLauncher = l;
@@ -105,8 +109,12 @@
return mStateHandlers;
}
- public void setStateListener(StateListener stateListener) {
- mStateListener = stateListener;
+ public void addStateListener(StateListener listener) {
+ mListeners.add(listener);
+ }
+
+ public void removeStateListener(StateListener listener) {
+ mListeners.remove(listener);
}
/**
@@ -157,11 +165,6 @@
}
private void goToState(LauncherState state, boolean animated, long delay,
- Runnable onCompleteRunnable) {
- goToState(state, animated, delay, -1, onCompleteRunnable);
- }
-
- public void goToState(LauncherState state, boolean animated, long delay, long overrideDuration,
final Runnable onCompleteRunnable) {
if (mLauncher.isInState(state)) {
if (mConfig.mCurrentAnimation == null) {
@@ -188,13 +191,13 @@
mConfig.reset();
if (!animated) {
- preOnStateTransitionStart();
onStateTransitionStart(state);
for (StateHandler handler : getStateHandlers()) {
handler.setState(state);
}
- if (mStateListener != null) {
- mStateListener.onStateSetImmediately(state);
+
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).onStateSetImmediately(state);
}
onStateTransitionEnd(state);
@@ -208,9 +211,6 @@
// 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;
- if (overrideDuration > -1) {
- mConfig.duration = overrideDuration;
- }
AnimatorSet animation = createAnimationToNewWorkspaceInternal(
state, new AnimatorSetBuilder(), onCompleteRunnable);
@@ -245,7 +245,6 @@
protected AnimatorSet createAnimationToNewWorkspaceInternal(final LauncherState state,
AnimatorSetBuilder builder, final Runnable onCompleteRunnable) {
- preOnStateTransitionStart();
for (StateHandler handler : getStateHandlers()) {
builder.startTag(handler);
@@ -259,16 +258,16 @@
public void onAnimationStart(Animator animation) {
// Change the internal state only when the transition actually starts
onStateTransitionStart(state);
- if (mStateListener != null) {
- mStateListener.onStateTransitionStart(state);
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).onStateTransitionStart(state);
}
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- if (mStateListener != null) {
- mStateListener.onStateTransitionComplete(mState);
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).onStateTransitionComplete(state);
}
}
@@ -285,15 +284,6 @@
return mConfig.mCurrentAnimation;
}
- private void preOnStateTransitionStart() {
- // If we are still animating to launcher from an app,
- // finish it and let this state animation take over.
- LauncherAppTransitionManager transitionManager = mLauncher.getAppTransitionManager();
- if (transitionManager != null) {
- transitionManager.finishLauncherAnimation();
- }
- }
-
private void onStateTransitionStart(LauncherState state) {
mState.onStateDisabled(mLauncher);
mState = state;
@@ -333,6 +323,10 @@
}
public void moveToRestState() {
+ if (mConfig.mCurrentAnimation != null && mConfig.userControlled) {
+ // The user is doing something. Lets not mess it up
+ return;
+ }
if (mState.disableRestore) {
goToState(getRestState());
// Reset history
@@ -355,6 +349,15 @@
mConfig.reset();
}
+ /**
+ * Sets the animation as the current state animation, i.e., canceled when
+ * starting another animation and may block some launcher interactions while running.
+ */
+ public void setCurrentAnimation(AnimatorSet anim) {
+ cancelAnimation();
+ mConfig.setAnimation(anim);
+ }
+
private class StartAnimRunnable implements Runnable {
private final AnimatorSet mAnim;
@@ -380,12 +383,14 @@
public static class AnimationConfig extends AnimatorListenerAdapter {
public long duration;
public boolean userControlled;
+ private PropertySetter mProperSetter;
private AnimatorSet mCurrentAnimation;
public void reset() {
duration = 0;
userControlled = false;
+ mProperSetter = null;
if (mCurrentAnimation != null) {
mCurrentAnimation.setDuration(0);
@@ -394,6 +399,14 @@
}
}
+ public PropertySetter getProperSetter(AnimatorSetBuilder builder) {
+ if (mProperSetter == null) {
+ mProperSetter = duration == 0 ? NO_ANIM_PROPERTY_SETTER
+ : new AnimatedPropertySetter(duration, builder);
+ }
+ return mProperSetter;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
if (mCurrentAnimation == animation) {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index d39ec3e..9eff84b 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -19,10 +19,7 @@
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
-import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -30,8 +27,6 @@
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputDevice;
@@ -48,7 +43,6 @@
import android.view.animation.Interpolator;
import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.touch.OverScroll;
import com.android.launcher3.util.Thunk;
@@ -62,7 +56,9 @@
public abstract class PagedView<T extends View & PageIndicator> extends ViewGroup {
private static final String TAG = "PagedView";
private static final boolean DEBUG = false;
+
protected static final int INVALID_PAGE = -1;
+ protected static final ComputePageScrollsLogic SIMPLE_SCROLL_LOGIC = (v) -> v.getVisibility() != GONE;
public static final int PAGE_SNAP_ANIMATION_DURATION = 750;
public static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
@@ -105,31 +101,21 @@
private VelocityTracker mVelocityTracker;
protected int mPageSpacing = 0;
- private float mParentDownMotionX;
- private float mParentDownMotionY;
private float mDownMotionX;
private float mDownMotionY;
- private float mDownScrollX;
- private float mDragViewBaselineLeft;
private float mLastMotionX;
private float mLastMotionXRemainder;
- private float mLastMotionY;
private float mTotalMotionX;
- private boolean mCancelTap;
-
private int[] mPageScrolls;
protected final static int TOUCH_STATE_REST = 0;
protected final static int TOUCH_STATE_SCROLLING = 1;
protected final static int TOUCH_STATE_PREV_PAGE = 2;
protected final static int TOUCH_STATE_NEXT_PAGE = 3;
- protected final static int TOUCH_STATE_REORDERING = 4;
protected int mTouchState = TOUCH_STATE_REST;
- protected OnLongClickListener mLongClickListener;
-
protected int mTouchSlop;
private int mMaximumVelocity;
protected boolean mAllowOverScroll = true;
@@ -153,26 +139,6 @@
@Thunk int mPageIndicatorViewId;
protected T mPageIndicator;
- // Reordering
- // We use the min scale to determine how much to expand the actually PagedView measured
- // dimensions such that when we are zoomed out, the view is not clipped
- private static int REORDERING_DROP_REPOSITION_DURATION = 200;
- @Thunk static int REORDERING_REORDER_REPOSITION_DURATION = 300;
- private static int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 80;
-
- @Thunk View mDragView;
- private Runnable mSidePageHoverRunnable;
- @Thunk int mSidePageHoverIndex = -1;
- // This variable's scope is only for the duration of startReordering() and endReordering()
- private boolean mReorderingStarted = false;
- // This variable's scope is for the duration of startReordering() and after the zoomIn()
- // animation after endReordering()
- private boolean mIsReordering;
- // The runnable that settles the page after snapToPage and animateDragViewToOriginalPosition
- private static final int NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT = 2;
- private int mPostReorderingPreZoomInRemainingAnimationCount;
- private Runnable mPostReorderingPreZoomInRunnable;
-
// Convenience/caching
private static final Matrix sTmpInvMatrix = new Matrix();
private static final float[] sTmpPoint = new float[2];
@@ -237,47 +203,6 @@
}
}
- // Convenience methods to map points from self to parent and vice versa
- private float[] mapPointFromViewToParent(View v, float x, float y) {
- sTmpPoint[0] = x;
- sTmpPoint[1] = y;
- v.getMatrix().mapPoints(sTmpPoint);
- sTmpPoint[0] += v.getLeft();
- sTmpPoint[1] += v.getTop();
- return sTmpPoint;
- }
- private float[] mapPointFromParentToView(View v, float x, float y) {
- sTmpPoint[0] = x - v.getLeft();
- sTmpPoint[1] = y - v.getTop();
- v.getMatrix().invert(sTmpInvMatrix);
- sTmpInvMatrix.mapPoints(sTmpPoint);
- return sTmpPoint;
- }
-
- private void updateDragViewTranslationDuringDrag() {
- if (mDragView != null) {
- float x = (mLastMotionX - mDownMotionX) + (getScrollX() - mDownScrollX) +
- (mDragViewBaselineLeft - mDragView.getLeft());
- float y = mLastMotionY - mDownMotionY;
- mDragView.setTranslationX(x);
- mDragView.setTranslationY(y);
-
- if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): "
- + x + ", " + y);
- }
- }
-
- @Override
- public void setScaleX(float scaleX) {
- super.setScaleX(scaleX);
- if (isReordering(true)) {
- float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
- mLastMotionX = p[0];
- mLastMotionY = p[1];
- updateDragViewTranslationDuringDrag();
- }
- }
-
public T getPageIndicator() {
return mPageIndicator;
}
@@ -380,12 +305,9 @@
}
private void updatePageIndicator() {
- // Update the page indicator (when we aren't reordering)
if (mPageIndicator != null) {
mPageIndicator.setPageDescription(getPageIndicatorDescription());
- if (!isReordering(false)) {
- mPageIndicator.setActiveMarker(getNextPage());
- }
+ mPageIndicator.setActiveMarker(getNextPage());
}
}
protected void pageBeginTransition() {
@@ -421,21 +343,6 @@
mWasInOverscroll = false;
}
- /**
- * Registers the specified listener on each page contained in this workspace.
- *
- * @param l The listener used to respond to long clicks.
- */
- @Override
- public void setOnLongClickListener(OnLongClickListener l) {
- mLongClickListener = l;
- final int count = getPageCount();
- for (int i = 0; i < count; i++) {
- getPageAt(i).setOnLongClickListener(l);
- }
- super.setOnLongClickListener(l);
- }
-
protected int getUnboundedScrollX() {
return mUnboundedScrollX;
}
@@ -490,14 +397,6 @@
mOverScrollX = x;
super.scrollTo(x, y);
}
-
- // Update the last motion events when scrolling
- if (isReordering(true)) {
- float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
- mLastMotionX = p[0];
- mLastMotionY = p[1];
- updateDragViewTranslationDuringDrag();
- }
}
private void sendScrollAccessibilityEvent() {
@@ -549,7 +448,6 @@
pageEndTransition();
}
- onPostReorderingAnimationCompleted();
if (isAccessibilityEnabled(getContext())) {
// Notify the user when the page changes
announceForAccessibility(getCurrentPageDescription());
@@ -644,43 +542,13 @@
if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
final int childCount = getChildCount();
- final int startIndex = mIsRtl ? childCount - 1 : 0;
- final int endIndex = mIsRtl ? -1 : childCount;
- final int delta = mIsRtl ? -1 : 1;
-
- int verticalPadding = getPaddingTop() + getPaddingBottom();
-
- int scrollOffsetLeft = mInsets.left + getPaddingLeft();
- int childLeft = scrollOffsetLeft;
-
boolean pageScrollChanged = false;
if (mPageScrolls == null || childCount != mChildCountOnLastLayout) {
mPageScrolls = new int[childCount];
pageScrollChanged = true;
}
-
- for (int i = startIndex; i != endIndex; i += delta) {
- final View child = getPageAt(i);
- if (child.getVisibility() != View.GONE) {
- int childTop = getPaddingTop() + mInsets.top;
- childTop += (getMeasuredHeight() - mInsets.top - mInsets.bottom - verticalPadding
- - child.getMeasuredHeight()) / 2;
-
- final int childWidth = child.getMeasuredWidth();
- final int childHeight = child.getMeasuredHeight();
-
- if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop);
- child.layout(childLeft, childTop,
- childLeft + child.getMeasuredWidth(), childTop + childHeight);
-
- final int pageScroll = childLeft - scrollOffsetLeft;
- if (mPageScrolls[i] != pageScroll) {
- pageScrollChanged = true;
- mPageScrolls[i] = pageScroll;
- }
-
- childLeft += childWidth + mPageSpacing + getChildGap();
- }
+ if (getPageScrolls(mPageScrolls, true, SIMPLE_SCROLL_LOGIC)) {
+ pageScrollChanged = true;
}
final LayoutTransition transition = getLayoutTransition();
@@ -716,10 +584,51 @@
setCurrentPage(getNextPage());
}
mChildCountOnLastLayout = childCount;
+ }
- if (isReordering(true)) {
- updateDragViewTranslationDuringDrag();
+ /**
+ * Initializes {@code outPageScrolls} with scroll positions for view at that index. The length
+ * of {@code outPageScrolls} should be same as the the childCount
+ *
+ */
+ protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren,
+ ComputePageScrollsLogic scrollLogic) {
+ final int childCount = getChildCount();
+
+ final int startIndex = mIsRtl ? childCount - 1 : 0;
+ final int endIndex = mIsRtl ? -1 : childCount;
+ final int delta = mIsRtl ? -1 : 1;
+
+ int verticalPadding = getPaddingTop() + getPaddingBottom();
+
+ int scrollOffsetLeft = mInsets.left + getPaddingLeft();
+ int childLeft = scrollOffsetLeft;
+ boolean pageScrollChanged = false;
+
+ for (int i = startIndex; i != endIndex; i += delta) {
+ final View child = getPageAt(i);
+ if (scrollLogic.shouldIncludeView(child)) {
+ int childTop = getPaddingTop() + mInsets.top;
+ childTop += (getMeasuredHeight() - mInsets.top - mInsets.bottom - verticalPadding
+ - child.getMeasuredHeight()) / 2;
+ final int childWidth = child.getMeasuredWidth();
+
+ if (layoutChildren) {
+ final int childHeight = child.getMeasuredHeight();
+ child.layout(childLeft, childTop,
+ childLeft + child.getMeasuredWidth(), childTop + childHeight);
+ }
+
+ final int pageScroll = childLeft - scrollOffsetLeft;
+ if (outPageScrolls[i] != pageScroll) {
+ pageScrollChanged = true;
+ outPageScrolls[i] = pageScroll;
+ }
+
+ childLeft += childWidth + mPageSpacing + getChildGap();
+ }
}
+ return pageScrollChanged;
}
protected int getChildGap() {
@@ -756,11 +665,13 @@
@Override
public void onViewAdded(View child) {
+ super.onViewAdded(child);
dispatchPageCountChanged();
}
@Override
public void onViewRemoved(View child) {
+ super.onViewRemoved(child);
mCurrentPage = validateNewPage(mCurrentPage);
dispatchPageCountChanged();
}
@@ -937,12 +848,7 @@
// Remember location of down touch
mDownMotionX = x;
mDownMotionY = y;
- mDownScrollX = getScrollX();
mLastMotionX = x;
- mLastMotionY = y;
- float[] p = mapPointFromViewToParent(this, x, y);
- mParentDownMotionX = p[0];
- mParentDownMotionY = p[1];
mLastMotionXRemainder = 0;
mTotalMotionX = 0;
mActivePointerId = ev.getPointerId(0);
@@ -990,6 +896,10 @@
return mTouchState != TOUCH_STATE_REST;
}
+ public boolean isHandlingTouch() {
+ return mTouchState != TOUCH_STATE_REST;
+ }
+
protected void determineScrollingStart(MotionEvent ev) {
determineScrollingStart(ev, 1.0f);
}
@@ -1101,22 +1011,12 @@
dampedOverScroll(amount);
}
- /**
- * return true if freescroll has been enabled, false otherwise
- */
- protected void enableFreeScroll() {
- enableFreeScroll(false);
- }
protected void enableFreeScroll(boolean settleOnPageInFreeScroll) {
setEnableFreeScroll(true);
mSettleOnPageInFreeScroll = settleOnPageInFreeScroll;
}
- protected void disableFreeScroll() {
- setEnableFreeScroll(false);
- }
-
private void setEnableFreeScroll(boolean freeScroll) {
boolean wasFreeScroll = mFreeScroll;
mFreeScroll = freeScroll;
@@ -1134,27 +1034,6 @@
mAllowOverScroll = enable;
}
- private int getNearestHoverOverPageIndex() {
- if (mDragView != null) {
- int dragX = (int) (mDragView.getLeft() + (mDragView.getMeasuredWidth() / 2)
- + mDragView.getTranslationX());
- int minDistance = Integer.MAX_VALUE;
- int minIndex = indexOfChild(mDragView);
- int maxPageNo = getChildCount() - 1;
- for (int i = 0; i <= maxPageNo; i++) {
- View page = getPageAt(i);
- int pageX = (page.getLeft() + page.getMeasuredWidth() / 2);
- int d = Math.abs(dragX - pageX);
- if (d < minDistance) {
- minIndex = i;
- minDistance = d;
- }
- }
- return minIndex;
- }
- return -1;
- }
-
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
@@ -1178,11 +1057,7 @@
// Remember where the motion event started
mDownMotionX = mLastMotionX = ev.getX();
- mDownMotionY = mLastMotionY = ev.getY();
- mDownScrollX = getScrollX();
- float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
- mParentDownMotionX = p[0];
- mParentDownMotionY = p[1];
+ mDownMotionY = ev.getY();
mLastMotionXRemainder = 0;
mTotalMotionX = 0;
mActivePointerId = ev.getPointerId(0);
@@ -1215,82 +1090,6 @@
} else {
awakenScrollBars();
}
- } else if (mTouchState == TOUCH_STATE_REORDERING) {
- // Update the last motion position
- mLastMotionX = ev.getX();
- mLastMotionY = ev.getY();
-
- // Update the parent down so that our zoom animations take this new movement into
- // account
- float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
- mParentDownMotionX = pt[0];
- mParentDownMotionY = pt[1];
- updateDragViewTranslationDuringDrag();
-
- // Find the closest page to the touch point
- final int dragViewIndex = indexOfChild(mDragView);
-
- if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX);
- if (DEBUG) Log.d(TAG, "mLastMotionY: " + mLastMotionY);
- if (DEBUG) Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
- if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);
-
- final int pageUnderPointIndex = getNearestHoverOverPageIndex();
- // Do not allow any page to be moved to 0th position.
- if (pageUnderPointIndex > 0 && pageUnderPointIndex != indexOfChild(mDragView)) {
- if (0 <= pageUnderPointIndex && pageUnderPointIndex <= getPageCount() - 1 &&
- pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
- mSidePageHoverIndex = pageUnderPointIndex;
- mSidePageHoverRunnable = new Runnable() {
- @Override
- public void run() {
- // Setup the scroll to the correct page before we swap the views
- snapToPage(pageUnderPointIndex);
-
- // For each of the pages between the paged view and the drag view,
- // animate them from the previous position to the new position in
- // the layout (as a result of the drag view moving in the layout)
- int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
- int lowerIndex = (dragViewIndex < pageUnderPointIndex) ?
- dragViewIndex + 1 : pageUnderPointIndex;
- int upperIndex = (dragViewIndex > pageUnderPointIndex) ?
- dragViewIndex - 1 : pageUnderPointIndex;
- for (int i = lowerIndex; i <= upperIndex; ++i) {
- View v = getChildAt(i);
- // dragViewIndex < pageUnderPointIndex, so after we remove the
- // drag view all subsequent views to pageUnderPointIndex will
- // shift down.
- int oldX = getChildOffset(i);
- int newX = getChildOffset(i + shiftDelta);
-
- // Animate the view translation from its old position to its new
- // position
- ObjectAnimator anim = (ObjectAnimator) v.getTag();
- if (anim != null) {
- anim.cancel();
- }
-
- v.setTranslationX(oldX - newX);
- anim = LauncherAnimUtils.ofFloat(v, View.TRANSLATION_X, 0);
- anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
- anim.start();
- v.setTag(anim);
- }
-
- removeView(mDragView);
- addView(mDragView, pageUnderPointIndex);
- mSidePageHoverIndex = -1;
- if (mPageIndicator != null) {
- mPageIndicator.setActiveMarker(getNextPage());
- }
- }
- };
- postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
- }
- } else {
- removeCallbacks(mSidePageHoverRunnable);
- mSidePageHoverIndex = -1;
- }
} else {
determineScrollingStart(ev);
}
@@ -1391,25 +1190,8 @@
} else {
snapToDestination();
}
- } else if (mTouchState == TOUCH_STATE_REORDERING) {
- // Update the last motion position
- mLastMotionX = ev.getX();
- mLastMotionY = ev.getY();
-
- // Update the parent down so that our zoom animations take this new movement into
- // account
- float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
- mParentDownMotionX = pt[0];
- mParentDownMotionY = pt[1];
- updateDragViewTranslationDuringDrag();
- } else {
- if (!mCancelTap) {
- onUnhandledTap(ev);
- }
}
- // Remove the callback to wait for the side page hover timeout
- removeCallbacks(mSidePageHoverRunnable);
// End any intermediate reordering states
resetTouchState();
break;
@@ -1437,8 +1219,6 @@
private void resetTouchState() {
releaseVelocityTracker();
- endReordering();
- mCancelTap = false;
mTouchState = TOUCH_STATE_REST;
mActivePointerId = INVALID_POINTER;
}
@@ -1452,10 +1232,6 @@
protected void onScrollInteractionEnd() {
}
- protected void onUnhandledTap(MotionEvent ev) {
- Launcher.getLauncher(getContext()).onClick(this);
- }
-
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
@@ -1512,7 +1288,6 @@
// TODO: Make this decision more intelligent.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
- mLastMotionY = ev.getY(newPointerIndex);
mLastMotionXRemainder = 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
if (mVelocityTracker != null) {
@@ -1689,139 +1464,6 @@
if (getNextPage() < getChildCount() -1) snapToPage(getNextPage() + 1);
}
- @Override
- public boolean performLongClick() {
- mCancelTap = true;
- return super.performLongClick();
- }
-
- public static class SavedState extends BaseSavedState {
- int currentPage = -1;
-
- SavedState(Parcelable superState) {
- super(superState);
- }
-
- @Thunk SavedState(Parcel in) {
- super(in);
- currentPage = in.readInt();
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- super.writeToParcel(out, flags);
- out.writeInt(currentPage);
- }
-
- public static final Parcelable.Creator<SavedState> CREATOR =
- new Parcelable.Creator<SavedState>() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
- // Animate the drag view back to the original position
- private void animateDragViewToOriginalPosition() {
- if (mDragView != null) {
- Animator anim = LauncherAnimUtils.ofPropertyValuesHolder(mDragView,
- new PropertyListBuilder()
- .scale(1)
- .translationX(0)
- .translationY(0)
- .build())
- .setDuration(REORDERING_DROP_REPOSITION_DURATION);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- onPostReorderingAnimationCompleted();
- }
- });
- anim.start();
- }
- }
-
- public void onStartReordering() {
- // Set the touch state to reordering (allows snapping to pages, dragging a child, etc.)
- mTouchState = TOUCH_STATE_REORDERING;
- mIsReordering = true;
-
- // We must invalidate to trigger a redraw to update the layers such that the drag view
- // is always drawn on top
- invalidate();
- }
-
- @Thunk void onPostReorderingAnimationCompleted() {
- // Trigger the callback when reordering has settled
- --mPostReorderingPreZoomInRemainingAnimationCount;
- if (mPostReorderingPreZoomInRunnable != null &&
- mPostReorderingPreZoomInRemainingAnimationCount == 0) {
- mPostReorderingPreZoomInRunnable.run();
- mPostReorderingPreZoomInRunnable = null;
- }
- }
-
- public void onEndReordering() {
- mIsReordering = false;
- }
-
- public boolean startReordering(View v) {
- int dragViewIndex = indexOfChild(v);
-
- // Do not allow the first page to be moved around
- if (mTouchState != TOUCH_STATE_REST || dragViewIndex <= 0) return false;
-
- // Check if we are within the reordering range
- if (0 <= dragViewIndex && dragViewIndex <= getPageCount() - 1) {
- // Find the drag view under the pointer
- mDragView = getChildAt(dragViewIndex);
- mDragView.animate().scaleX(1.15f).scaleY(1.15f).setDuration(100).start();
- mDragViewBaselineLeft = mDragView.getLeft();
- mReorderingStarted = true;
-
- snapToPage(getPageNearestToCenterOfScreen());
- disableFreeScroll();
- onStartReordering();
- return true;
- }
- return false;
- }
-
- boolean isReordering(boolean testTouchState) {
- boolean state = mIsReordering;
- if (testTouchState) {
- state &= (mTouchState == TOUCH_STATE_REORDERING);
- }
- return state;
- }
- void endReordering() {
- // For simplicity, we call endReordering sometimes even if reordering was never started.
- // In that case, we don't want to do anything.
- if (!mReorderingStarted) return;
- mReorderingStarted = false;
-
- mPostReorderingPreZoomInRunnable = new Runnable() {
- public void run() {
- // If we haven't flung-to-delete the current child,
- // then we just animate the drag view back into position
- onEndReordering();
-
- enableFreeScroll();
- }
- };
-
- mPostReorderingPreZoomInRemainingAnimationCount =
- NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT;
- // Snap to the current page
- snapToPage(indexOfChild(mDragView), 0);
- // Animate the drag view back to the front position
- animateDragViewToOriginalPosition();
- }
-
/* Accessibility */
@SuppressWarnings("deprecation")
@Override
@@ -1900,4 +1542,9 @@
public boolean onHoverEvent(android.view.MotionEvent event) {
return true;
}
+
+ protected interface ComputePageScrollsLogic {
+
+ boolean shouldIncludeView(View view);
+ }
}
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index 6a4e93b..7fa0e52 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -31,11 +31,17 @@
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.provider.Settings;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Adapter;
import com.android.launcher3.graphics.IconShapeOverride;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.util.SettingsObserver;
import com.android.launcher3.views.ButtonPreference;
+import com.android.launcher3.views.HighlightableListView;
/**
* Settings activity for Launcher. Currently implements the following setting: Allow rotation
@@ -48,6 +54,10 @@
/** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
+ private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
+ private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600;
+ private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -55,11 +65,15 @@
if (savedInstanceState == null) {
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
- .replace(android.R.id.content, new LauncherSettingsFragment())
+ .replace(android.R.id.content, getNewFragment())
.commit();
}
}
+ protected PreferenceFragment getNewFragment() {
+ return new LauncherSettingsFragment();
+ }
+
/**
* This fragment shows the launcher preferences.
*/
@@ -67,9 +81,22 @@
private IconBadgingObserver mIconBadgingObserver;
+ private String mPreferenceKey;
+ private boolean mPreferenceHighlighted = false;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.launcher_preference, container, false);
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ mPreferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY);
+ }
+
getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY);
addPreferencesFromResource(R.xml.launcher_preferences);
@@ -101,6 +128,43 @@
}
@Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ Intent intent = getActivity().getIntent();
+ mPreferenceKey = intent.getStringExtra(EXTRA_FRAGMENT_ARG_KEY);
+ if (isAdded() && !mPreferenceHighlighted && !TextUtils.isEmpty(mPreferenceKey)) {
+ getView().postDelayed(this::highlightPreference, DELAY_HIGHLIGHT_DURATION_MILLIS);
+ }
+ }
+
+ private void highlightPreference() {
+ HighlightableListView list = getView().findViewById(android.R.id.list);
+ Preference pref = findPreference(mPreferenceKey);
+ Adapter adapter = list.getAdapter();
+ if (adapter == null) {
+ return;
+ }
+
+ // Find the position
+ int position = -1;
+ for (int i = adapter.getCount() - 1; i >= 0; i--) {
+ if (pref == adapter.getItem(i)) {
+ position = i;
+ break;
+ }
+ }
+ list.highlightPosition(position);
+ mPreferenceHighlighted = true;
+ }
+
+ @Override
public void onDestroy() {
if (mIconBadgingObserver != null) {
mIconBadgingObserver.unregister();
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index f329f5e..68ad253 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -59,7 +59,6 @@
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
-import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate;
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
@@ -82,6 +81,7 @@
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
import com.android.launcher3.touch.ItemLongClickListener;
+import com.android.launcher3.touch.WorkspaceTouchListener;
import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -242,7 +242,6 @@
private Runnable mOnOverlayHiddenCallback;
private boolean mForceDrawAdjacentPages = false;
- private boolean mPageRearrangeEnabled = false;
// Total over scrollX in the overlay direction.
private float mOverlayTranslation;
@@ -250,8 +249,6 @@
// Handles workspace state transitions
private final WorkspaceStateTransitionAnimation mStateTransitionAnimation;
- private AccessibilityDelegate mPagesAccessibilityDelegate;
-
/**
* Used to inflate the Workspace from XML.
*
@@ -286,6 +283,7 @@
// Attach a scrim
new WorkspaceAndHotseatScrim(this).attach();
+ setOnTouchListener(new WorkspaceTouchListener(mLauncher, this));
}
@Override
@@ -475,7 +473,6 @@
}
CellLayout cl = ((CellLayout) child);
cl.setOnInterceptTouchListener(this);
- cl.setClickable(true);
cl.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
super.onViewAdded(child);
}
@@ -555,10 +552,6 @@
// created CellLayout.
CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
R.layout.workspace_screen, this, false /* attachToRoot */);
- newScreen.setOnLongClickListener(mLongClickListener);
- newScreen.setOnClickListener(mLauncher);
- newScreen.setSoundEffectsEnabled(false);
-
int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx;
int paddingBottom = mLauncher.getDeviceProfile().cellLayoutBottomPaddingPx;
newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
@@ -938,7 +931,6 @@
child.setHapticFeedbackEnabled(false);
child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
-
if (child instanceof DropTarget) {
mDragController.addDropTarget((DropTarget) child);
}
@@ -1378,8 +1370,7 @@
}
private void updateChildrenLayersEnabled() {
- boolean enableChildrenLayers =
- isPageRearrangeEnabled() || mIsSwitchingState || isPageInTransition();
+ boolean enableChildrenLayers = mIsSwitchingState || isPageInTransition();
if (enableChildrenLayers != mChildrenLayersEnabled) {
mChildrenLayersEnabled = enableChildrenLayers;
@@ -1463,40 +1454,6 @@
mOutlineProvider = outlineProvider;
}
- public void onStartReordering() {
- super.onStartReordering();
- // Reordering handles its own animations, disable the automatic ones.
- disableLayoutTransitions();
- }
-
- public void onEndReordering() {
- super.onEndReordering();
-
- if (mLauncher.isWorkspaceLoading()) {
- // Invalid and dangerous operation if workspace is loading
- return;
- }
-
- ArrayList<Long> prevScreenOrder = (ArrayList<Long>) mScreenOrder.clone();
- mScreenOrder.clear();
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- CellLayout cl = ((CellLayout) getChildAt(i));
- mScreenOrder.add(getIdForScreen(cl));
- }
-
- for (int i = 0; i < prevScreenOrder.size(); i++) {
- if (mScreenOrder.get(i) != prevScreenOrder.get(i)) {
- mLauncher.getUserEventDispatcher().logOverviewReorder();
- break;
- }
- }
- LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
-
- // Re-enable auto layout transitions for page deletion.
- enableLayoutTransitions();
- }
-
public void snapToPageFromOverView(int whichPage) {
snapToPage(whichPage, OVERVIEW_TRANSITION_MS, Interpolators.ZOOM_IN);
}
@@ -1556,47 +1513,17 @@
if (!mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) {
int total = getPageCount();
for (int i = 0; i < total; i++) {
- updateAccessibilityFlags(accessibilityFlag, (CellLayout) getPageAt(i), i);
+ updateAccessibilityFlags(accessibilityFlag, (CellLayout) getPageAt(i));
}
setImportantForAccessibility(accessibilityFlag);
}
}
- private void updateAccessibilityFlags(int accessibilityFlag, CellLayout page, int pageNo) {
- if (isPageRearrangeEnabled()) {
- page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
- page.getShortcutsAndWidgets().setImportantForAccessibility(
- IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
- page.setContentDescription(getPageDescription(pageNo));
-
- // No custom action for the first page.
- if (!FeatureFlags.QSB_ON_FIRST_SCREEN || pageNo > 0) {
- if (mPagesAccessibilityDelegate == null) {
- mPagesAccessibilityDelegate = new OverviewScreenAccessibilityDelegate(this);
- }
- page.setAccessibilityDelegate(mPagesAccessibilityDelegate);
- }
- } else {
- page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
- page.getShortcutsAndWidgets().setImportantForAccessibility(accessibilityFlag);
- page.setContentDescription(null);
- page.setAccessibilityDelegate(null);
- }
- }
-
- public void setPageRearrangeEnabled(boolean isEnabled) {
- if (mPageRearrangeEnabled != isEnabled) {
- mPageRearrangeEnabled = isEnabled;
- if (isEnabled) {
- enableFreeScroll();
- } else {
- disableFreeScroll();
- }
- }
- }
-
- public boolean isPageRearrangeEnabled() {
- return mPageRearrangeEnabled;
+ private void updateAccessibilityFlags(int accessibilityFlag, CellLayout page) {
+ page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+ page.getShortcutsAndWidgets().setImportantForAccessibility(accessibilityFlag);
+ page.setContentDescription(null);
+ page.setAccessibilityDelegate(null);
}
public void startDrag(CellLayout.CellInfo cellInfo, DragOptions options) {
@@ -1612,10 +1539,6 @@
protected void enableAccessibleDrag(boolean enable) {
super.enableAccessibleDrag(enable);
setEnableForLayout(mLauncher.getHotseat().getLayout(),enable);
-
- // We need to allow our individual children to become click handlers in this
- // case, so temporarily unset the click handlers.
- setOnClickListener(enable ? null : mLauncher);
}
});
}
@@ -3331,8 +3254,7 @@
&& v instanceof FolderIcon) {
FolderBadgeInfo folderBadgeInfo = new FolderBadgeInfo();
for (ShortcutInfo si : ((FolderInfo) info).contents) {
- folderBadgeInfo.addBadgeInfo(mLauncher.getPopupDataProvider()
- .getBadgeInfoForItem(si));
+ folderBadgeInfo.addBadgeInfo(mLauncher.getBadgeInfoForItem(si));
}
((FolderIcon) v).setBadgeInfo(folderBadgeInfo);
}
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index f6d0248..63c1181 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -18,6 +18,8 @@
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherState.HOTSEAT;
+import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.Animator;
@@ -32,65 +34,14 @@
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.graphics.ViewScrim;
/**
- * A convenience class to update a view's visibility state after an alpha animation.
- */
-class AlphaUpdateListener extends AnimatorListenerAdapter implements ValueAnimator.AnimatorUpdateListener {
- private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
-
- private View mView;
- private boolean mAccessibilityEnabled;
- private boolean mCanceled = false;
-
- public AlphaUpdateListener(View v, boolean accessibilityEnabled) {
- mView = v;
- mAccessibilityEnabled = accessibilityEnabled;
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator arg0) {
- updateVisibility(mView, mAccessibilityEnabled);
- }
-
- public static void updateVisibility(View view, boolean accessibilityEnabled) {
- // We want to avoid the extra layout pass by setting the views to GONE unless
- // accessibility is on, in which case not setting them to GONE causes a glitch.
- int invisibleState = accessibilityEnabled ? View.GONE : View.INVISIBLE;
- if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {
- view.setVisibility(invisibleState);
- } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
- && view.getVisibility() != View.VISIBLE) {
- view.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCanceled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator arg0) {
- if (mCanceled) return;
- updateVisibility(mView, mAccessibilityEnabled);
- }
-
- @Override
- public void onAnimationStart(Animator arg0) {
- // We want the views to be visible for animation, so fade-in/out is visible
- mView.setVisibility(View.VISIBLE);
- }
-}
-
-/**
* Manages the animations between each of the workspace states.
*/
public class WorkspaceStateTransitionAnimation {
- public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter();
-
private final Launcher mLauncher;
private final Workspace mWorkspace;
@@ -107,9 +58,7 @@
public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder,
AnimationConfig config) {
- AnimatedPropertySetter propertySetter =
- new AnimatedPropertySetter(config.duration, builder);
- setWorkspaceProperty(toState, propertySetter);
+ setWorkspaceProperty(toState, config.getProperSetter(builder));
}
public float getFinalScale() {
@@ -135,10 +84,12 @@
propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
scaleAndTranslation[2], Interpolators.ZOOM_IN);
- propertySetter.setViewAlpha(mLauncher.getHotseat(), state.getHoseatAlpha(mLauncher),
+ int elements = state.getVisibleElements(mLauncher);
+ float hotseatAlpha = (elements & HOTSEAT) != 0 ? 1 : 0;
+ propertySetter.setViewAlpha(mLauncher.getHotseat(), hotseatAlpha,
pageAlphaProvider.interpolator);
propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
- state.getHoseatAlpha(mLauncher), pageAlphaProvider.interpolator);
+ hotseatAlpha, pageAlphaProvider.interpolator);
// Set scrim
propertySetter.setFloat(ViewScrim.get(mWorkspace), ViewScrim.PROGRESS,
@@ -162,71 +113,4 @@
propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
pageAlpha, pageAlphaProvider.interpolator);
}
-
- public static class PropertySetter {
-
- public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
- view.setAlpha(alpha);
- AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view.getContext()));
- }
-
- public <T> void setFloat(T target, Property<T, Float> property, float value,
- TimeInterpolator interpolator) {
- property.set(target, value);
- }
-
- public <T> void setInt(T target, Property<T, Integer> property, int value,
- TimeInterpolator interpolator) {
- property.set(target, value);
- }
- }
-
- public static class AnimatedPropertySetter extends PropertySetter {
-
- private final long mDuration;
- private final AnimatorSetBuilder mStateAnimator;
-
- public AnimatedPropertySetter(long duration, AnimatorSetBuilder builder) {
- mDuration = duration;
- mStateAnimator = builder;
- }
-
- @Override
- public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
- if (view.getAlpha() == alpha) {
- return;
- }
- ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
- anim.addListener(new AlphaUpdateListener(
- view, isAccessibilityEnabled(view.getContext())));
- anim.setDuration(mDuration).setInterpolator(interpolator);
- mStateAnimator.play(anim);
- }
-
- @Override
- public <T> void setFloat(T target, Property<T, Float> property, float value,
- TimeInterpolator interpolator) {
- if (property.get(target) == value) {
- return;
- }
- Animator anim = ObjectAnimator.ofFloat(target, property, value);
- anim.setDuration(mDuration).setInterpolator(interpolator);
- mStateAnimator.play(anim);
- }
-
- @Override
- public <T> void setInt(T target, Property<T, Integer> property, int value,
- TimeInterpolator interpolator) {
- if (property.get(target) == value) {
- return;
- }
- Animator anim = ObjectAnimator.ofInt(target, property, value);
- anim.setDuration(mDuration).setInterpolator(interpolator);
- mStateAnimator.play(anim);
- }
-
- private TimeInterpolator getFadeInterpolator(float finalAlpha) {
- return finalAlpha == 0 ? Interpolators.DEACCEL_2 : null;
- }
- }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
deleted file mode 100644
index f9eb2ed..0000000
--- a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2015 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.accessibility;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
-import com.android.launcher3.config.FeatureFlags;
-
-public class OverviewScreenAccessibilityDelegate extends AccessibilityDelegate {
-
- private static final int MOVE_BACKWARD = R.id.action_move_screen_backwards;
- private static final int MOVE_FORWARD = R.id.action_move_screen_forwards;
-
- private final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
- private final Workspace mWorkspace;
-
- public OverviewScreenAccessibilityDelegate(Workspace workspace) {
- mWorkspace = workspace;
-
- Context context = mWorkspace.getContext();
- boolean isRtl = Utilities.isRtl(context.getResources());
- mActions.put(MOVE_BACKWARD, new AccessibilityAction(MOVE_BACKWARD,
- context.getText(isRtl ? R.string.action_move_screen_right :
- R.string.action_move_screen_left)));
- mActions.put(MOVE_FORWARD, new AccessibilityAction(MOVE_FORWARD,
- context.getText(isRtl ? R.string.action_move_screen_left :
- R.string.action_move_screen_right)));
- }
-
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if (host != null) {
- if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS ) {
- int index = mWorkspace.indexOfChild(host);
- mWorkspace.setCurrentPage(index);
- } else if (action == MOVE_FORWARD) {
- movePage(mWorkspace.indexOfChild(host) + 1, host);
- return true;
- } else if (action == MOVE_BACKWARD) {
- movePage(mWorkspace.indexOfChild(host) - 1, host);
- return true;
- }
- }
-
- return super.performAccessibilityAction(host, action, args);
- }
-
- private void movePage(int finalIndex, View view) {
- mWorkspace.onStartReordering();
- mWorkspace.removeView(view);
- mWorkspace.addView(view, finalIndex);
- mWorkspace.onEndReordering();
- mWorkspace.announceForAccessibility(mWorkspace.getContext().getText(R.string.screen_moved));
-
- mWorkspace.updateAccessibilityFlags();
- view.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
- }
-
- @Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
-
- int index = mWorkspace.indexOfChild(host);
- if (index < mWorkspace.getChildCount() - 1) {
- info.addAction(mActions.get(MOVE_FORWARD));
- }
-
- int startIndex = FeatureFlags.QSB_ON_FIRST_SCREEN ? 1 : 0;
- if (index > startIndex) {
- info.addAction(mActions.get(MOVE_BACKWARD));
- }
- }
-}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 3fe5d7a..8f5fcf5 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -25,6 +25,7 @@
import android.os.Process;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Selection;
@@ -192,6 +193,19 @@
return false;
}
+ public String getDescription() {
+ @StringRes int descriptionRes;
+ if (mUsingTabs) {
+ descriptionRes =
+ mViewPager.getNextPage() == 0
+ ? R.string.all_apps_button_personal_label
+ : R.string.all_apps_button_work_label;
+ } else {
+ descriptionRes = R.string.all_apps_button_label;
+ }
+ return getContext().getString(descriptionRes);
+ }
+
public AllAppsRecyclerView getActiveRecyclerView() {
if (!mUsingTabs || mViewPager.getNextPage() == 0) {
return mAH[AdapterHolder.MAIN].recyclerView;
@@ -203,14 +217,14 @@
/**
* Resets the state of AllApps.
*/
- public void reset() {
+ public void reset(boolean animate) {
for (int i = 0; i < mAH.length; i++) {
if (mAH[i].recyclerView != null) {
mAH[i].recyclerView.scrollToTop();
}
}
if (isHeaderVisible()) {
- mHeader.reset();
+ mHeader.reset(animate);
}
// Reset the search bar and base recycler view after transitioning home
mSearchUiManager.resetSearch();
@@ -346,7 +360,7 @@
public void onTabChanged(int pos) {
mHeader.setMainActive(pos == 0);
- reset();
+ reset(true /* animate */);
if (mAH[pos].recyclerView != null) {
mAH[pos].recyclerView.bindFastScrollbar();
@@ -369,6 +383,18 @@
return mHeader;
}
+ public View getSearchView() {
+ return mSearchContainer;
+ }
+
+ public View getContentView() {
+ return mViewPager == null ? getActiveRecyclerView() : mViewPager;
+ }
+
+ public RecyclerViewFastScroller getScrollBar() {
+ return getActiveRecyclerView().getScrollbar();
+ }
+
public void setupHeader() {
mHeader.setVisibility(View.VISIBLE);
mHeader.setup(mAH, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null);
diff --git a/src/com/android/launcher3/allapps/AllAppsPagedView.java b/src/com/android/launcher3/allapps/AllAppsPagedView.java
index 3b4450b..b2e35a4 100644
--- a/src/com/android/launcher3/allapps/AllAppsPagedView.java
+++ b/src/com/android/launcher3/allapps/AllAppsPagedView.java
@@ -17,10 +17,9 @@
import android.content.Context;
import android.util.AttributeSet;
-
import android.view.MotionEvent;
+
import com.android.launcher3.PagedView;
-import com.android.launcher3.R;
public class AllAppsPagedView extends PagedView<PersonalWorkSlidingTabStrip> {
@@ -42,8 +41,8 @@
@Override
protected String getCurrentPageDescription() {
- return getResources().getString(
- getNextPage() == 0 ? R.string.all_apps_personal_tab : R.string.all_apps_work_tab);
+ // Not necessary, tab-bar already has two tabs with their own descriptions.
+ return "";
}
@Override
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 13a42f1..bf8f531 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -1,7 +1,10 @@
package com.android.launcher3.allapps;
+import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
+import static com.android.launcher3.LauncherState.ALL_APPS_HEADER;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS;
import android.animation.Animator;
@@ -13,16 +16,15 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
-import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.SearchUiManager.OnScrollRangeChangeListener;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.util.Themes;
/**
@@ -55,7 +57,6 @@
public static final float PARALLAX_COEFFICIENT = .125f;
private AllAppsContainerView mAppsView;
- private Hotseat mHotseat;
private final Launcher mLauncher;
private final boolean mIsDarkTheme;
@@ -88,7 +89,6 @@
private void onProgressAnimationStart() {
// Initialize values that should not change until #onDragEnd
- mHotseat.setVisibility(View.VISIBLE);
mAppsView.setVisibility(View.VISIBLE);
}
@@ -116,14 +116,10 @@
mProgress = progress;
float shiftCurrent = progress * mShiftRange;
- float workspaceHotseatAlpha = Utilities.boundToRange(progress, 0f, 1f);
- float alpha = 1 - workspaceHotseatAlpha;
-
mAppsView.setTranslationY(shiftCurrent);
float hotseatTranslation = -mShiftRange + shiftCurrent;
if (!mIsVerticalLayout) {
- mAppsView.setAlpha(alpha);
mLauncher.getHotseat().setTranslationY(hotseatTranslation);
mLauncher.getWorkspace().getPageIndicator().setTranslationY(hotseatTranslation);
}
@@ -149,6 +145,7 @@
@Override
public void setState(LauncherState state) {
setProgress(state.getVerticalProgress(mLauncher));
+ setAlphas(state, NO_ANIM_PROPERTY_SETTER);
onProgressAnimationEnd();
}
@@ -161,6 +158,7 @@
AnimatorSetBuilder builder, AnimationConfig config) {
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
+ setAlphas(toState, config.getProperSetter(builder));
// Fail fast
onProgressAnimationEnd();
return;
@@ -174,6 +172,19 @@
anim.addListener(getProgressAnimatorListener());
builder.play(anim);
+
+ setAlphas(toState, config.getProperSetter(builder));
+ }
+
+ private void setAlphas(LauncherState toState, PropertySetter setter) {
+ int visibleElements = toState.getVisibleElements(mLauncher);
+ boolean hasHeader = (visibleElements & ALL_APPS_HEADER) != 0;
+ boolean hasContent = (visibleElements & ALL_APPS_CONTENT) != 0;
+
+ setter.setViewAlpha(mAppsView.getSearchView(), hasHeader ? 1 : 0, LINEAR);
+ setter.setViewAlpha(mAppsView.getContentView(), hasContent ? 1 : 0, LINEAR);
+ setter.setViewAlpha(mAppsView.getScrollBar(), hasContent ? 1 : 0, LINEAR);
+ mAppsView.getFloatingHeaderView().setContentVisibility(hasHeader, hasContent, setter);
}
public AnimatorListenerAdapter getProgressAnimatorListener() {
@@ -190,10 +201,8 @@
};
}
- public void setupViews(AllAppsContainerView appsView, Hotseat hotseat) {
+ public void setupViews(AllAppsContainerView appsView) {
mAppsView = appsView;
- mHotseat = hotseat;
- mHotseat.bringToFront();
mAppsView.getSearchUiManager().addOnScrollRangeChangeListener(this);
}
@@ -210,15 +219,12 @@
private void onProgressAnimationEnd() {
if (Float.compare(mProgress, 1f) == 0) {
mAppsView.setVisibility(View.INVISIBLE);
- mHotseat.setVisibility(View.VISIBLE);
- mAppsView.reset();
+ mAppsView.reset(false /* animate */);
} else if (Float.compare(mProgress, 0f) == 0) {
- mHotseat.setVisibility(View.INVISIBLE);
mAppsView.setVisibility(View.VISIBLE);
mAppsView.onScrollUpEnd();
} else {
mAppsView.setVisibility(View.VISIBLE);
- mHotseat.setVisibility(View.VISIBLE);
}
}
}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index a0dc5a3..461f5b5 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.allapps;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
@@ -29,6 +31,7 @@
import android.widget.LinearLayout;
import com.android.launcher3.R;
+import com.android.launcher3.anim.PropertySetter;
public class FloatingHeaderView extends LinearLayout implements
ValueAnimator.AnimatorUpdateListener {
@@ -57,7 +60,7 @@
}
};
- private ViewGroup mTabLayout;
+ protected ViewGroup mTabLayout;
private AllAppsRecyclerView mMainRV;
private AllAppsRecyclerView mWorkRV;
private AllAppsRecyclerView mCurrentRV;
@@ -65,6 +68,8 @@
private boolean mHeaderCollapsed;
private int mSnappedScrolledY;
private int mTranslationY;
+
+ private boolean mAllowTouchForwarding;
private boolean mForwardToRecyclerView;
protected boolean mTabsHidden;
@@ -91,7 +96,7 @@
mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView);
mParent = (ViewGroup) mMainRV.getParent();
setMainActive(true);
- reset();
+ reset(false);
}
private AllAppsRecyclerView setupRV(AllAppsRecyclerView old, AllAppsRecyclerView updated) {
@@ -158,12 +163,19 @@
}
}
- public void reset() {
- int translateTo = 0;
- mAnimator.setIntValues(mTranslationY, translateTo);
- mAnimator.addUpdateListener(this);
- mAnimator.setDuration(150);
- mAnimator.start();
+ public void reset(boolean animate) {
+ if (mAnimator.isStarted()) {
+ mAnimator.cancel();
+ }
+ if (animate) {
+ mAnimator.setIntValues(mTranslationY, 0);
+ mAnimator.addUpdateListener(this);
+ mAnimator.setDuration(150);
+ mAnimator.start();
+ } else {
+ mTranslationY = 0;
+ apply();
+ }
mHeaderCollapsed = false;
mSnappedScrolledY = -mMaxTranslation;
mCurrentRV.scrollToTop();
@@ -181,6 +193,10 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (!mAllowTouchForwarding) {
+ mForwardToRecyclerView = false;
+ return super.onInterceptTouchEvent(ev);
+ }
calcOffset(mTempOffset);
ev.offsetLocation(mTempOffset.x, mTempOffset.y);
mForwardToRecyclerView = mCurrentRV.onInterceptTouchEvent(ev);
@@ -208,6 +224,19 @@
p.x = getLeft() - mCurrentRV.getLeft() - mParent.getLeft();
p.y = getTop() - mCurrentRV.getTop() - mParent.getTop();
}
+
+ public void setContentVisibility(boolean hasHeader, boolean hasContent, PropertySetter setter) {
+ setter.setViewAlpha(this, hasContent ? 1 : 0, LINEAR);
+ allowTouchForwarding(hasContent);
+ }
+
+ protected void allowTouchForwarding(boolean allow) {
+ mAllowTouchForwarding = allow;
+ }
+
+ public boolean hasVisibleContent() {
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/anim/AlphaUpdateListener.java b/src/com/android/launcher3/anim/AlphaUpdateListener.java
new file mode 100644
index 0000000..04d97a7
--- /dev/null
+++ b/src/com/android/launcher3/anim/AlphaUpdateListener.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.anim;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.view.View;
+
+/**
+ * A convenience class to update a view's visibility state after an alpha animation.
+ */
+public class AlphaUpdateListener extends AnimatorListenerAdapter implements AnimatorUpdateListener {
+ private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
+
+ private View mView;
+ private boolean mAccessibilityEnabled;
+ private boolean mCanceled = false;
+
+ public AlphaUpdateListener(View v, boolean accessibilityEnabled) {
+ mView = v;
+ mAccessibilityEnabled = accessibilityEnabled;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator arg0) {
+ updateVisibility(mView, mAccessibilityEnabled);
+ }
+
+ public static void updateVisibility(View view, boolean accessibilityEnabled) {
+ // We want to avoid the extra layout pass by setting the views to GONE unless
+ // accessibility is on, in which case not setting them to GONE causes a glitch.
+ int invisibleState = accessibilityEnabled ? View.GONE : View.INVISIBLE;
+ if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {
+ view.setVisibility(invisibleState);
+ } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
+ && view.getVisibility() != View.VISIBLE) {
+ view.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCanceled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator arg0) {
+ if (mCanceled) return;
+ updateVisibility(mView, mAccessibilityEnabled);
+ }
+
+ @Override
+ public void onAnimationStart(Animator arg0) {
+ // We want the views to be visible for animation, so fade-in/out is visible
+ mView.setVisibility(View.VISIBLE);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java
new file mode 100644
index 0000000..51580b1
--- /dev/null
+++ b/src/com/android/launcher3/anim/PropertySetter.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 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.anim;
+
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.util.Property;
+import android.view.View;
+
+/**
+ * Utility class for setting a property with or without animation
+ */
+public class PropertySetter {
+
+ public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter();
+
+ public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
+ view.setAlpha(alpha);
+ AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view.getContext()));
+ }
+
+ public <T> void setFloat(T target, Property<T, Float> property, float value,
+ TimeInterpolator interpolator) {
+ property.set(target, value);
+ }
+
+ public <T> void setInt(T target, Property<T, Integer> property, int value,
+ TimeInterpolator interpolator) {
+ property.set(target, value);
+ }
+
+ public static class AnimatedPropertySetter extends PropertySetter {
+
+ private final long mDuration;
+ private final AnimatorSetBuilder mStateAnimator;
+
+ public AnimatedPropertySetter(long duration, AnimatorSetBuilder builder) {
+ mDuration = duration;
+ mStateAnimator = builder;
+ }
+
+ @Override
+ public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
+ if (view.getAlpha() == alpha) {
+ return;
+ }
+ ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
+ anim.addListener(new AlphaUpdateListener(
+ view, isAccessibilityEnabled(view.getContext())));
+ anim.setDuration(mDuration).setInterpolator(interpolator);
+ mStateAnimator.play(anim);
+ }
+
+ @Override
+ public <T> void setFloat(T target, Property<T, Float> property, float value,
+ TimeInterpolator interpolator) {
+ if (property.get(target) == value) {
+ return;
+ }
+ Animator anim = ObjectAnimator.ofFloat(target, property, value);
+ anim.setDuration(mDuration).setInterpolator(interpolator);
+ mStateAnimator.play(anim);
+ }
+
+ @Override
+ public <T> void setInt(T target, Property<T, Integer> property, int value,
+ TimeInterpolator interpolator) {
+ if (property.get(target) == value) {
+ return;
+ }
+ Animator anim = ObjectAnimator.ofInt(target, property, value);
+ anim.setDuration(mDuration).setInterpolator(interpolator);
+ mStateAnimator.play(anim);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 28645dc..78ea419 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -51,6 +51,4 @@
// When enabled shows a work profile tab in all apps
public static final boolean ALL_APPS_TABS_ENABLED = true;
-
- public static final boolean ENABLE_TWO_SWIPE_TARGETS = true;
}
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index f5d0b24..8519365 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -31,21 +31,17 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DropTargetBar;
-import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
-import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@@ -53,24 +49,20 @@
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.util.Thunk;
-import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.BaseDragLayer;
import java.util.ArrayList;
/**
* A ViewGroup that coordinates dragging across its descendants
*/
-public class DragLayer extends InsettableFrameLayout {
+public class DragLayer extends BaseDragLayer<Launcher> {
public static final int ANIMATION_END_DISAPPEAR = 0;
public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
- private final int[] mTmpXY = new int[2];
-
@Thunk DragController mDragController;
- private Launcher mLauncher;
-
// Variables relating to animation of views after drop
private ValueAnimator mDropAnim = null;
private final TimeInterpolator mCubicEaseOutInterpolator = Interpolators.DEACCEL_1_5;
@@ -79,9 +71,6 @@
@Thunk View mAnchorView = null;
private boolean mHoverPointClosesFolder = false;
- private final Rect mHitRect = new Rect();
-
- private TouchCompleteListener mTouchCompleteListener;
private int mTopViewIndex;
private int mChildCountOnLastUpdate = -1;
@@ -89,8 +78,6 @@
// Related to adjacent page hints
private final ViewGroupFocusHelper mFocusIndicatorHelper;
- protected TouchController[] mControllers;
- private TouchController mActiveController;
/**
* Used to create a new DragLayer from XML.
*
@@ -107,10 +94,9 @@
mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
}
- public void setup(Launcher launcher, DragController dragController) {
- mLauncher = launcher;
+ public void setup(DragController dragController) {
mDragController = dragController;
- mControllers = UiFactory.createTouchControllers(mLauncher);
+ mControllers = UiFactory.createTouchControllers(mActivity);
}
public ViewGroupFocusHelper getFocusIndicatorHelper() {
@@ -123,7 +109,7 @@
}
public boolean isEventOverHotseat(MotionEvent ev) {
- return isEventOverView(mLauncher.getHotseat(), ev);
+ return isEventOverView(mActivity.getHotseat(), ev);
}
private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
@@ -131,12 +117,7 @@
}
private boolean isEventOverDropTargetBar(MotionEvent ev) {
- return isEventOverView(mLauncher.getDropTargetBar(), ev);
- }
-
- public boolean isEventOverView(View view, MotionEvent ev) {
- getDescendantRectRelativeToSelf(view, mHitRect);
- return mHitRect.contains((int) ev.getX(), (int) ev.getY());
+ return isEventOverView(mActivity.getDropTargetBar(), ev);
}
@Override
@@ -149,66 +130,33 @@
}
@Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- int action = ev.getAction();
-
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- if (mTouchCompleteListener != null) {
- mTouchCompleteListener.onTouchComplete();
- }
- mTouchCompleteListener = null;
- } else if (action == MotionEvent.ACTION_DOWN) {
- mLauncher.finishAutoCancelActionMode();
- }
- return findActiveController(ev);
- }
-
- private boolean findActiveController(MotionEvent ev) {
- mActiveController = null;
-
- AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
- if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
- mActiveController = topView;
- return true;
- }
-
- if (mLauncher.getStateManager().getState().disableInteraction) {
+ protected boolean findActiveController(MotionEvent ev) {
+ if (mActivity.getStateManager().getState().disableInteraction) {
// You Shall Not Pass!!!
+ mActiveController = null;
return true;
}
-
- if (mDragController.onControllerInterceptTouchEvent(ev)) {
- mActiveController = mDragController;
- return true;
- }
-
- for (TouchController controller : mControllers) {
- if (controller.onControllerInterceptTouchEvent(ev)) {
- mActiveController = controller;
- return true;
- }
- }
- return false;
+ return super.findActiveController(ev);
}
@Override
public boolean onInterceptHoverEvent(MotionEvent ev) {
- if (mLauncher == null || mLauncher.getWorkspace() == null) {
+ if (mActivity == null || mActivity.getWorkspace() == null) {
return false;
}
- Folder currentFolder = Folder.getOpen(mLauncher);
+ Folder currentFolder = Folder.getOpen(mActivity);
if (currentFolder == null) {
return false;
} else {
- AccessibilityManager accessibilityManager = (AccessibilityManager)
- getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+ AccessibilityManager accessibilityManager = (AccessibilityManager)
+ getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
if (accessibilityManager.isTouchExplorationEnabled()) {
final int action = ev.getAction();
boolean isOverFolderOrSearchBar;
switch (action) {
case MotionEvent.ACTION_HOVER_ENTER:
isOverFolderOrSearchBar = isEventOverFolder(currentFolder, ev) ||
- (isInAccessibleDrag() && isEventOverDropTargetBar(ev));
+ (isInAccessibleDrag() && isEventOverDropTargetBar(ev));
if (!isOverFolderOrSearchBar) {
sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
mHoverPointClosesFolder = true;
@@ -218,7 +166,7 @@
break;
case MotionEvent.ACTION_HOVER_MOVE:
isOverFolderOrSearchBar = isEventOverFolder(currentFolder, ev) ||
- (isInAccessibleDrag() && isEventOverDropTargetBar(ev));
+ (isInAccessibleDrag() && isEventOverDropTargetBar(ev));
if (!isOverFolderOrSearchBar && !mHoverPointClosesFolder) {
sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
mHoverPointClosesFolder = true;
@@ -239,14 +187,22 @@
this, AccessibilityEvent.TYPE_VIEW_FOCUSED, getContext().getString(stringId));
}
+ @Override
+ public boolean onHoverEvent(MotionEvent ev) {
+ // If we've received this, we've already done the necessary handling
+ // in onInterceptHoverEvent. Return true to consume the event.
+ return false;
+ }
+
+
private boolean isInAccessibleDrag() {
- return mLauncher.getAccessibilityDelegate().isInAccessibleDrag();
+ return mActivity.getAccessibilityDelegate().isInAccessibleDrag();
}
@Override
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
// Shortcuts can appear above folder
- View topView = AbstractFloatingView.getTopOpenView(mLauncher);
+ View topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null) {
if (child == topView) {
return super.onRequestSendAccessibilityEvent(child, event);
@@ -263,13 +219,13 @@
@Override
public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
- View topView = AbstractFloatingView.getTopOpenView(mLauncher);
+ View topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null) {
// Only add the top view as a child for accessibility when it is open
childrenForAccessibility.add(topView);
if (isInAccessibleDrag()) {
- childrenForAccessibility.add(mLauncher.getDropTargetBar());
+ childrenForAccessibility.add(mActivity.getDropTargetBar());
}
} else {
super.addChildrenForAccessibility(childrenForAccessibility);
@@ -277,103 +233,9 @@
}
@Override
- public boolean onHoverEvent(MotionEvent ev) {
- // If we've received this, we've already done the necessary handling
- // in onInterceptHoverEvent. Return true to consume the event.
- return false;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- int action = ev.getAction();
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- if (mTouchCompleteListener != null) {
- mTouchCompleteListener.onTouchComplete();
- }
- mTouchCompleteListener = null;
- }
-
- if (mActiveController != null) {
- return mActiveController.onControllerTouchEvent(ev);
- } else {
- // In case no child view handled the touch event, we may not get onIntercept anymore
- return findActiveController(ev);
- }
- }
-
- /**
- * Determine the rect of the descendant in this DragLayer's coordinates
- *
- * @param descendant The descendant whose coordinates we want to find.
- * @param r The rect into which to place the results.
- * @return The factor by which this descendant is scaled relative to this DragLayer.
- */
- public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
- mTmpXY[0] = 0;
- mTmpXY[1] = 0;
- float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
-
- r.set(mTmpXY[0], mTmpXY[1],
- (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
- (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
- return scale;
- }
-
- public float getLocationInDragLayer(View child, int[] loc) {
- loc[0] = 0;
- loc[1] = 0;
- return getDescendantCoordRelativeToSelf(child, loc);
- }
-
- public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
- return getDescendantCoordRelativeToSelf(descendant, coord, false);
- }
-
- /**
- * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
- * coordinates.
- *
- * @param descendant The descendant to which the passed coordinate is relative.
- * @param coord The coordinate that we want mapped.
- * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
- * sometimes this is relevant as in a child's coordinates within the root descendant.
- * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
- * this scale factor is assumed to be equal in X and Y, and so if at any point this
- * assumption fails, we will need to return a pair of scale factors.
- */
- public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
- boolean includeRootScroll) {
- return Utilities.getDescendantCoordRelativeToAncestor(descendant, this,
- coord, includeRootScroll);
- }
-
- /**
- * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
- */
- public void mapCoordInSelfToDescendant(View descendant, int[] coord) {
- Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
- }
-
- public void getViewRectRelativeToSelf(View v, Rect r) {
- int[] loc = new int[2];
- getLocationInWindow(loc);
- int x = loc[0];
- int y = loc[1];
-
- v.getLocationInWindow(loc);
- int vX = loc[0];
- int vY = loc[1];
-
- int left = vX - x;
- int top = vY - y;
- r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
- }
-
- @Override
public boolean dispatchUnhandledMove(View focused, int direction) {
- // Consume the unhandled move if a container is open, to avoid switching pages underneath.
- boolean isContainerOpen = AbstractFloatingView.getTopOpenView(mLauncher) != null;
- return isContainerOpen || mDragController.dispatchUnhandledMove(focused, direction);
+ return super.dispatchUnhandledMove(focused, direction)
+ || mDragController.dispatchUnhandledMove(focused, direction);
}
@Override
@@ -386,91 +248,6 @@
}
}
- @Override
- public LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new LayoutParams(getContext(), attrs);
- }
-
- @Override
- protected LayoutParams generateDefaultLayoutParams() {
- return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- }
-
- // Override to allow type-checking of LayoutParams.
- @Override
- protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
- return p instanceof LayoutParams;
- }
-
- @Override
- protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
- return new LayoutParams(p);
- }
-
- public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
- public int x, y;
- public boolean customPosition = false;
-
- public LayoutParams(Context c, AttributeSet attrs) {
- super(c, attrs);
- }
-
- public LayoutParams(int width, int height) {
- super(width, height);
- }
-
- public LayoutParams(ViewGroup.LayoutParams lp) {
- super(lp);
- }
-
- public void setWidth(int width) {
- this.width = width;
- }
-
- public int getWidth() {
- return width;
- }
-
- public void setHeight(int height) {
- this.height = height;
- }
-
- public int getHeight() {
- return height;
- }
-
- public void setX(int x) {
- this.x = x;
- }
-
- public int getX() {
- return x;
- }
-
- public void setY(int y) {
- this.y = y;
- }
-
- public int getY() {
- return y;
- }
- }
-
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
- if (flp instanceof LayoutParams) {
- final LayoutParams lp = (LayoutParams) flp;
- if (lp.customPosition) {
- child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
- }
- }
- }
- }
-
public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
int duration) {
@@ -709,14 +486,14 @@
public void onViewAdded(View child) {
super.onViewAdded(child);
updateChildIndices();
- UiFactory.onLauncherStateOrFocusChanged(mLauncher);
+ UiFactory.onLauncherStateOrFocusChanged(mActivity);
}
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
updateChildIndices();
- UiFactory.onLauncherStateOrFocusChanged(mLauncher);
+ UiFactory.onLauncherStateOrFocusChanged(mActivity);
}
@Override
@@ -768,32 +545,4 @@
mFocusIndicatorHelper.draw(canvas);
super.dispatchDraw(canvas);
}
-
- @Override
- protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
- View topView = AbstractFloatingView.getTopOpenView(mLauncher);
- if (topView != null) {
- return topView.requestFocus(direction, previouslyFocusedRect);
- } else {
- return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
- }
- }
-
- @Override
- public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
- View topView = AbstractFloatingView.getTopOpenView(mLauncher);
- if (topView != null) {
- topView.addFocusables(views, direction);
- } else {
- super.addFocusables(views, direction, focusableMode);
- }
- }
-
- public void setTouchCompleteListener(TouchCompleteListener listener) {
- mTouchCompleteListener = listener;
- }
-
- public interface TouchCompleteListener {
- void onTouchComplete();
- }
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 2b42429..1bdd554 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -207,11 +207,11 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mContent = (FolderPagedView) findViewById(R.id.folder_content);
+ mContent = findViewById(R.id.folder_content);
mContent.setFolder(this);
- mPageIndicator = (PageIndicatorDots) findViewById(R.id.folder_page_indicator);
- mFolderName = (ExtendedEditText) findViewById(R.id.folder_name);
+ mPageIndicator = findViewById(R.id.folder_page_indicator);
+ mFolderName = findViewById(R.id.folder_name);
mFolderName.setOnBackKeyListener(this);
mFolderName.setOnFocusChangeListener(this);
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 6c94273..cb5d872 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -568,7 +568,7 @@
@Override
public void onAdd(ShortcutInfo item, int rank) {
boolean wasBadged = mBadgeInfo.hasBadge();
- mBadgeInfo.addBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item));
+ mBadgeInfo.addBadgeInfo(mLauncher.getBadgeInfoForItem(item));
boolean isBadged = mBadgeInfo.hasBadge();
updateBadgeScale(wasBadged, isBadged);
invalidate();
@@ -578,7 +578,7 @@
@Override
public void onRemove(ShortcutInfo item) {
boolean wasBadged = mBadgeInfo.hasBadge();
- mBadgeInfo.subtractBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item));
+ mBadgeInfo.subtractBadgeInfo(mLauncher.getBadgeInfoForItem(item));
boolean isBadged = mBadgeInfo.hasBadge();
updateBadgeScale(wasBadged, isBadged);
invalidate();
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
index 3393469..34a4e2d 100644
--- a/src/com/android/launcher3/graphics/DrawableFactory.java
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -17,6 +17,7 @@
package com.android.launcher3.graphics;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -70,6 +71,10 @@
return drawable;
}
+ public FastBitmapDrawable newIcon(BitmapInfo info, ActivityInfo target) {
+ return new FastBitmapDrawable(info);
+ }
+
/**
* Returns a FastBitmapDrawable with the icon.
*/
@@ -80,7 +85,6 @@
return new PreloadIconDrawable(info, mPreloadProgressPath, context);
}
-
protected Path getPreloadProgressPath(Context context) {
if (Utilities.ATLEAST_OREO) {
try {
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 4a9cdd9..3b5585b 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -29,11 +29,13 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.os.Build;
@@ -60,6 +62,8 @@
*/
public class LauncherIcons implements AutoCloseable {
+ private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;
+
public static final Object sPoolSync = new Object();
private static LauncherIcons sPool;
@@ -84,6 +88,9 @@
*/
public void recycle() {
synchronized (sPoolSync) {
+ // Clear any temporary state variables
+ mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
+
next = sPool;
sPool = this;
}
@@ -105,6 +112,9 @@
private IconNormalizer mNormalizer;
private ShadowGenerator mShadowGenerator;
+ private Drawable mWrapperIcon;
+ private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
+
// sometimes we store linked lists of these things
private LauncherIcons next;
@@ -172,6 +182,16 @@
* The bitmap is also visually normalized with other icons.
*/
public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk) {
+ return createBadgedIconBitmap(icon, user, iconAppTargetSdk, false);
+ }
+
+ /**
+ * Returns a bitmap suitable for displaying as an icon at various launcher UIs like all apps
+ * view or workspace. The icon is badged for {@param user}.
+ * The bitmap is also visually normalized with other icons.
+ */
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk,
+ boolean isInstantApp) {
float[] scale = new float[1];
icon = normalizeAndWrapToAdaptiveIcon(icon, iconAppTargetSdk, null, scale);
Bitmap bitmap = createIconBitmap(icon, scale[0]);
@@ -190,6 +210,9 @@
} else {
result = createIconBitmap(badged, 1f);
}
+ } else if (isInstantApp) {
+ badgeWithDrawable(bitmap, mContext.getDrawable(R.drawable.ic_instant_app_badge));
+ result = bitmap;
} else {
result = bitmap;
}
@@ -208,13 +231,23 @@
Math.min(scale[0], ShadowGenerator.getScaleForBounds(iconBounds)));
}
+ /**
+ * Sets the background color used for wrapped adaptive icon
+ */
+ public void setWrapperBackgroundColor(int color) {
+ mWrapperBackgroundColor = (Color.alpha(color) < 255) ? DEFAULT_WRAPPER_BACKGROUND : color;
+ }
+
private Drawable normalizeAndWrapToAdaptiveIcon(Drawable icon, int iconAppTargetSdk,
RectF outIconBounds, float[] outScale) {
float scale = 1f;
if (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) {
boolean[] outShape = new boolean[1];
- AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
- mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
+ if (mWrapperIcon == null) {
+ mWrapperIcon = mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper)
+ .mutate();
+ }
+ AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon;
dr.setBounds(0, 0, 1, 1);
scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape);
if (Utilities.ATLEAST_OREO && !outShape[0] && !(icon instanceof AdaptiveIconDrawable)) {
@@ -223,6 +256,8 @@
fsd.setScale(scale);
icon = dr;
scale = getNormalizer().getScale(icon, outIconBounds, null, null);
+
+ ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
}
} else {
scale = getNormalizer().getScale(icon, outIconBounds, null, null);
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index cbdabf3..1fd7078 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -74,6 +74,9 @@
/** Maps keys to their corresponding current group key */
private final Map<String, String> mNotificationGroupKeyMap = new HashMap<>();
+ /** The last notification key that was dismissed from launcher UI */
+ private String mLastKeyDismissedByLauncher;
+
private SettingsObserver mNotificationBadgingObserver;
private final Handler.Callback mWorkerCallback = new Handler.Callback() {
@@ -251,13 +254,25 @@
}
NotificationGroup notificationGroup = mNotificationGroupMap.get(sbn.getGroupKey());
+ String key = sbn.getKey();
if (notificationGroup != null) {
- notificationGroup.removeChildKey(sbn.getKey());
+ notificationGroup.removeChildKey(key);
if (notificationGroup.isEmpty()) {
- cancelNotification(notificationGroup.getGroupSummaryKey());
+ if (key.equals(mLastKeyDismissedByLauncher)) {
+ // Only cancel the group notification if launcher dismissed the last child.
+ cancelNotification(notificationGroup.getGroupSummaryKey());
+ }
mNotificationGroupMap.remove(sbn.getGroupKey());
}
}
+ if (key.equals(mLastKeyDismissedByLauncher)) {
+ mLastKeyDismissedByLauncher = null;
+ }
+ }
+
+ public void cancelNotificationFromLauncher(String key) {
+ mLastKeyDismissedByLauncher = key;
+ cancelNotification(key);
}
@Override
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index e427a81..033fdf8 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -745,7 +745,7 @@
private void updateNotificationHeader() {
ItemInfoWithIcon itemInfo = (ItemInfoWithIcon) mOriginalIcon.getTag();
- BadgeInfo badgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo);
+ BadgeInfo badgeInfo = mLauncher.getBadgeInfoForItem(itemInfo);
if (mNotificationItemView != null && badgeInfo != null) {
mNotificationItemView.updateHeader(
badgeInfo.getNotificationCount(), itemInfo.iconColor);
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 335426c..f1b8ec0 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -206,7 +206,7 @@
if (notificationListener == null) {
return;
}
- notificationListener.cancelNotification(notificationKey);
+ notificationListener.cancelNotificationFromLauncher(notificationKey);
}
public void setAllWidgets(ArrayList<WidgetListRowEntry> allWidgets) {
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 2cc8dfa..a20149e 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -9,6 +9,7 @@
import android.view.View;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
@@ -27,7 +28,7 @@
*
* Example system shortcuts, defined as inner classes, include Widgets and AppInfo.
*/
-public abstract class SystemShortcut extends ItemInfo {
+public abstract class SystemShortcut<T extends BaseDraggingActivity> extends ItemInfo {
public final int iconResId;
public final int labelResId;
@@ -36,10 +37,9 @@
this.labelResId = labelResId;
}
- public abstract View.OnClickListener getOnClickListener(final Launcher launcher,
- final ItemInfo itemInfo);
+ public abstract View.OnClickListener getOnClickListener(T activity, ItemInfo itemInfo);
- public static class Widgets extends SystemShortcut {
+ public static class Widgets extends SystemShortcut<Launcher> {
public Widgets() {
super(R.drawable.ic_widget, R.string.widget_button_text);
@@ -54,17 +54,14 @@
if (widgets == null) {
return null;
}
- return new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- AbstractFloatingView.closeAllOpenViews(launcher);
- WidgetsBottomSheet widgetsBottomSheet =
- (WidgetsBottomSheet) launcher.getLayoutInflater().inflate(
- R.layout.widgets_bottom_sheet, launcher.getDragLayer(), false);
- widgetsBottomSheet.populateAndShow(itemInfo);
- launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
- ControlType.WIDGETS_BUTTON, view);
- }
+ return (view) -> {
+ AbstractFloatingView.closeAllOpenViews(launcher);
+ WidgetsBottomSheet widgetsBottomSheet =
+ (WidgetsBottomSheet) launcher.getLayoutInflater().inflate(
+ R.layout.widgets_bottom_sheet, launcher.getDragLayer(), false);
+ widgetsBottomSheet.populateAndShow(itemInfo);
+ launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
+ ControlType.WIDGETS_BUTTON, view);
};
}
}
@@ -75,18 +72,15 @@
}
@Override
- public View.OnClickListener getOnClickListener(final Launcher launcher,
- final ItemInfo itemInfo) {
- return new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Rect sourceBounds = launcher.getViewBounds(view);
- Bundle opts = launcher.getActivityLaunchOptionsAsBundle(view, false);
- new PackageManagerHelper(launcher).startDetailsActivityForInfo(
- itemInfo, sourceBounds, opts);
- launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
- ControlType.APPINFO_TARGET, view);
- }
+ public View.OnClickListener getOnClickListener(
+ BaseDraggingActivity activity, ItemInfo itemInfo) {
+ return (view) -> {
+ Rect sourceBounds = activity.getViewBounds(view);
+ Bundle opts = activity.getActivityLaunchOptionsAsBundle(view, false);
+ new PackageManagerHelper(activity).startDetailsActivityForInfo(
+ itemInfo, sourceBounds, opts);
+ activity.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
+ ControlType.APPINFO_TARGET, view);
};
}
}
@@ -97,28 +91,29 @@
}
@Override
- public View.OnClickListener getOnClickListener(final Launcher launcher,
- final ItemInfo itemInfo) {
+ public View.OnClickListener getOnClickListener(
+ BaseDraggingActivity activity, ItemInfo itemInfo) {
boolean supportsWebUI = (itemInfo instanceof ShortcutInfo) &&
((ShortcutInfo) itemInfo).hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI);
boolean isInstantApp = false;
if (itemInfo instanceof com.android.launcher3.AppInfo) {
com.android.launcher3.AppInfo appInfo = (com.android.launcher3.AppInfo) itemInfo;
- isInstantApp = InstantAppResolver.newInstance(launcher).isInstantApp(appInfo);
+ isInstantApp = InstantAppResolver.newInstance(activity).isInstantApp(appInfo);
}
boolean enabled = supportsWebUI || isInstantApp;
if (!enabled) {
return null;
}
- return createOnClickListener(launcher, itemInfo);
+ return createOnClickListener(activity, itemInfo);
}
- public View.OnClickListener createOnClickListener(Launcher launcher, ItemInfo itemInfo) {
+ public View.OnClickListener createOnClickListener(
+ BaseDraggingActivity activity, ItemInfo itemInfo) {
return view -> {
Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent(
itemInfo.getTargetComponent().getPackageName());
- launcher.startActivitySafely(view, intent, itemInfo);
- AbstractFloatingView.closeAllOpenViews(launcher);
+ activity.startActivitySafely(view, intent, itemInfo);
+ AbstractFloatingView.closeAllOpenViews(activity);
};
}
}
diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java
index d3c0fef..0a2c3e4 100644
--- a/src/com/android/launcher3/states/InternalStateHandler.java
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -56,8 +56,8 @@
sScheduler.schedule(this);
}
- public void clearReference() {
- sScheduler.clearReference(this);
+ public boolean clearReference() {
+ return sScheduler.clearReference(this);
}
public static boolean handleCreate(Launcher launcher, Intent intent) {
@@ -125,10 +125,12 @@
return false;
}
- public synchronized void clearReference(InternalStateHandler handler) {
+ public synchronized boolean clearReference(InternalStateHandler handler) {
if (mPendingHandler.get() == handler) {
mPendingHandler.clear();
+ return true;
}
+ return false;
}
}
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
new file mode 100644
index 0000000..db53634
--- /dev/null
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -0,0 +1,230 @@
+/*
+ * 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.touch;
+
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.util.TouchController;
+
+/**
+ * TouchController for handling state changes
+ */
+public abstract class AbstractStateChangeTouchController extends AnimatorListenerAdapter
+ implements TouchController, SwipeDetector.Listener {
+
+ private static final String TAG = "ASCTouchController";
+ public static final float RECATCH_REJECTION_FRACTION = .0875f;
+ public static final int SINGLE_FRAME_MS = 16;
+
+ // 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 Launcher mLauncher;
+ protected final SwipeDetector mDetector;
+
+ private boolean mNoIntercept;
+ protected int mStartContainerType;
+
+ protected LauncherState mFromState;
+ protected LauncherState mToState;
+ protected AnimatorPlaybackController mCurrentAnimation;
+
+ private float mStartProgress;
+ // Ratio of transition process [0, 1] to drag displacement (px)
+ private float mProgressMultiplier;
+
+ public AbstractStateChangeTouchController(Launcher l, SwipeDetector.Direction dir) {
+ mLauncher = l;
+ mDetector = new SwipeDetector(l, this, dir);
+ }
+
+ protected abstract boolean canInterceptTouch(MotionEvent ev);
+
+ /**
+ * Initializes the {@code mFromState} and {@code mToState} and swipe direction to use for
+ * the detector. In can of disabling swipe, return 0.
+ */
+ protected abstract int getSwipeDirection(MotionEvent ev);
+
+ @Override
+ public final 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 {
+ directionsToDetectScroll = getSwipeDirection(ev);
+ if (directionsToDetectScroll == 0) {
+ mNoIntercept = true;
+ return false;
+ }
+ }
+ mDetector.setDetectableScrollConditions(
+ directionsToDetectScroll, ignoreSlopWhenSettling);
+ }
+
+ if (mNoIntercept) {
+ return false;
+ }
+
+ onControllerTouchEvent(ev);
+ return mDetector.isDraggingOrSettling();
+ }
+
+ @Override
+ public final boolean onControllerTouchEvent(MotionEvent ev) {
+ return mDetector.onTouchEvent(ev);
+ }
+
+ protected float getShiftRange() {
+ return mLauncher.getAllAppsController().getShiftRange();
+ }
+
+ protected abstract float initCurrentAnimation();
+
+ @Override
+ public void onDragStart(boolean start) {
+ if (mCurrentAnimation == null) {
+ mStartProgress = 0;
+ mProgressMultiplier = initCurrentAnimation();
+
+ mCurrentAnimation.getTarget().addListener(this);
+ mCurrentAnimation.dispatchOnStart();
+ } else {
+ mCurrentAnimation.pause();
+ mStartProgress = mCurrentAnimation.getProgressFraction();
+ }
+ }
+
+ @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 int logAction;
+ final LauncherState targetState;
+ final float progress = mCurrentAnimation.getProgressFraction();
+
+ if (fling) {
+ logAction = Touch.FLING;
+ targetState =
+ Float.compare(Math.signum(velocity), Math.signum(mProgressMultiplier)) == 0
+ ? mToState : mFromState;
+ // snap to top or bottom using the release velocity
+ } else {
+ logAction = Touch.SWIPE;
+ targetState = (progress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState;
+ }
+
+
+ final float endProgress;
+ final float startProgress;
+ final long duration;
+
+ if (targetState == mToState) {
+ endProgress = 1;
+ if (progress >= 1) {
+ duration = 0;
+ startProgress = 1;
+ } else {
+ startProgress = Utilities.boundToRange(
+ progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
+ duration = SwipeDetector.calculateDuration(velocity,
+ endProgress - Math.max(progress, 0));
+ }
+ } else {
+ endProgress = 0;
+ if (progress <= 0) {
+ duration = 0;
+ startProgress = 0;
+ } else {
+ startProgress = Utilities.boundToRange(
+ progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
+ duration = SwipeDetector.calculateDuration(velocity,
+ Math.min(progress, 1) - endProgress);
+ }
+ }
+
+ mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState, logAction));
+ ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
+ anim.setFloatValues(startProgress, endProgress);
+ anim.setDuration(duration).setInterpolator(scrollInterpolatorForVelocity(velocity));
+ anim.start();
+ }
+
+ protected int getDirectionForLog() {
+ return mToState.ordinal > mFromState.ordinal ? Direction.UP : Direction.DOWN;
+ }
+
+ protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+ if (targetState != mFromState) {
+ // Transition complete. log the action
+ mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
+ getDirectionForLog(),
+ mStartContainerType,
+ mFromState.containerType,
+ mToState.containerType,
+ mLauncher.getWorkspace().getCurrentPage());
+ }
+ clearState();
+ mLauncher.getStateManager().goToState(targetState, false /* animated */);
+ }
+
+ protected void clearState() {
+ mCurrentAnimation = null;
+ mDetector.finishedScrolling();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (mCurrentAnimation != null && animation == mCurrentAnimation.getOriginalTarget()) {
+ Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception());
+ clearState();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index f10a695..6f012f6 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -18,6 +18,7 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -78,8 +79,8 @@
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!canStartDrag(launcher)) return false;
// When we have exited all apps or are in transition, disregard long clicks
- if (!launcher.isInState(LauncherState.ALL_APPS) ||
- launcher.getWorkspace().isSwitchingState()) return false;
+ if (!launcher.isInState(ALL_APPS) && !launcher.isInState(OVERVIEW)) return false;
+ if (launcher.getWorkspace().isSwitchingState()) return false;
// Start the drag
final DragController dragController = launcher.getDragController();
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
new file mode 100644
index 0000000..df11686
--- /dev/null
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.touch;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+import static android.view.ViewConfiguration.getLongPressTimeout;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.HapticFeedbackConstants;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.views.OptionsPopupView;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+
+/**
+ * Helper class to handle touch on empty space in workspace and show options popup on long press
+ */
+public class WorkspaceTouchListener implements OnTouchListener, Runnable {
+
+ /**
+ * STATE_PENDING_PARENT_INFORM is the state between longPress performed & the next motionEvent.
+ * This next event is used to send an ACTION_CANCEL to Workspace, to that it clears any
+ * temporary scroll state. After that, the state is set to COMPLETED, and we just eat up all
+ * subsequent motion events.
+ */
+ private static final int STATE_CANCELLED = 0;
+ private static final int STATE_REQUESTED = 1;
+ private static final int STATE_PENDING_PARENT_INFORM = 2;
+ private static final int STATE_COMPLETED = 3;
+
+ private final Rect mTempRect = new Rect();
+ private final Launcher mLauncher;
+ private final Workspace mWorkspace;
+ private final PointF mTouchDownPoint = new PointF();
+
+ private int mLongPressState = STATE_CANCELLED;
+
+ public WorkspaceTouchListener(Launcher launcher, Workspace workspace) {
+ mLauncher = launcher;
+ mWorkspace = workspace;
+ }
+
+ @Override
+ public boolean onTouch(View view, MotionEvent ev) {
+ int action = ev.getActionMasked();
+ if (action == ACTION_DOWN) {
+ // Check if we can handle long press.
+ boolean handleLongPress = AbstractFloatingView.getTopOpenView(mLauncher) == null
+ && mLauncher.isInState(NORMAL);
+
+ if (handleLongPress) {
+ // Check if the event is not near the edges
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ DragLayer dl = mLauncher.getDragLayer();
+ Rect insets = dp.getInsets();
+
+ mTempRect.set(insets.left, insets.top, dl.getWidth() - insets.right,
+ dl.getHeight() - insets.bottom);
+ mTempRect.inset(dp.edgeMarginPx, dp.edgeMarginPx);
+ handleLongPress = mTempRect.contains((int) ev.getX(), (int) ev.getY());
+ }
+
+ cancelLongPress();
+ if (handleLongPress) {
+ mLongPressState = STATE_REQUESTED;
+ mTouchDownPoint.set(ev.getX(), ev.getY());
+ mWorkspace.postDelayed(this, getLongPressTimeout());
+ }
+
+ mWorkspace.onTouchEvent(ev);
+ // Return true to keep receiving touch events
+ return true;
+ }
+
+ if (mLongPressState == STATE_PENDING_PARENT_INFORM) {
+ // Inform the workspace to cancel touch handling
+ ev.setAction(ACTION_CANCEL);
+ mWorkspace.onTouchEvent(ev);
+ ev.setAction(action);
+ mLongPressState = STATE_COMPLETED;
+ }
+
+ if (mLongPressState == STATE_COMPLETED) {
+ // We have handled the touch, so workspace does not need to know anything anymore.
+ return true;
+ } else if (mLongPressState == STATE_REQUESTED) {
+ mWorkspace.onTouchEvent(ev);
+ if (action == ACTION_UP || action == ACTION_CANCEL || mWorkspace.isHandlingTouch()) {
+ cancelLongPress();
+ }
+ return true;
+ } else {
+ // We don't want to handle touch, let workspace handle it as usual.
+ return false;
+ }
+ }
+
+ private void cancelLongPress() {
+ mWorkspace.removeCallbacks(this);
+ mLongPressState = STATE_CANCELLED;
+ }
+
+ @Override
+ public void run() {
+ if (mLongPressState == STATE_REQUESTED) {
+ mLongPressState = STATE_PENDING_PARENT_INFORM;
+ mWorkspace.getParent().requestDisallowInterceptTouchEvent(true);
+
+ mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
+ Action.Direction.NONE, ContainerType.WORKSPACE,
+ mWorkspace.getCurrentPage());
+ OptionsPopupView.show(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/util/InstantAppResolver.java b/src/com/android/launcher3/util/InstantAppResolver.java
index 601a5ab..4485427 100644
--- a/src/com/android/launcher3/util/InstantAppResolver.java
+++ b/src/com/android/launcher3/util/InstantAppResolver.java
@@ -22,7 +22,6 @@
import android.util.Log;
import com.android.launcher3.AppInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -47,8 +46,8 @@
return false;
}
- public boolean isInstantApp(Launcher launcher, String packageName) {
- PackageManager packageManager = launcher.getPackageManager();
+ public boolean isInstantApp(Context context, String packageName) {
+ PackageManager packageManager = context.getPackageManager();
try {
return isInstantApp(packageManager.getPackageInfo(packageName, 0).applicationInfo);
} catch (PackageManager.NameNotFoundException e) {
diff --git a/src/com/android/launcher3/util/VerticalSwipeController.java b/src/com/android/launcher3/util/VerticalSwipeController.java
deleted file mode 100644
index ae5bfd5..0000000
--- a/src/com/android/launcher3/util/VerticalSwipeController.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * 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.util;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.touch.SwipeDetector.Direction;
-
-
-/**
- * Handles vertical touch gesture on the DragLayer allowing transitioning from
- * {@link #mBaseState} to {@link LauncherState#ALL_APPS} and vice-versa.
- */
-public abstract 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;
-
- protected final Launcher mLauncher;
- protected final SwipeDetector mDetector;
- private final LauncherState mBaseState;
- private final LauncherState mTargetState;
-
- private boolean mNoIntercept;
-
- private AnimatorPlaybackController mCurrentAnimation;
- protected LauncherState mToState;
-
- private float mStartProgress;
- // Ratio of transition process [0, 1] to drag displacement (px)
- private float mProgressMultiplier;
-
- public VerticalSwipeController(Launcher l, LauncherState baseState) {
- this(l, baseState, ALL_APPS, SwipeDetector.VERTICAL);
- }
-
- public VerticalSwipeController(
- Launcher l, LauncherState baseState, LauncherState targetState, Direction dir) {
- mLauncher = l;
- mDetector = new SwipeDetector(l, this, dir);
- mBaseState = baseState;
- mTargetState = targetState;
- }
-
- private boolean canInterceptTouch(MotionEvent ev) {
- if (mCurrentAnimation != null) {
- // If we are already animating from a previous state, we can intercept.
- return true;
- }
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
- return false;
- }
- return shouldInterceptTouch(ev);
- }
-
- protected abstract boolean shouldInterceptTouch(MotionEvent ev);
-
- @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;
- }
- }
-
- @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 {
- directionsToDetectScroll = getSwipeDirection(ev);
- }
-
- mDetector.setDetectableScrollConditions(
- directionsToDetectScroll, ignoreSlopWhenSettling);
- }
-
- if (mNoIntercept) {
- return false;
- }
-
- onControllerTouchEvent(ev);
- return mDetector.isDraggingOrSettling();
- }
-
- protected abstract int getSwipeDirection(MotionEvent ev);
-
- @Override
- public boolean onControllerTouchEvent(MotionEvent 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(mTargetState) ? mBaseState : mTargetState;
- mCurrentAnimation = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(mToState, maxAccuracy);
- mCurrentAnimation.getTarget().addListener(this);
- mStartProgress = 0;
- mProgressMultiplier =
- (mLauncher.isInState(mTargetState) ^ isTransitionFlipped() ? 1 : -1) / range;
- mCurrentAnimation.dispatchOnStart();
- } else {
- mCurrentAnimation.pause();
- mStartProgress = mCurrentAnimation.getProgressFraction();
- }
- }
-
- protected boolean isTransitionFlipped() {
- return false;
- }
-
- protected float getShiftRange() {
- return mLauncher.getAllAppsController().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 LauncherState targetState;
- final float progress = mCurrentAnimation.getProgressFraction();
-
- if (fling) {
- if (velocity < 0 ^ isTransitionFlipped()) {
- targetState = mTargetState;
- } else {
- targetState = mBaseState;
- }
- animationDuration = SwipeDetector.calculateDuration(velocity,
- mToState == targetState ? (1 - progress) : progress);
- // snap to top or bottom using the release velocity
- } else {
- if (progress > SUCCESS_TRANSITION_PROGRESS) {
- targetState = mToState;
- animationDuration = SwipeDetector.calculateDuration(velocity, 1 - progress);
- } else {
- targetState = mToState == mTargetState ? mBaseState : mTargetState;
- animationDuration = SwipeDetector.calculateDuration(velocity, progress);
- }
- }
-
- mCurrentAnimation.setEndAction(() -> {
- mLauncher.getStateManager().goToState(targetState, false);
- onTransitionComplete(fling, targetState == mToState);
- mDetector.finishedScrolling();
- mCurrentAnimation = null;
- });
-
- float nextFrameProgress = Utilities.boundToRange(
- progress + velocity * SINGLE_FRAME_MS * mProgressMultiplier, 0f, 1f);
-
- ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
- anim.setFloatValues(nextFrameProgress, targetState == mToState ? 1f : 0f);
- anim.setDuration(animationDuration);
- anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
- anim.start();
- }
-
- protected abstract void onTransitionComplete(boolean wasFling, boolean stateChanged);
-}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
new file mode 100644
index 0000000..489e59e
--- /dev/null
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.views;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.InsettableFrameLayout;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.TouchController;
+
+import java.util.ArrayList;
+
+/**
+ * A viewgroup with utility methods for drag-n-drop and touch interception
+ */
+public abstract class BaseDragLayer<T extends BaseDraggingActivity> extends InsettableFrameLayout {
+
+ protected final int[] mTmpXY = new int[2];
+ protected final Rect mHitRect = new Rect();
+
+ protected final T mActivity;
+
+ protected TouchController[] mControllers;
+ protected TouchController mActiveController;
+ private TouchCompleteListener mTouchCompleteListener;
+
+ public BaseDragLayer(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mActivity = (T) BaseActivity.fromContext(context);
+ }
+
+
+ public boolean isEventOverView(View view, MotionEvent ev) {
+ getDescendantRectRelativeToSelf(view, mHitRect);
+ return mHitRect.contains((int) ev.getX(), (int) ev.getY());
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ int action = ev.getAction();
+
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ if (mTouchCompleteListener != null) {
+ mTouchCompleteListener.onTouchComplete();
+ }
+ mTouchCompleteListener = null;
+ } else if (action == MotionEvent.ACTION_DOWN) {
+ mActivity.finishAutoCancelActionMode();
+ }
+ return findActiveController(ev);
+ }
+
+ protected boolean findActiveController(MotionEvent ev) {
+ mActiveController = null;
+
+ AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
+ if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
+ mActiveController = topView;
+ return true;
+ }
+
+ for (TouchController controller : mControllers) {
+ if (controller.onControllerInterceptTouchEvent(ev)) {
+ mActiveController = controller;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+ // Shortcuts can appear above folder
+ View topView = AbstractFloatingView.getTopOpenView(mActivity);
+ if (topView != null) {
+ if (child == topView) {
+ return super.onRequestSendAccessibilityEvent(child, event);
+ }
+ // Skip propagating onRequestSendAccessibilityEvent for all other children
+ // which are not topView
+ return false;
+ }
+ return super.onRequestSendAccessibilityEvent(child, event);
+ }
+
+ @Override
+ public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
+ View topView = AbstractFloatingView.getTopOpenView(mActivity);
+ if (topView != null) {
+ // Only add the top view as a child for accessibility when it is open
+ childrenForAccessibility.add(topView);
+ } else {
+ super.addChildrenForAccessibility(childrenForAccessibility);
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ int action = ev.getAction();
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ if (mTouchCompleteListener != null) {
+ mTouchCompleteListener.onTouchComplete();
+ }
+ mTouchCompleteListener = null;
+ }
+
+ if (mActiveController != null) {
+ return mActiveController.onControllerTouchEvent(ev);
+ } else {
+ // In case no child view handled the touch event, we may not get onIntercept anymore
+ return findActiveController(ev);
+ }
+ }
+
+ /**
+ * Determine the rect of the descendant in this DragLayer's coordinates
+ *
+ * @param descendant The descendant whose coordinates we want to find.
+ * @param r The rect into which to place the results.
+ * @return The factor by which this descendant is scaled relative to this DragLayer.
+ */
+ public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
+ mTmpXY[0] = 0;
+ mTmpXY[1] = 0;
+ float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
+
+ r.set(mTmpXY[0], mTmpXY[1],
+ (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
+ (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
+ return scale;
+ }
+
+ public float getLocationInDragLayer(View child, int[] loc) {
+ loc[0] = 0;
+ loc[1] = 0;
+ return getDescendantCoordRelativeToSelf(child, loc);
+ }
+
+ public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
+ return getDescendantCoordRelativeToSelf(descendant, coord, false);
+ }
+
+ /**
+ * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
+ * coordinates.
+ *
+ * @param descendant The descendant to which the passed coordinate is relative.
+ * @param coord The coordinate that we want mapped.
+ * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
+ * sometimes this is relevant as in a child's coordinates within the root descendant.
+ * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
+ * this scale factor is assumed to be equal in X and Y, and so if at any point this
+ * assumption fails, we will need to return a pair of scale factors.
+ */
+ public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
+ boolean includeRootScroll) {
+ return Utilities.getDescendantCoordRelativeToAncestor(descendant, this,
+ coord, includeRootScroll);
+ }
+
+ /**
+ * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
+ */
+ public void mapCoordInSelfToDescendant(View descendant, int[] coord) {
+ Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
+ }
+
+ public void getViewRectRelativeToSelf(View v, Rect r) {
+ int[] loc = new int[2];
+ getLocationInWindow(loc);
+ int x = loc[0];
+ int y = loc[1];
+
+ v.getLocationInWindow(loc);
+ int vX = loc[0];
+ int vY = loc[1];
+
+ int left = vX - x;
+ int top = vY - y;
+ r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
+ }
+
+ @Override
+ public boolean dispatchUnhandledMove(View focused, int direction) {
+ // Consume the unhandled move if a container is open, to avoid switching pages underneath.
+ return AbstractFloatingView.getTopOpenView(mActivity) != null;
+ }
+
+ @Override
+ protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+ View topView = AbstractFloatingView.getTopOpenView(mActivity);
+ if (topView != null) {
+ return topView.requestFocus(direction, previouslyFocusedRect);
+ } else {
+ return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
+ }
+ }
+
+ @Override
+ public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+ View topView = AbstractFloatingView.getTopOpenView(mActivity);
+ if (topView != null) {
+ topView.addFocusables(views, direction);
+ } else {
+ super.addFocusables(views, direction, focusableMode);
+ }
+ }
+
+ public void setTouchCompleteListener(TouchCompleteListener listener) {
+ mTouchCompleteListener = listener;
+ }
+
+ public interface TouchCompleteListener {
+ void onTouchComplete();
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return new LayoutParams(getContext(), attrs);
+ }
+
+ @Override
+ protected LayoutParams generateDefaultLayoutParams() {
+ return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }
+
+ // Override to allow type-checking of LayoutParams.
+ @Override
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+ return p instanceof LayoutParams;
+ }
+
+ @Override
+ protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+ return new LayoutParams(p);
+ }
+
+ public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
+ public int x, y;
+ public boolean customPosition = false;
+
+ public LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ }
+
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ }
+
+ public LayoutParams(ViewGroup.LayoutParams lp) {
+ super(lp);
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public void setX(int x) {
+ this.x = x;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public void setY(int y) {
+ this.y = y;
+ }
+
+ public int getY() {
+ return y;
+ }
+ }
+
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
+ if (flp instanceof LayoutParams) {
+ final LayoutParams lp = (LayoutParams) flp;
+ if (lp.customPosition) {
+ child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/BottomUserEducationView.java b/src/com/android/launcher3/views/BottomUserEducationView.java
index ba78cf6..a291fc6 100644
--- a/src/com/android/launcher3/views/BottomUserEducationView.java
+++ b/src/com/android/launcher3/views/BottomUserEducationView.java
@@ -22,11 +22,15 @@
import android.view.LayoutInflater;
import android.view.TouchDelegate;
import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+
public class BottomUserEducationView extends AbstractSlideInView implements Insettable {
private static final String KEY_SHOWED_BOTTOM_USER_EDUCATION = "showed_bottom_user_education";
@@ -90,6 +94,10 @@
// close action.
mLauncher.getSharedPrefs().edit()
.putBoolean(KEY_SHOWED_BOTTOM_USER_EDUCATION, true).apply();
+ sendCustomAccessibilityEvent(
+ BottomUserEducationView.this,
+ AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+ getContext().getString(R.string.bottom_work_tab_user_education_closed));
}
}
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index 01b63be..a11a8c5 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -20,7 +20,6 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Region;
import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
import android.widget.TextView;
diff --git a/src/com/android/launcher3/views/HighlightableListView.java b/src/com/android/launcher3/views/HighlightableListView.java
new file mode 100644
index 0000000..7da979f
--- /dev/null
+++ b/src/com/android/launcher3/views/HighlightableListView.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.views;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.v4.graphics.ColorUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.HeaderViewListAdapter;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
+
+import java.util.ArrayList;
+
+/**
+ * Extension of list view with support for element highlighting.
+ */
+public class HighlightableListView extends ListView {
+
+ private int mPosHighlight = -1;
+ private boolean mColorAnimated = false;
+
+ public HighlightableListView(Context context) {
+ super(context);
+ }
+
+ public HighlightableListView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public HighlightableListView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public void setAdapter(ListAdapter adapter) {
+ super.setAdapter(new HighLightAdapter(adapter));
+ }
+
+ public void highlightPosition(int pos) {
+ if (mPosHighlight == pos) {
+ return;
+ }
+
+ mColorAnimated = false;
+ mPosHighlight = pos;
+ setSelection(mPosHighlight);
+
+ int start = getFirstVisiblePosition();
+ int end = getLastVisiblePosition();
+ if (start <= mPosHighlight && mPosHighlight <= end) {
+ highlightView(getChildAt(mPosHighlight - start));
+ }
+ }
+
+ private void highlightView(View view) {
+ if (Boolean.TRUE.equals(view.getTag(R.id.view_highlighted))) {
+ // already highlighted
+ } else {
+ view.setTag(R.id.view_highlighted, true);
+ view.setTag(R.id.view_unhighlight_background, view.getBackground());
+ view.setBackground(getHighlightBackground());
+ view.postDelayed(() -> {
+ mPosHighlight = -1;
+ unhighlightView(view);
+ }, 15000L);
+ }
+ }
+
+ private void unhighlightView(View view) {
+ if (Boolean.TRUE.equals(view.getTag(R.id.view_highlighted))) {
+ Object background = view.getTag(R.id.view_unhighlight_background);
+ if (background instanceof Drawable) {
+ view.setBackground((Drawable) background);
+ }
+ view.setTag(R.id.view_unhighlight_background, null);
+ view.setTag(R.id.view_highlighted, false);
+ }
+ }
+
+ private class HighLightAdapter extends HeaderViewListAdapter {
+ public HighLightAdapter(ListAdapter adapter) {
+ super(new ArrayList<>(), new ArrayList<>(), adapter);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view = super.getView(position, convertView, parent);
+
+ if (position == mPosHighlight) {
+ highlightView(view);
+ } else {
+ unhighlightView(view);
+ }
+ return view;
+ }
+ }
+
+ private ColorDrawable getHighlightBackground() {
+ int color = ColorUtils.setAlphaComponent(Themes.getColorAccent(getContext()), 26);
+ if (mColorAnimated) {
+ return new ColorDrawable(color);
+ }
+ mColorAnimated = true;
+ ColorDrawable bg = new ColorDrawable(Color.WHITE);
+ ObjectAnimator anim = ObjectAnimator.ofInt(bg, "color", Color.WHITE, color);
+ anim.setEvaluator(new ArgbEvaluator());
+ anim.setDuration(200L);
+ anim.setRepeatMode(ValueAnimator.REVERSE);
+ anim.setRepeatCount(4);
+ anim.start();
+ return bg;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
similarity index 81%
rename from quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java
rename to src/com/android/launcher3/views/OptionsPopupView.java
index ccdcbed..21b6773 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.views;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -29,6 +29,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.widget.Toast;
@@ -43,12 +44,15 @@
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.graphics.ColorScrim;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.widget.WidgetsFullSheet;
/**
* Popup shown on long pressing an empty space in launcher
*/
-public class OptionsPopupView extends AbstractFloatingView implements OnClickListener {
+public class OptionsPopupView extends AbstractFloatingView
+ implements OnClickListener, OnLongClickListener {
private final float mOutlineRadius;
private final Launcher mLauncher;
@@ -81,29 +85,49 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- findViewById(R.id.wallpaper_button).setOnClickListener(this);
- findViewById(R.id.widget_button).setOnClickListener(this);
- findViewById(R.id.settings_button).setOnClickListener(this);
+ attachListeners(findViewById(R.id.wallpaper_button));
+ attachListeners(findViewById(R.id.widget_button));
+ attachListeners(findViewById(R.id.settings_button));
+ }
+
+ private void attachListeners(View view) {
+ view.setOnClickListener(this);
+ view.setOnLongClickListener(this);
}
@Override
public void onClick(View view) {
+ handleViewClick(view, Action.Touch.TAP);
+ }
+
+ @Override
+ public boolean onLongClick(View view) {
+ return handleViewClick(view, Action.Touch.LONGPRESS);
+ }
+
+ private boolean handleViewClick(View view, int action) {
if (view.getId() == R.id.wallpaper_button) {
mLauncher.onClickWallpaperPicker(null);
+ logTap(action, ControlType.WALLPAPER_BUTTON);
close(true);
+ return true;
} else if (view.getId() == R.id.widget_button) {
- if (mLauncher.getPackageManager().isSafeMode()) {
- Toast.makeText(mLauncher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
- } else {
- WidgetsFullSheet.show(mLauncher, true /* animated */);
+ logTap(action, ControlType.WIDGETS_BUTTON);
+ if (onWidgetsClicked(mLauncher)) {
close(true);
+ return true;
}
} else if (view.getId() == R.id.settings_button) {
- mLauncher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
- .setPackage(mLauncher.getPackageName())
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ startSettings(mLauncher);
+ logTap(action, ControlType.SETTINGS_BUTTON);
close(true);
+ return true;
}
+ return false;
+ }
+
+ private void logTap(int action, int controlType) {
+ mLauncher.getUserEventDispatcher().logActionOnControl(action, controlType);
}
@Override
@@ -267,4 +291,20 @@
launcher.getDragLayer().addView(view);
view.animateOpen();
}
+
+ public static boolean onWidgetsClicked(Launcher launcher) {
+ if (launcher.getPackageManager().isSafeMode()) {
+ Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
+ return false;
+ } else {
+ WidgetsFullSheet.show(launcher, true /* animated */);
+ return true;
+ }
+ }
+
+ public static void startSettings(Launcher launcher) {
+ launcher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
+ .setPackage(launcher.getPackageName())
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ }
}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 9d74218..12859c7 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -47,7 +47,7 @@
import com.android.launcher3.StylusEventHelper;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.dragndrop.DragLayer.TouchCompleteListener;
+import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
import java.util.ArrayList;
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
index 2acd29b..c05d30c 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
@@ -63,8 +63,8 @@
}
@Override
- public float getHoseatAlpha(Launcher launcher) {
- return 0;
+ public int getVisibleElements(Launcher launcher) {
+ return ALL_APPS_HEADER | ALL_APPS_CONTENT;
}
@Override
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java
index 76b7e0d..e495477 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java
@@ -1,19 +1,3 @@
-/*
- * 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.uioverrides;
import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -21,31 +5,34 @@
import android.view.MotionEvent;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
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.VerticalSwipeController;
/**
- * Extension of {@link VerticalSwipeController} to switch between NORMAL and ALL_APPS state.
+ * TouchController to switch between NORMAL and ALL_APPS state.
*/
-public class AllAppsSwipeController extends VerticalSwipeController {
-
- private int mStartContainerType;
+public class AllAppsSwipeController extends AbstractStateChangeTouchController {
public AllAppsSwipeController(Launcher l) {
- super(l, NORMAL);
+ super(l, SwipeDetector.VERTICAL);
}
@Override
- protected boolean shouldInterceptTouch(MotionEvent ev) {
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ if (mCurrentAnimation != null) {
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
if (!mLauncher.isInState(NORMAL) && !mLauncher.isInState(ALL_APPS)) {
// Don't listen for the swipe gesture if we are already in some other state.
return false;
}
-
if (mLauncher.isInState(ALL_APPS) && !mLauncher.getAppsView().shouldContainerScroll(ev)) {
return false;
}
@@ -56,8 +43,12 @@
protected int getSwipeDirection(MotionEvent ev) {
if (mLauncher.isInState(ALL_APPS)) {
mStartContainerType = ContainerType.ALLAPPS;
+ mFromState = ALL_APPS;
+ mToState = NORMAL;
return SwipeDetector.DIRECTION_NEGATIVE;
} else {
+ mFromState = NORMAL;
+ mToState = ALL_APPS;
mStartContainerType = mLauncher.getDragLayer().isEventOverHotseat(ev) ?
ContainerType.HOTSEAT : ContainerType.WORKSPACE;
return SwipeDetector.DIRECTION_POSITIVE;
@@ -65,14 +56,14 @@
}
@Override
- protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
- if (stateChanged) {
- // Transition complete. log the action
- mLauncher.getUserEventDispatcher().logActionOnContainer(
- wasFling ? Touch.FLING : Touch.SWIPE,
- mLauncher.isInState(ALL_APPS) ? Direction.UP : Direction.DOWN,
- mStartContainerType,
- mLauncher.getWorkspace().getCurrentPage());
- }
+ protected float initCurrentAnimation() {
+ float range = getShiftRange();
+ long maxAccuracy = (long) (2 * range);
+ mCurrentAnimation = mLauncher.getStateManager()
+ .createAnimationToNewWorkspace(mToState, maxAccuracy);
+ float startVerticalShift = mFromState.getVerticalProgress(mLauncher) * range;
+ float endVerticalShift = mToState.getVerticalProgress(mLauncher) * range;
+ float totalShift = endVerticalShift - startVerticalShift;
+ return 1 / totalShift;
}
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java
index 88a1e10..d9ce87c 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java
@@ -27,13 +27,13 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.views.OptionsPopupView;
/**
* Accessibility delegate with actions pointing to various Overview entry points.
*/
public class OverviewAccessibilityDelegate extends AccessibilityDelegate {
- private static final int OVERVIEW = R.string.accessibility_action_overview;
private static final int WALLPAPERS = R.string.wallpaper_button_text;
private static final int WIDGETS = R.string.widget_button_text;
private static final int SETTINGS = R.string.settings_button_text;
@@ -43,7 +43,6 @@
super.onInitializeAccessibilityNodeInfo(host, info);
Context context = host.getContext();
- info.addAction(new AccessibilityAction(OVERVIEW, context.getText(OVERVIEW)));
if (Utilities.isWallpaperAllowed(context)) {
info.addAction(new AccessibilityAction(WALLPAPERS, context.getText(WALLPAPERS)));
@@ -55,18 +54,13 @@
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
Launcher launcher = Launcher.getLauncher(host.getContext());
- OverviewPanel overviewPanel = launcher.findViewById(R.id.overview_panel);
- if (action == OVERVIEW) {
- launcher.getStateManager().goToState(LauncherState.OVERVIEW);
- return true;
- } else if (action == WALLPAPERS) {
+ if (action == WALLPAPERS) {
launcher.onClickWallpaperPicker(host);
return true;
} else if (action == WIDGETS) {
- overviewPanel.onClickAddWidgetButton();
- return true;
+ return OptionsPopupView.onWidgetsClicked(launcher);
} else if (action == SETTINGS) {
- overviewPanel.onClickSettingsButton(host);
+ OptionsPopupView.startSettings(launcher);
return true;
}
return super.performAccessibilityAction(host, action, args);
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
deleted file mode 100644
index 616e25c..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * 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.uioverrides;
-
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.WorkspaceStateTransitionAnimation.NO_ANIM_PROPERTY_SETTER;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.Toast;
-
-import com.android.launcher3.Insettable;
-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.Utilities;
-import com.android.launcher3.WorkspaceStateTransitionAnimation.AnimatedPropertySetter;
-import com.android.launcher3.WorkspaceStateTransitionAnimation.PropertySetter;
-import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
-import com.android.launcher3.widget.WidgetsFullSheet;
-
-public class OverviewPanel extends LinearLayout implements Insettable, View.OnClickListener,
- View.OnLongClickListener, LauncherStateManager.StateHandler {
-
- // Out of 100, the percent of space the overview bar should try and take vertically.
- private static final float OVERVIEW_ICON_ZONE_RATIO = 0.22f;
-
- private final Launcher mLauncher;
-
- public OverviewPanel(Context context) {
- this(context, null);
- }
-
- public OverviewPanel(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public OverviewPanel(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
- setAlpha(0);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- int visibleChildCount = 3;
- // Attach buttons.
- attachListeners(findViewById(R.id.wallpaper_button));
- attachListeners(findViewById(R.id.widget_button));
-
- View settingsButton = findViewById(R.id.settings_button);
- if (mLauncher.hasSettings()) {
- attachListeners(settingsButton);
- } else {
- settingsButton.setVisibility(GONE);
- visibleChildCount--;
- }
-
- // Init UI
- Resources res = getResources();
- int itemWidthPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_item_width);
- int spacerWidthPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_spacer_width);
-
- int totalItemWidth = visibleChildCount * itemWidthPx;
- int maxWidth = totalItemWidth + (visibleChildCount - 1) * spacerWidthPx;
-
- getLayoutParams().width = Math.min(mLauncher.getDeviceProfile().availableWidthPx, maxWidth);
- getLayoutParams().height = getButtonBarHeight(mLauncher);
- }
-
- private void attachListeners(View view) {
- view.setOnClickListener(this);
- view.setOnLongClickListener(this);
- }
-
- @Override
- public void setInsets(Rect insets) {
- ((FrameLayout.LayoutParams) getLayoutParams()).bottomMargin = insets.bottom;
- }
-
- @Override
- public void onClick(View view) {
- handleViewClick(view, Action.Touch.TAP);
- }
-
- @Override
- public boolean onLongClick(View view) {
- return handleViewClick(view, Action.Touch.LONGPRESS);
- }
-
- private boolean handleViewClick(View view, int action) {
- if (mLauncher.getWorkspace().isSwitchingState()) {
- return false;
- }
-
- final int controlType;
- if (view.getId() == R.id.wallpaper_button) {
- mLauncher.onClickWallpaperPicker(view);
- controlType = ControlType.WALLPAPER_BUTTON;
- } else if (view.getId() == R.id.widget_button) {
- onClickAddWidgetButton();
- controlType = ControlType.WIDGETS_BUTTON;
- } else if (view.getId() == R.id.settings_button) {
- onClickSettingsButton(view);
- controlType = ControlType.SETTINGS_BUTTON;
- } else {
- return false;
- }
-
- mLauncher.getUserEventDispatcher().logActionOnControl(action, controlType);
- return true;
- }
-
- /**
- * Event handler for the (Add) Widgets button that appears after a long press
- * on the home screen.
- */
- public void onClickAddWidgetButton() {
- if (getContext().getPackageManager().isSafeMode()) {
- Toast.makeText(mLauncher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
- } else {
- WidgetsFullSheet.show(mLauncher, true /* animated */);
- }
- }
-
- /**
- * Event handler for a click on the settings button that appears after a long press
- * on the home screen.
- */
- public void onClickSettingsButton(View v) {
- Intent intent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
- .setPackage(getContext().getPackageName());
- intent.setSourceBounds(mLauncher.getViewBounds(v));
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- getContext().startActivity(intent, mLauncher.getActivityLaunchOptionsAsBundle(v, false));
- }
-
- @Override
- public void setState(LauncherState state) {
- setState(state, NO_ANIM_PROPERTY_SETTER);
- }
-
- @Override
- public void setStateWithAnimation(LauncherState toState,
- AnimatorSetBuilder builder, AnimationConfig config) {
- setState(toState, new AnimatedPropertySetter(config.duration, builder));
- }
-
- private void setState(LauncherState state, PropertySetter setter) {
- float myAlpha = state == OVERVIEW ? 1 : 0;
- setter.setViewAlpha(this, myAlpha, Interpolators.ACCEL);
- }
-
- public static int getButtonBarHeight(Launcher launcher) {
- int zoneHeight = (int) (OVERVIEW_ICON_ZONE_RATIO *
- launcher.getDeviceProfile().availableHeightPx);
- Resources res = launcher.getResources();
- int overviewModeMinIconZoneHeightPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_min_icon_zone_height);
- int overviewModeMaxIconZoneHeightPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_max_icon_zone_height);
- return Utilities.boundToRange(zoneHeight,
- overviewModeMinIconZoneHeightPx,
- overviewModeMaxIconZoneHeightPx);
- }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
index 37d0aa2..8def0d3 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
@@ -16,16 +16,8 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
-import android.graphics.Rect;
-import android.view.View;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
@@ -33,56 +25,7 @@
*/
public class OverviewState extends LauncherState {
- // The percent to shrink the workspace during overview mode
- private static final float SCALE_FACTOR = 0.7f;
-
- private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
- FLAG_DISABLE_PAGE_CLIPPING | FLAG_PAGE_BACKGROUNDS | FLAG_OVERVIEW_UI;
-
public OverviewState(int id) {
- super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
- }
-
- @Override
- public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
- DeviceProfile grid = launcher.getDeviceProfile();
- Workspace ws = launcher.getWorkspace();
- Rect insets = launcher.getDragLayer().getInsets();
-
- int overviewButtonBarHeight = OverviewPanel.getButtonBarHeight(launcher);
- int scaledHeight = (int) (SCALE_FACTOR * ws.getNormalChildHeight());
- int workspaceTop = insets.top + grid.workspacePadding.top;
- int workspaceBottom = ws.getHeight() - insets.bottom - grid.workspacePadding.bottom;
- int overviewTop = insets.top;
- int overviewBottom = ws.getHeight() - insets.bottom - overviewButtonBarHeight;
- int workspaceOffsetTopEdge =
- workspaceTop + ((workspaceBottom - workspaceTop) - scaledHeight) / 2;
- int overviewOffsetTopEdge = overviewTop + (overviewBottom - overviewTop - scaledHeight) / 2;
- return new float[] {SCALE_FACTOR, 0, -workspaceOffsetTopEdge + overviewOffsetTopEdge };
- }
-
- @Override
- public float getHoseatAlpha(Launcher launcher) {
- return 0;
- }
-
- @Override
- public void onStateEnabled(Launcher launcher) {
- launcher.getWorkspace().setPageRearrangeEnabled(true);
-
- if (isAccessibilityEnabled(launcher)) {
- launcher.getOverviewPanel().getChildAt(0).performAccessibilityAction(
- AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
- }
- }
-
- @Override
- public void onStateDisabled(Launcher launcher) {
- launcher.getWorkspace().setPageRearrangeEnabled(false);
- }
-
- @Override
- public View getFinalFocus(Launcher launcher) {
- return launcher.getOverviewPanel();
+ super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, FLAG_DISABLE_RESTORE);
}
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/PinchToOverviewListener.java b/src_ui_overrides/com/android/launcher3/uioverrides/PinchToOverviewListener.java
deleted file mode 100644
index a7c8cee..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/PinchToOverviewListener.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides;
-
-import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.ScaleGestureDetector.OnScaleGestureListener;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.Workspace;
-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 extends AnimatorListenerAdapter
- implements TouchController, OnScaleGestureListener {
-
- private static final float ACCEPT_THRESHOLD = 0.65f;
- /**
- * The velocity threshold at which a pinch will be completed instead of canceled,
- * even if the first threshold has not been passed. Measured in scale / millisecond
- */
- private static final float FLING_VELOCITY = 0.001f;
-
- private final ScaleGestureDetector mPinchDetector;
- private Launcher mLauncher;
- private Workspace mWorkspace = null;
- private boolean mPinchStarted = false;
-
- private AnimatorPlaybackController mCurrentAnimation;
- private float mCurrentScale;
- private boolean mShouldGoToFinalState;
-
- private LauncherState mToState;
-
- public PinchToOverviewListener(Launcher launcher) {
- mLauncher = launcher;
- mPinchDetector = new ScaleGestureDetector(mLauncher, this);
- }
-
- public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- mPinchDetector.onTouchEvent(ev);
- return mPinchStarted;
- }
-
- public boolean onControllerTouchEvent(MotionEvent ev) {
- return mPinchDetector.onTouchEvent(ev);
- }
-
- @Override
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- if (isAccessibilityEnabled(mLauncher)) {
- return false;
- }
- if (!mLauncher.isInState(NORMAL) && !mLauncher.isInState(OVERVIEW)) {
- // Don't listen for the pinch gesture if on all apps, widget picker, -1, etc.
- return false;
- }
- if (mCurrentAnimation != null) {
- // Don't listen for the pinch gesture if we are already animating from a previous one.
- return false;
- }
- if (mLauncher.isWorkspaceLocked()) {
- // Don't listen for the pinch gesture if the workspace isn't ready.
- return false;
- }
- if (mWorkspace == null) {
- mWorkspace = mLauncher.getWorkspace();
- }
- if (mWorkspace.isSwitchingState()) {
- // Don't listen for the pinch gesture while switching state, as it will cause a jump
- // once the state switching animation is complete.
- return false;
- }
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
- // Don't listen for the pinch gesture if a floating view is open.
- return false;
- }
-
- if (mLauncher.getDragController().isDragging()) {
- mLauncher.getDragController().cancelDrag();
- }
-
- mToState = mLauncher.isInState(OVERVIEW) ? NORMAL : OVERVIEW;
- mCurrentAnimation = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(mToState, OVERVIEW_TRANSITION_MS);
- mCurrentAnimation.getTarget().addListener(this);
- mPinchStarted = true;
- mCurrentScale = 1;
- mShouldGoToFinalState = false;
-
- mCurrentAnimation.dispatchOnStart();
- return true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mCurrentAnimation = null;
- mPinchStarted = false;
- }
-
- @Override
- public void onScaleEnd(ScaleGestureDetector detector) {
- if (mShouldGoToFinalState) {
- mCurrentAnimation.start();
- } else {
- mCurrentAnimation.setEndAction(new Runnable() {
- @Override
- public void run() {
- mLauncher.getStateManager().goToState(
- mToState == OVERVIEW ? NORMAL : OVERVIEW, false);
- }
- });
- mCurrentAnimation.reverse();
- }
- }
-
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
- mCurrentScale = detector.getScaleFactor() * mCurrentScale;
-
- // If we are zooming out, inverse the mCurrentScale so that animationFraction = [0, 1]
- // 0 => Animation complete
- // 1=> Animation started
- float animationFraction = mToState == OVERVIEW ? mCurrentScale : (1 / mCurrentScale);
-
- float velocity = (1 - detector.getScaleFactor()) / detector.getTimeDelta();
- if (Math.abs(velocity) >= FLING_VELOCITY) {
- LauncherState toState = velocity > 0 ? OVERVIEW : NORMAL;
- mShouldGoToFinalState = toState == mToState;
- } else {
- mShouldGoToFinalState = animationFraction <= ACCEPT_THRESHOLD;
- }
-
- // Move the transition animation to that duration.
- mCurrentAnimation.setPlayFraction(1 - animationFraction);
- return true;
- }
-}
\ No newline at end of file
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index de75ac9..1227dfe 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -16,9 +16,6 @@
package com.android.launcher3.uioverrides;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
-import android.graphics.PointF;
import android.view.View.AccessibilityDelegate;
import com.android.launcher3.Launcher;
@@ -29,7 +26,7 @@
public static TouchController[] createTouchControllers(Launcher launcher) {
return new TouchController[] {
- new AllAppsSwipeController(launcher), new PinchToOverviewListener(launcher)};
+ launcher.getDragController(), new AllAppsSwipeController(launcher)};
}
public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() {
@@ -38,14 +35,9 @@
public static StateHandler[] getStateHandler(Launcher launcher) {
return new StateHandler[] {
- (OverviewPanel) launcher.getOverviewPanel(),
launcher.getAllAppsController(), launcher.getWorkspace() };
}
- public static void onWorkspaceLongPress(Launcher launcher, PointF touchPoint) {
- launcher.getStateManager().goToState(OVERVIEW);
- }
-
public static void resetOverview(Launcher launcher) { }
public static void onLauncherStateOrFocusChanged(Launcher launcher) { }