diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml index bb03f50763..c24850d847 100644 --- a/AndroidManifest-common.xml +++ b/AndroidManifest-common.xml @@ -87,9 +87,11 @@ android:process=":wallpaper_chooser" android:permission="android.permission.BIND_JOB_SERVICE" /> - + diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 6ef78285f2..c3ddfd62b8 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -71,7 +71,7 @@ android:clearTaskOnLaunch="true" android:stateNotNeeded="true" android:windowSoftInputMode="adjustPan" - android:screenOrientation="nosensor" + android:screenOrientation="unspecified" android:configChanges="keyboard|keyboardHidden|navigation" android:resizeableActivity="true" android:resumeWhilePausing="true" diff --git a/proguard.flags b/proguard.flags index b8cade5726..cac8930d5d 100644 --- a/proguard.flags +++ b/proguard.flags @@ -102,6 +102,11 @@ public (...); } +# InstantAppResolver +-keep class com.android.quickstep.InstantAppResolverImpl { + public (...); +} + -keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** { *; } diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml index 02b4379bf6..d531a463b0 100644 --- a/quickstep/AndroidManifest.xml +++ b/quickstep/AndroidManifest.xml @@ -36,8 +36,13 @@ android:restoreAnyVersion="true" android:supportsRtl="true" > - + + + + + diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar index d5859a7a54..9006831b02 100644 Binary files a/quickstep/libs/sysui_shared.jar and b/quickstep/libs/sysui_shared.jar differ diff --git a/res/layout/widgets_bottom_sheet_scrim.xml b/quickstep/res/layout/fallback_recents_activity.xml similarity index 54% rename from res/layout/widgets_bottom_sheet_scrim.xml rename to quickstep/res/layout/fallback_recents_activity.xml index 6c6626c1d2..c41684455b 100644 --- a/res/layout/widgets_bottom_sheet_scrim.xml +++ b/quickstep/res/layout/fallback_recents_activity.xml @@ -1,5 +1,5 @@ - - - - \ No newline at end of file + android:layout_height="match_parent"> + + + + \ No newline at end of file diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml index 9f4f8a153f..54a90cfe84 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. --> - - - - \ No newline at end of file + \ No newline at end of file diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml index 91b6aa3361..0ac2b11030 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. --> - - - \ No newline at end of file + \ No newline at end of file diff --git a/quickstep/res/layout/task_menu.xml b/quickstep/res/layout/task_menu.xml index 6e3fb4fbdb..b8466652e5 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. --> - - \ No newline at end of file + \ No newline at end of file diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 0956048429..849719191c 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -16,24 +16,21 @@ - 24dp - 24dp 48dp 12dp 2dp 20dp 10dp + 100dp + + 600dp 500dp 250dp - -24dp - - - 90dp - 25dp 80dp diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml index ba99d81c07..2bd9f8f6f3 100644 --- a/quickstep/res/values/override.xml +++ b/quickstep/res/values/override.xml @@ -16,5 +16,7 @@ com.android.launcher3.LauncherAppTransitionManagerImpl + + com.android.quickstep.InstantAppResolverImpl diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 0fe29e35dc..ba0cbfa77d 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -16,7 +16,8 @@ package com.android.launcher3; -import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA; +import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; +import static com.android.launcher3.LauncherState.NORMAL; 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; @@ -31,11 +32,13 @@ import android.animation.ObjectAnimator; 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; import android.graphics.Matrix; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Handler; import android.util.Log; @@ -47,14 +50,18 @@ import android.view.animation.Interpolator; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.InsettableFrameLayout.LayoutParams; import com.android.launcher3.allapps.AllAppsTransitionController; +import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.graphics.DrawableFactory; +import com.android.launcher3.shortcuts.DeepShortcutTextView; +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; @@ -74,12 +81,16 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag 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 = 150; + private static final int LAUNCHER_RESUME_START_DELAY = 100; private static final int CLOSING_TRANSITION_DURATION_MS = 350; // Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down. @@ -151,6 +162,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag @Override public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) { if (hasControlRemoteAppTransitionPermission()) { + TaskView taskView = findTaskViewToLaunch(launcher, v); try { RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) { @Override @@ -160,8 +172,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag // processed before the next frame. postAtFrontOfQueueAsynchronously(v.getHandler(), () -> { final boolean removeTrackingView; - LauncherTransitionAnimator animator = - composeRecentsLaunchAnimator(v, targets); + LauncherTransitionAnimator animator = composeRecentsLaunchAnimator( + taskView == null ? v : taskView, targets); if (animator != null) { // We are animating the task view directly, do not remove it after removeTrackingView = false; @@ -201,8 +213,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag } }; - return ActivityOptionsCompat.makeRemoteAnimation( - new RemoteAnimationAdapterCompat(runner, 500, 380)); + int duration = taskView != 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. @@ -211,20 +225,66 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return getDefaultActivityLaunchOptions(launcher, v); } + /** + * 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 TaskView findTaskViewToLaunch(Launcher launcher, View v) { + if (v instanceof TaskView) { + return (TaskView) v; + } + if (!launcher.isInState(LauncherState.OVERVIEW)) { + return null; + } + if (v.getTag() instanceof ItemInfo) { + ItemInfo itemInfo = (ItemInfo) v.getTag(); + ComponentName componentName = itemInfo.getTargetComponent(); + if (componentName != null) { + RecentsView recentsView = launcher.getOverviewPanel(); + 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; + } + } + } + } + } + return null; + } + /** * Composes the animations for a launch from the recents list if possible. */ private LauncherTransitionAnimator composeRecentsLaunchAnimator(View v, RemoteAnimationTargetCompat[] targets) { + RecentsView recentsView = mLauncher.getOverviewPanel(); + boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING); + MutableBoolean skipLauncherChanges = new MutableBoolean(!launcherClosing); + if (v instanceof TaskView) { + // We already found a task view to launch, so use that for the animation. + TaskView taskView = (TaskView) v; + return new LauncherTransitionAnimator(getRecentsLauncherAnimator(recentsView, taskView), + getRecentsWindowAnimator(taskView, skipLauncherChanges, targets)); + } + + // 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. + // Ensure recents is actually visible - if (!mLauncher.isInState(LauncherState.OVERVIEW)) { + if (!mLauncher.getStateManager().getState().overviewUi) { return null; } // Resolve the opening task id int openingTaskId = -1; for (RemoteAnimationTargetCompat target : targets) { - if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) { + if (target.mode == MODE_OPENING) { openingTaskId = target.taskId; break; } @@ -237,15 +297,40 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag // 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; } // Found a visible recents task that matches the opening app, lets launch the app from there - return new LauncherTransitionAnimator(getRecentsLauncherAnimator(recentsView, taskView), - getRecentsWindowAnimator(taskView, targets)); + Animator launcherAnim; + 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(); + } + }; + } else { + AnimatorPlaybackController controller = + mLauncher.getStateManager() + .createAnimationToNewWorkspace(NORMAL, RECENTS_LAUNCH_DURATION); + controller.dispatchOnStart(); + launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION); + windowAnimEndListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mLauncher.getStateManager().goToState(NORMAL, false); + } + }; + } + + Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, targets); + windowAnim.addListener(windowAnimEndListener); + return new LauncherTransitionAnimator(launcherAnim, windowAnim, skipLauncherChanges); } /** @@ -260,15 +345,16 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag int launchedTaskIndex = recentsView.indexOfChild(v); int centerTaskIndex = recentsView.getCurrentPage(); 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, new PropertyListBuilder() .scale(adjacentPage1.getScaleX() * mRecentsScale) .translationY(mRecentsTransY) - .translationX(mIsRtl ? mRecentsTransX : -mRecentsTransX) + .translationX(isRtl ? mRecentsTransX : -mRecentsTransX) .build()); launcherAnimator.play(adjacentTask1ScaleAndTranslate); } @@ -279,11 +365,11 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag new PropertyListBuilder() .scale(adjacentTask2.getScaleX() * mRecentsScale) .translationY(mRecentsTransY) - .translationX(mIsRtl ? -mRecentsTransX : mRecentsTransX) + .translationX(isRtl ? -mRecentsTransX : mRecentsTransX) .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()); @@ -291,11 +377,11 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag LauncherAnimUtils.ofPropertyValuesHolder(centerTask, new PropertyListBuilder() .scale(v.getScaleX()) - .translationX(mIsRtl ? -translationX : translationX) + .translationX(isRtl ? -translationX : translationX) .build()); launcherAnimator.play(centerTaskParallaxToRight); int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex); - if (otherAdjacentTaskIndex >= recentsView.getFirstTaskIndex() + if (otherAdjacentTaskIndex >= 0 && otherAdjacentTaskIndex < recentsView.getPageCount()) { TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt( otherAdjacentTaskIndex); @@ -303,7 +389,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask, new PropertyListBuilder() .translationX(otherAdjacentTask.getTranslationX() - + (mIsRtl ? -translationX : translationX)) + + (isRtl ? -translationX : translationX)) .build()); launcherAnimator.play(otherAdjacentTaskParallaxToRight); } @@ -314,7 +400,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag launcherAnimator.play(allAppsSlideOut); Workspace workspace = mLauncher.getWorkspace(); - float[] workspaceScaleAndTranslation = LauncherState.NORMAL + float[] workspaceScaleAndTranslation = NORMAL .getWorkspaceScaleAndTranslation(mLauncher); Animator recenterWorkspace = LauncherAnimUtils.ofPropertyValuesHolder( workspace, new PropertyListBuilder() @@ -324,9 +410,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag launcherAnimator.play(recenterWorkspace); CellLayout currentWorkspacePage = (CellLayout) workspace.getPageAt( workspace.getCurrentPage()); - Animator hideWorkspaceScrim = ObjectAnimator.ofInt( - currentWorkspacePage.getScrimBackground(), DRAWABLE_ALPHA, 0); - launcherAnimator.play(hideWorkspaceScrim); launcherAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); launcherAnimator.setDuration(RECENTS_LAUNCH_DURATION); @@ -337,7 +420,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag * @return Animator that controls the window of the opening targets for the recents launch * animation. */ - private ValueAnimator getRecentsWindowAnimator(TaskView v, + private ValueAnimator getRecentsWindowAnimator(TaskView v, MutableBoolean skipLauncherChanges, RemoteAnimationTargetCompat[] targets) { Rect taskViewBounds = new Rect(); mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds); @@ -373,13 +456,15 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag final float percent = animation.getAnimatedFraction(); TaskWindowBounds tw = recentsInterpolator.interpolate(percent); - v.setScaleX(tw.taskScale); - v.setScaleY(tw.taskScale); - v.setTranslationX(tw.taskX); - v.setTranslationY(tw.taskY); - // Defer fading out the view until after the app window gets faded in - v.setAlpha(getValue(1f, 0f, 75, 75, - appAnimator.getDuration() * percent, Interpolators.LINEAR)); + if (!skipLauncherChanges.value) { + v.setScaleX(tw.taskScale); + v.setScaleY(tw.taskScale); + v.setTranslationX(tw.taskX); + v.setTranslationY(tw.taskY); + // Defer fading out the view until after the app window gets faded in + v.setAlpha(getValue(1f, 0f, 75, 75, + appAnimator.getDuration() * percent, Interpolators.LINEAR)); + } matrix.setScale(tw.winScale, tw.winScale); matrix.postTranslate(tw.winX, tw.winY); @@ -401,7 +486,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag matrix.postTranslate(target.position.x, target.position.y); t.setMatrix(target.leash, matrix); t.setWindowCrop(target.leash, crop); - t.deferTransactionUntil(target.leash, surface, getNextFrameNumber(surface)); + + if (!skipLauncherChanges.value) { + t.deferTransactionUntil(target.leash, surface, frameNumber); + } } if (isFirstFrame) { t.show(target.leash); @@ -413,13 +501,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag isFirstFrame = false; } }); - appAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - // Make sure recents gets fixed up by resetting task alphas and scales, etc. - mLauncher.getStateManager().reapplyState(); - } - }); return appAnimator; } @@ -497,26 +578,40 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag * @return Animator that controls the icon used to launch the target. */ private AnimatorSet getIconAnimator(View v) { - boolean isBubbleTextView = v instanceof BubbleTextView; + final boolean isBubbleTextView = v instanceof BubbleTextView; mFloatingView = new View(mLauncher); if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) { // Create a copy of the app icon - ItemInfoWithIcon info = (ItemInfoWithIcon) v.getTag(); - FastBitmapDrawable d = DrawableFactory.get(mLauncher).newIcon(info); - d.setIsDisabled(info.isDisabled()); - mFloatingView.setBackground(d); + mFloatingView.setBackground( + DrawableFactory.get(mLauncher).newIcon((ItemInfoWithIcon) v.getTag())); } // Position the floating view exactly on top of the original Rect rect = new Rect(); - mDragLayer.getDescendantRectRelativeToSelf(v, rect); - int viewLocationStart = mIsRtl + final 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(), rect); + } else { + mDragLayer.getDescendantRectRelativeToSelf(v, rect); + } + final int viewLocationStart = mIsRtl ? mDeviceProfile.widthPx - rect.right : rect.left; - int viewLocationTop = rect.top; + final int viewLocationTop = rect.top; - if (isBubbleTextView) { - ((BubbleTextView) v).getIconBounds(rect); + float startScale = 1f; + if (isBubbleTextView && !isDeepShortcutTextView) { + BubbleTextView btv = (BubbleTextView) v; + btv.getIconBounds(rect); + Drawable dr = btv.getIcon(); + if (dr instanceof FastBitmapDrawable) { + startScale = ((FastBitmapDrawable) dr).getAnimatedScale(); + } + } else { + rect.set(0, 0, rect.width(), rect.height()); } LayoutParams lp = new LayoutParams(rect.width(), rect.height()); lp.ignoreInsets = true; @@ -544,8 +639,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag // 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); @@ -556,14 +651,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag float maxScaleX = mDeviceProfile.widthPx / (float) rect.width(); float maxScaleY = mDeviceProfile.heightPx / (float) rect.height(); float scale = Math.max(maxScaleX, maxScaleY); - ObjectAnimator sX = ObjectAnimator.ofFloat(mFloatingView, View.SCALE_X, 1f, scale); - ObjectAnimator sY = ObjectAnimator.ofFloat(mFloatingView, View.SCALE_Y, 1f, scale); - sX.setDuration(500); - sY.setDuration(500); - sX.setInterpolator(Interpolators.EXAGGERATED_EASE); - sY.setInterpolator(Interpolators.EXAGGERATED_EASE); - appIconAnimatorSet.play(sX); - appIconAnimatorSet.play(sY); + ObjectAnimator scaleAnim = ObjectAnimator + .ofFloat(mFloatingView, SCALE_PROPERTY, startScale, scale); + scaleAnim.setDuration(APP_LAUNCH_DURATION).setInterpolator(Interpolators.EXAGGERATED_EASE); + appIconAnimatorSet.play(scaleAnim); // Fade out the app icon. ObjectAnimator alpha = ObjectAnimator.ofFloat(mFloatingView, View.ALPHA, 1f, 0f); @@ -580,7 +671,13 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag */ 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); @@ -591,7 +688,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag 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; @@ -713,7 +810,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag postAtFrontOfQueueAsynchronously(handler, () -> { if ((Utilities.getPrefs(mLauncher) .getBoolean("pref_use_screenshot_for_swipe_up", false) - && mLauncher.isInState(LauncherState.OVERVIEW)) + && 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. @@ -750,7 +847,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag Matrix matrix = new Matrix(); float height = mLauncher.getDeviceProfile().heightPx; float width = mLauncher.getDeviceProfile().widthPx; - float endX = (Utilities.isRtl(mLauncher.getResources()) ? -width : width) * 1.16f; + float endX = (mLauncher.getOverviewPanel().isRtl() ? -width : width) * 1.16f; ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1); closingAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS); diff --git a/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java b/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java index aec28697e8..ab9234b516 100644 --- a/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java +++ b/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java @@ -27,11 +27,20 @@ import android.animation.AnimatorSet; */ 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; } @@ -50,6 +59,7 @@ public class LauncherTransitionAnimator { public void cancel() { mAnimatorSet.cancel(); + mLauncherAnimCancelState.value = true; } public boolean isRunning() { @@ -58,6 +68,7 @@ public class LauncherTransitionAnimator { 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 new file mode 100644 index 0000000000..75382171af --- /dev/null +++ b/quickstep/src/com/android/launcher3/MutableBoolean.java @@ -0,0 +1,25 @@ +/* + * 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 426fe35efb..31261d9853 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.AbstractFloatingView; 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; /** @@ -32,7 +33,8 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; */ public class AllAppsState extends LauncherState { - private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY; + private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY + | FLAG_SHOW_SCRIM | FLAG_ALL_APPS_SCRIM; private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) { @Override @@ -57,7 +59,8 @@ public class AllAppsState extends LauncherState { @Override public String getDescription(Launcher launcher) { - return launcher.getString(R.string.all_apps_button_label); + AllAppsContainerView appsView = launcher.getAppsView(); + return appsView.getDescription(); } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java index 541c6bbc61..97ac3e6069 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java @@ -31,13 +31,12 @@ 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.anim.SpringAnimationHandler; 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; +import com.android.quickstep.views.RecentsView; class EventLogTags { private EventLogTags() { @@ -142,11 +141,6 @@ public class EdgeSwipeController extends VerticalSwipeController implements } } - @Override - protected void initSprings() { - mSpringHandlers = new SpringAnimationHandler[0]; - } - @Override protected float getShiftRange() { return getShiftRange(mLauncher); diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java new file mode 100644 index 0000000000..9541d0d052 --- /dev/null +++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java @@ -0,0 +1,50 @@ +/* + * 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 com.android.launcher3.Launcher; +import com.android.quickstep.QuickScrubController; +import com.android.quickstep.views.RecentsView; + +/** + * Extension of overview state used for QuickScrub + */ +public class FastOverviewState extends OverviewState { + + private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_DISABLE_RESTORE + | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI; + + private static final boolean DEBUG_DIFFERENT_UI = false; + + public FastOverviewState(int id) { + super(id, QuickScrubController.QUICK_SWITCH_START_DURATION, STATE_FLAGS); + } + + @Override + public void onStateTransitionEnd(Launcher launcher) { + super.onStateTransitionEnd(launcher); + RecentsView recentsView = launcher.getOverviewPanel(); + recentsView.getQuickScrubController().onFinishedTransitionToQuickScrub(); + } + + @Override + public float getHoseatAlpha(Launcher launcher) { + if (DEBUG_DIFFERENT_UI) { + return 0; + } + return super.getHoseatAlpha(launcher); + } +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java index 9ba2308c62..abb4ecf4c9 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java @@ -16,20 +16,17 @@ 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.content.Context; 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.Utilities; 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 @@ -37,27 +34,26 @@ import com.android.quickstep.RecentsView; public class OverviewState extends LauncherState { private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED - | FLAG_DISABLE_RESTORE; + | FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI; public OverviewState(int id) { - super(id, ContainerType.TASKSWITCHER, OVERVIEW_TRANSITION_MS, STATE_FLAGS); + this(id, OVERVIEW_TRANSITION_MS, STATE_FLAGS); + } + + 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 @@ -73,8 +69,8 @@ public class OverviewState extends LauncherState { } @Override - public float getVerticalProgress(Launcher launcher) { - return getVerticalProgress(launcher.getDeviceProfile(), launcher); + public void onStateTransitionEnd(Launcher launcher) { + launcher.getRotationHelper().setCurrentStateRequest(REQUEST_ROTATE); } @Override @@ -83,51 +79,25 @@ public class OverviewState extends LauncherState { } 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; - - if (Utilities.isRtl(launcher.getResources())) { - translationX -= offsetX / scale; - } else { - translationX += offsetX / scale; - } - - return new float[] {scale, translationX, translationY}; - } - - public static float getVerticalProgress(DeviceProfile grid, Context context) { - if (!grid.isVerticalBarLayout()) { - return 1f; - } - - float total = grid.heightPx; - float searchHeight = total - grid.availableHeightPx + - context.getResources().getDimension(R.dimen.all_apps_search_box_full_height); - return 1 - (searchHeight / total); + return new float[] {scale, 0, translationY}; } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java index 468a5617cb..c8b54adaf0 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java @@ -15,10 +15,14 @@ */ 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 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; @@ -32,19 +36,13 @@ 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.userevent.nano.LauncherLogProto.ContainerType; 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 @@ -65,6 +63,7 @@ public class OverviewSwipeController extends AnimatorListenerAdapter private final RecentsView mRecentsView; private final int[] mTempCords = new int[2]; + private PendingAnimation mPendingAnimation; private AnimatorPlaybackController mCurrentAnimation; private boolean mCurrentAnimationIsGoingUp; @@ -132,28 +131,21 @@ public class OverviewSwipeController extends AnimatorListenerAdapter 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; + mStartingTarget = LauncherLogProto.ItemType.TASK; + } else if (isEventOverHotseat(ev)) { + // The hotseat is being dragged + directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE; + mSwipeDownEnabled = false; + mStartingTarget = ContainerType.HOTSEAT; } 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; + mStartingTarget = ContainerType.WORKSPACE; + return false; } } @@ -185,6 +177,11 @@ public class OverviewSwipeController extends AnimatorListenerAdapter 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); @@ -201,19 +198,11 @@ public class OverviewSwipeController extends AnimatorListenerAdapter } } 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); - - 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(); + mPendingAnimation = mRecentsView + .createTaskDismissAnimation(mTaskBeingDragged, maxDuration); + mCurrentAnimation = AnimatorPlaybackController + .wrap(mPendingAnimation.anim, maxDuration); + mEndDisplacement = -mTaskBeingDragged.getHeight(); } else { AnimatorSet anim = new AnimatorSet(); // TODO: Setup a zoom animation @@ -299,15 +288,17 @@ public class OverviewSwipeController extends AnimatorListenerAdapter } private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) { + if (mPendingAnimation != null) { + mPendingAnimation.finish(wasSuccess); + mPendingAnimation = null; + } 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 (!mCurrentAnimationIsGoingUp) { mTaskBeingDragged.launchTask(false); mLauncher.getUserEventDispatcher().logTaskLaunch(logAction, Direction.DOWN, mTaskBeingDragged.getTask().getTopComponent()); diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index 7d371e96bf..b7f79b321c 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -16,7 +16,7 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.LauncherState.NORMAL; -import static com.android.launcher3.LauncherState.OVERVIEW; +import static com.android.launcher3.anim.Interpolators.ACCEL; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -28,84 +28,71 @@ import com.android.launcher3.LauncherState; 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; +import com.android.quickstep.views.TaskView; 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; + private boolean mIsRecentsSlidingInOrOut; 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 == OVERVIEW); - setVisibility(state == OVERVIEW); - setTransitionProgress(state == OVERVIEW ? 1 : 0); - if (state == OVERVIEW) { - for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) { - ((TaskView) mRecentsView.getPageAt(i)).resetVisualProperties(); - } - mRecentsView.updateCurveProperties(); + setVisibility(state.overviewUi); + setTransitionProgress(state.overviewUi ? 1 : 0); + if (state.overviewUi) { + mRecentsView.resetTaskVisuals(); } } @Override public void setStateWithAnimation(final LauncherState toState, AnimatorSetBuilder builder, AnimationConfig config) { - boolean settingEnabled = Utilities.getPrefs(mLauncher) - .getBoolean("pref_scroll_to_first_task", false); - mIsRecentsScrollingToFirstTask = mLauncher.isInState(NORMAL) && toState == OVERVIEW - && settingEnabled; - // TODO: Instead of animating the workspace translationX, move the contents - mWorkspaceCard.setWorkspaceScrollingEnabled(mIsRecentsScrollingToFirstTask); + LauncherState fromState = mLauncher.getStateManager().getState(); + mIsRecentsSlidingInOrOut = fromState == NORMAL && toState.overviewUi + || fromState.overviewUi && toState == NORMAL; // Scroll to the workspace card before changing to the NORMAL state. int currPage = mRecentsView.getCurrentPage(); - if (toState == NORMAL && currPage != 0 && !config.userControlled) { + 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 == OVERVIEW ? 1 : 0); + 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 == OVERVIEW); mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen()); } }); builder.play(progressAnim); - ObjectAnimator visibilityAnim = animateVisibility(toState == OVERVIEW); + ObjectAnimator visibilityAnim = animateVisibility(toState.overviewUi); visibilityAnim.setDuration(config.duration); visibilityAnim.setInterpolator(Interpolators.LINEAR); builder.play(visibilityAnim); @@ -144,11 +131,14 @@ public class RecentsViewStateController implements StateHandler { 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)); + if (mIsRecentsSlidingInOrOut) { + float interpolatedProgress = ACCEL.getInterpolation(mTransitionProgress.value); + // Slide in from the side as we swipe. + int translation = mRecentsView.getWidth(); + if (mRecentsView.isRtl()) { + translation = -translation; + } + mRecentsView.setTranslationX(translation * (1 - interpolatedProgress)); } } @@ -158,5 +148,9 @@ public class RecentsViewStateController implements StateHandler { private void applyProgress() { mRecentsView.setAlpha(mTransitionProgress.value * mVisibilityMultiplier.value); + if (mIsRecentsSlidingInOrOut) { + // While animating into recents, update the visible task data as needed + mRecentsView.loadVisibleTaskData(); + } } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java index 2695054c23..c8d75dc6f6 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java @@ -19,7 +19,6 @@ 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.launcher3.anim.SpringAnimationHandler.Y_DIRECTION; import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR; import android.animation.Animator; @@ -27,7 +26,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.support.animation.SpringAnimation; import android.util.Log; import android.view.MotionEvent; @@ -38,11 +36,9 @@ 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.allapps.AllAppsContainerView; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorSetBuilder; -import com.android.launcher3.anim.SpringAnimationHandler; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; @@ -52,8 +48,6 @@ import com.android.launcher3.util.FloatRange; import com.android.launcher3.util.TouchController; import com.android.quickstep.TouchInteractionService; -import java.util.ArrayList; - /** * Handles vertical touch gesture on the DragLayer */ @@ -112,8 +106,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter // Ratio of transition process [0, 1] to drag displacement (px) private float mProgressMultiplier; - private SpringAnimationHandler[] mSpringHandlers; - public TwoStepSwipeController(Launcher l) { mLauncher = l; mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL); @@ -156,29 +148,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter } } - private void initSprings() { - AllAppsContainerView appsView = mLauncher.getAppsView(); - - SpringAnimationHandler handler = appsView.getSpringAnimationHandler(); - if (handler == null) { - mSpringHandlers = new SpringAnimationHandler[0]; - return; - } - - ArrayList handlers = new ArrayList<>(); - handlers.add(handler); - - SpringAnimation searchSpring = appsView.getSearchUiManager().getSpringForFling(); - if (searchSpring != null) { - SpringAnimationHandler searchHandler = - new SpringAnimationHandler(Y_DIRECTION, handler.getFactory()); - searchHandler.add(searchSpring, true /* setDefaultValues */); - handlers.add(searchHandler); - } - - mSpringHandlers = handlers.toArray(new SpringAnimationHandler[handlers.size()]); - } - @Override public boolean onControllerInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { @@ -214,10 +183,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter mDetector.setDetectableScrollConditions( directionsToDetectScroll, ignoreSlopWhenSettling); - - if (mSpringHandlers == null) { - initSprings(); - } } if (mNoIntercept) { @@ -230,9 +195,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter @Override public boolean onControllerTouchEvent(MotionEvent ev) { - for (SpringAnimationHandler h : mSpringHandlers) { - h.addMovement(ev); - } return mDetector.onTouchEvent(ev); } @@ -283,10 +245,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter mDragPauseDetector.clearDisabledFlags(FLAG_OVERVIEW_DISABLED_FLING); updatePauseDetectorRangeFlag(); } - - for (SpringAnimationHandler h : mSpringHandlers) { - h.skipToEnd(); - } } private float getShiftRange() { @@ -329,13 +287,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter targetState = (progress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState; } - if (fling && targetState == ALL_APPS) { - for (SpringAnimationHandler h : mSpringHandlers) { - // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.) - h.animateToFinalPosition(0 /* pos */, 1 /* startValue */); - } - } - float endProgress; if (mDragPauseDetector.isTriggered() && targetState == NORMAL) { diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index 7bd43668ec..9051cfbfc2 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -18,37 +18,29 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.LauncherState.NORMAL; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.PointF; +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.graphics.BitmapRenderer; +import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.util.TouchController; import com.android.quickstep.OverviewInteractionState; -import com.android.quickstep.RecentsView; -import com.android.systemui.shared.recents.view.RecentsTransition; +import com.android.quickstep.RecentsModel; +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 final boolean USE_HARDWARE_BITMAP = false; // FeatureFlags.IS_DOGFOOD_BUILD; - public static TouchController[] createTouchControllers(Launcher launcher) { if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) { return new TouchController[] { - new IgnoreTouchesInQuickScrub(), new EdgeSwipeController(launcher), new TwoStepSwipeController(launcher), new OverviewSwipeController(launcher)}; } else { return new TouchController[] { - new IgnoreTouchesInQuickScrub(), new TwoStepSwipeController(launcher), new OverviewSwipeController(launcher)}; } @@ -64,28 +56,40 @@ public class UiFactory { new RecentsViewStateController(launcher)}; } - public static void onWorkspaceLongPress(Launcher launcher, PointF touchPoint) { - OptionsPopupView.show(launcher, touchPoint.x, touchPoint.y); - } - public static void onLauncherStateOrFocusChanged(Launcher launcher) { - OverviewInteractionState.setBackButtonVisible(launcher, launcher == null - || !launcher.isInState(NORMAL) || !launcher.hasWindowFocus()); - } - - public static Bitmap createFromRenderer(int width, int height, boolean forceSoftwareRenderer, - BitmapRenderer renderer) { - if (USE_HARDWARE_BITMAP && !forceSoftwareRenderer) { - return RecentsTransition.createHardwareBitmap(width, height, renderer::render); - } else { - Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - renderer.render(new Canvas(result)); - return result; + boolean shouldBackButtonBeVisible = launcher == null + || !launcher.isInState(NORMAL) + || !launcher.hasWindowFocus(); + if (!shouldBackButtonBeVisible) { + // Show the back button if there is a floating view visible. + DragLayer dragLayer = launcher.getDragLayer(); + for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) { + View child = dragLayer.getChildAt(i); + if (child instanceof AbstractFloatingView) { + shouldBackButtonBeVisible = true; + break; + } + } } + OverviewInteractionState.setBackButtonVisible(launcher, shouldBackButtonBeVisible); } public static void resetOverview(Launcher launcher) { RecentsView recents = launcher.getOverviewPanel(); recents.reset(); } + + public static void onStart(Launcher launcher) { + RecentsModel model = RecentsModel.getInstance(launcher); + if (model != null) { + model.onStart(); + } + } + + public static void onTrimMemory(Launcher launcher, int level) { + RecentsModel model = RecentsModel.getInstance(launcher); + 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 8533502b06..0000000000 --- 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/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java index 214b3f3b9f..84dfa457e9 100644 --- a/quickstep/src/com/android/quickstep/AnimatedFloat.java +++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java @@ -77,6 +77,12 @@ public class AnimatedFloat { } } + 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 index b3ebd772cc..5871a6d59f 100644 --- a/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java +++ b/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java @@ -23,6 +23,7 @@ import com.android.quickstep.TouchConsumer.InteractionType; public abstract class BaseSwipeInteractionHandler extends InternalStateHandler { protected Runnable mGestureEndCallback; + protected boolean mIsGoingToHome; public void setGestureEndCallback(Runnable gestureEndCallback) { mGestureEndCallback = gestureEndCallback; diff --git a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java new file mode 100644 index 0000000000..b92678a2ef --- /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/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/FallbackRecentsView.java new file mode 100644 index 0000000000..22f6e0cc25 --- /dev/null +++ b/quickstep/src/com/android/quickstep/FallbackRecentsView.java @@ -0,0 +1,57 @@ +/* + * 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 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); + } + + public 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; + } +} diff --git a/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java new file mode 100644 index 0000000000..12757c0f79 --- /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 getInstantApps() { + try { + List 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/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java index 6e92d83c52..94b6faa39e 100644 --- a/quickstep/src/com/android/quickstep/MotionEventQueue.java +++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java @@ -53,6 +53,8 @@ public class MotionEventQueue { 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 class MotionEventQueue { 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 @@ public class MotionEventQueue { 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 @@ public class MotionEventQueue { queueVirtualAction(ACTION_RESET, 0); } + public void deferInit() { + queueVirtualAction(ACTION_DEFER_INIT, 0); + } + + public TouchConsumer getConsumer() { + return mConsumer; + } + private static class EventArray extends ArrayList { public int lastEventAction = ACTION_CANCEL; diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java index ff7d434e7f..89c9d1611d 100644 --- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java +++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java @@ -17,7 +17,6 @@ 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; @@ -51,6 +50,8 @@ 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.quickstep.views.RecentsView; +import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -319,13 +320,14 @@ public class NavBarSwipeInteractionHandler extends BaseSwipeInteractionHandler i /** 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) { - mStateCallback.setState((Float.compare(mCurrentShift.value, 0) == 0) - ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS); + mStateCallback.setState(mIsGoingToHome + ? STATE_SCALED_SNAPSHOT_RECENTS : STATE_SCALED_SNAPSHOT_APP); } }); anim.start(); diff --git a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java index 431fb30a12..f875bb786e 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 @@ import com.android.systemui.shared.recents.model.TaskKeyLruCache; public class NormalizedIconLoader extends IconLoader { private final SparseArray mDefaultIcons = new SparseArray<>(); + private final DrawableFactory mDrawableFactory; private LauncherIcons mLauncherIcons; public NormalizedIconLoader(Context context, TaskKeyLruCache iconCache, LruCache activityInfoCache) { super(context, iconCache, activityInfoCache); + mDrawableFactory = DrawableFactory.get(context); } @Override @@ -53,7 +56,7 @@ public class NormalizedIconLoader extends IconLoader { 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 @@ public class NormalizedIconLoader extends IconLoader { } @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 488cd72b53..c96f6d73aa 100644 --- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java @@ -23,9 +23,11 @@ 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.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON; 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; @@ -37,10 +39,9 @@ import android.graphics.Color; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; -import android.metrics.LogMaker; +import android.os.Build; import android.os.Bundle; import android.os.Looper; -import android.os.SystemClock; import android.util.Log; import android.view.Choreographer; import android.view.Display; @@ -63,50 +64,20 @@ import com.android.systemui.shared.system.RecentsAnimationListener; 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; -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()); - } -} - /** * 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 = DEBUG_SHOW_OVERVIEW_BUTTON + ? new int[] {HIT_TARGET_BACK, HIT_TARGET_OVERVIEW} : new int[] {HIT_TARGET_BACK}; private final RunningTaskInfo mRunningTask; private final RecentsModel mRecentsModel; @@ -115,6 +86,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC 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; @@ -124,26 +96,24 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private BaseSwipeInteractionHandler mInteractionHandler; private int mDisplayRotation; private Rect mStableInsets = new Rect(); - private @HitTarget int mDownHitTarget = HIT_TARGET_NONE; private VelocityTracker mVelocityTracker; private MotionEventQueue mEventQueue; - - private final MetricsLogger mMetricsLogger = new MetricsLogger(); + private boolean mIsGoingToHome; public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo, RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy, MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer, - @HitTarget int downHitTarget) { + @HitTarget int downHitTarget, VelocityTracker velocityTracker) { super(base); mRunningTask = runningTaskInfo; mRecentsModel = recentsModel; mHomeIntent = homeIntent; - mVelocityTracker = VelocityTracker.obtain(); + mVelocityTracker = velocityTracker; mISystemUiProxy = systemUiProxy; mMainThreadExecutor = mainThreadExecutor; mBackgroundThreadChoreographer = backgroundThreadChoreographer; - mDownHitTarget = downHitTarget; + mIsDeferredDownTarget = Arrays.binarySearch(DEFERRED_HIT_TARGETS, downHitTarget) >= 0; } @Override @@ -162,7 +132,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC // 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 (!isUsingScreenShot() && !mIsDeferredDownTarget) { startTouchTrackingForWindowAnimation(ev.getEventTime()); } @@ -204,7 +174,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC if (isUsingScreenShot()) { startTouchTrackingForScreenshotAnimation(); - } else if (mDownHitTarget == HIT_TARGET_BACK) { + } else if (mIsDeferredDownTarget) { // If we deferred starting the window animation on touch down, then // start tracking now startTouchTrackingForWindowAnimation(ev.getEventTime()); @@ -312,7 +282,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private void startTouchTrackingForWindowAnimation(long touchTimeMs) { // Create the shared handler final WindowTransformSwipeHandler handler = - new WindowTransformSwipeHandler(mRunningTask, this); + new WindowTransformSwipeHandler(mRunningTask, this, touchTimeMs); // Preload the plan mRecentsModel.loadTasks(mRunningTask.id, null); @@ -350,16 +320,6 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC TraceHelper.endSection("RecentsController", "Finishing no handler"); controller.finish(false /* toHome */); } - - // 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*/, - SystemClock.uptimeMillis() - touchTimeMs); - mMetricsLogger.write(builder); } public void onAnimationCanceled() { @@ -417,6 +377,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC if (mInteractionHandler != null) { final BaseSwipeInteractionHandler handler = mInteractionHandler; mInteractionHandler = null; + mIsGoingToHome = handler.mIsGoingToHome; mMainThreadExecutor.execute(handler::reset); } } @@ -471,4 +432,15 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC } } } + + @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 0000000000..031624aaca --- /dev/null +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -0,0 +1,120 @@ +/* + * 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 static com.android.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON; + +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.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 = DEBUG_SHOW_OVERVIEW_BUTTON; + + 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); + 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); + } + + public void onOverviewToggle() { + if (DEBUG_START_FALLBACK_ACTIVITY) { + 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 { + Intent intent = addToIntent(new Intent(homeIntent)); + mContext.startActivity(intent); + initWhenReady(); + } + } + + private void startNonLauncherTask(int backStackCount) { + for (RecentTaskInfo rti : mAM.getRecentTasks(backStackCount, UserHandle.myUserId())) { + backStackCount--; + if (backStackCount == 0) { + mAM.startActivityFromRecents(rti.id, null); + } + } + } + + 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; + } + +} diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java index 3c68281a82..4af89bf46b 100644 --- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java +++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java @@ -15,7 +15,9 @@ */ package com.android.quickstep; +import static com.android.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON; 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.os.Handler; @@ -60,7 +62,7 @@ public class OverviewInteractionState { } }; - private static int sFlags; + private static int sFlags = DEBUG_SHOW_OVERVIEW_BUTTON ? FLAG_SHOW_OVERVIEW_BUTTON : 0; public static void setBackButtonVisible(Context context, boolean visible) { updateFlagOnUi(context, FLAG_HIDE_BACK_BUTTON, !visible); diff --git a/quickstep/src/com/android/quickstep/PendingAnimation.java b/quickstep/src/com/android/quickstep/PendingAnimation.java new file mode 100644 index 0000000000..d22ef61053 --- /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> mEndListeners = new ArrayList<>(); + + public final AnimatorSet anim; + + public PendingAnimation(AnimatorSet anim) { + this.anim = anim; + } + + public void finish(boolean isSuccess) { + for (Consumer listeners : mEndListeners) { + listeners.accept(isSuccess); + } + mEndListeners.clear(); + } + + public void addEndListener(Consumer listener) { + mEndListeners.add(listener); + } +} diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java index f28d51c8ea..a154b291e2 100644 --- a/quickstep/src/com/android/quickstep/QuickScrubController.java +++ b/quickstep/src/com/android/quickstep/QuickScrubController.java @@ -19,13 +19,14 @@ package com.android.quickstep; 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 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; */ 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 @@ public class QuickScrubController implements OnAlarmListener { 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 class QuickScrubController implements OnAlarmListener { 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,11 +84,7 @@ public class QuickScrubController implements OnAlarmListener { } int page = mRecentsView.getNextPage(); Runnable launchTaskRunnable = () -> { - if (page < mRecentsView.getFirstTaskIndex()) { - mRecentsView.getPageAt(page).performClick(); - } else { - ((TaskView) mRecentsView.getPageAt(page)).launchTask(true); - } + ((TaskView) mRecentsView.getPageAt(page)).launchTask(true); }; int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen()) * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE; @@ -93,8 +95,8 @@ public class QuickScrubController implements OnAlarmListener { // 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 +104,9 @@ public class QuickScrubController implements OnAlarmListener { 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 +120,45 @@ public class QuickScrubController implements OnAlarmListener { } 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 +171,7 @@ public class QuickScrubController implements OnAlarmListener { 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 f92d773bd6..598c34de0e 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -15,34 +15,29 @@ */ package com.android.quickstep; -import android.app.ListActivity; import android.os.Bundle; -import android.os.UserHandle; -import android.support.annotation.Nullable; -import android.widget.ArrayAdapter; -import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; -import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions; -import com.android.systemui.shared.recents.model.RecentsTaskLoader; -import com.android.systemui.shared.recents.model.Task; +import com.android.launcher3.BaseActivity; +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.R; /** * A simple activity to show the recently launched tasks */ -public class RecentsActivity extends ListActivity { - - private ArrayAdapter mAdapter; +public class RecentsActivity extends BaseActivity { @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); } } diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index 7fe77510df..392b73fc63 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -16,6 +16,8 @@ package com.android.quickstep; import android.annotation.TargetApi; +import android.app.ActivityManager; +import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; @@ -51,7 +53,6 @@ import java.util.function.Consumer; */ @TargetApi(Build.VERSION_CODES.O) public class RecentsModel extends TaskStackChangeListener { - // We do not need any synchronization for this variable as its only written on UI thread. private static RecentsModel INSTANCE; @@ -83,10 +84,16 @@ public class RecentsModel extends TaskStackChangeListener { private int mTaskChangeId; private ISystemUiProxy mSystemUiProxy; private boolean mClearAssistCacheOnStackChange = true; + private final boolean mPreloadTasksInBackground; private RecentsModel(Context context) { mContext = context; + ActivityManager activityManager = + (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + mPreloadTasksInBackground = !activityManager.isLowRamDevice(); + mMainThreadExecutor = new MainThreadExecutor(); + Resources res = context.getResources(); mRecentsTaskLoader = new RecentsTaskLoader(mContext, res.getInteger(R.integer.config_recentsMaxThumbnailCacheSize), @@ -100,8 +107,6 @@ public class RecentsModel extends TaskStackChangeListener { } }; mRecentsTaskLoader.startLoader(mContext); - - mMainThreadExecutor = new MainThreadExecutor(); ActivityManagerWrapper.getInstance().registerTaskStackListener(this); mTaskChangeId = 1; @@ -162,6 +167,31 @@ public class RecentsModel extends TaskStackChangeListener { } } + @Override + public void onTaskStackChangedBackground() { + int userId = UserHandle.myUserId(); + if (!mPreloadTasksInBackground || !checkCurrentUserId(userId, false /* debug */)) { + // TODO: Only register this for the current user + return; + } + + // Preload a fixed number of task icons/thumbnails in the background + ActivityManager.RunningTaskInfo runningTaskInfo = + ActivityManagerWrapper.getInstance().getRunningTask(); + RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext); + RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); + launchOpts.runningTaskId = runningTaskInfo != null ? runningTaskInfo.id : -1; + launchOpts.numVisibleTasks = 2; + launchOpts.numVisibleTaskThumbnails = 2; + launchOpts.onlyLoadForCache = true; + launchOpts.onlyLoadPausedActivities = true; + launchOpts.loadThumbnails = true; + PreloadOptions preloadOpts = new PreloadOptions(); + preloadOpts.loadTitles = false; + plan.preloadPlan(preloadOpts, mRecentsTaskLoader, -1, userId); + mRecentsTaskLoader.loadTasks(plan, launchOpts); + } + public boolean isLoadPlanValid(int resultId) { return mTaskChangeId == resultId; } @@ -178,6 +208,19 @@ public class RecentsModel extends TaskStackChangeListener { return mSystemUiProxy; } + public void onStart() { + mRecentsTaskLoader.startLoader(mContext); + 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.onTrimMemory(level); + } + @WorkerThread public void preloadAssistData(int taskId, Bundle data) { mMainThreadExecutor.execute(() -> { diff --git a/quickstep/src/com/android/quickstep/RecentsRootView.java b/quickstep/src/com/android/quickstep/RecentsRootView.java new file mode 100644 index 0000000000..3c69dbfd64 --- /dev/null +++ b/quickstep/src/com/android/quickstep/RecentsRootView.java @@ -0,0 +1,56 @@ +/* + * 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.InsettableFrameLayout; +import com.android.launcher3.R; +import com.android.launcher3.util.Themes; + +public class RecentsRootView extends InsettableFrameLayout { + + private final BaseActivity mActivity; + + public RecentsRootView(Context context, AttributeSet attrs) { + super(context, attrs); + mActivity = BaseActivity.fromContext(context); + } + + @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/SimpleTaskView.java b/quickstep/src/com/android/quickstep/SimpleTaskView.java deleted file mode 100644 index 8425fa3ba4..0000000000 --- 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/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java index 75d8619eae..eebfb91654 100644 --- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java +++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java @@ -16,27 +16,39 @@ package com.android.quickstep; -import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Rect; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import android.view.View; +import android.view.ViewTreeObserver.OnPreDrawListener; +import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.util.InstantAppResolver; +import com.android.quickstep.views.RecentsView; +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; +import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; +import com.android.systemui.shared.recents.view.RecentsTransition; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.ActivityOptionsCompat; +import com.android.systemui.shared.system.WindowManagerWrapper; +import java.util.Collections; +import java.util.List; import java.util.function.Consumer; /** @@ -86,9 +98,10 @@ public class TaskSystemShortcut extends SystemShortcut } } - public static class SplitScreen extends TaskSystemShortcut { + public static class SplitScreen extends TaskSystemShortcut implements OnPreDrawListener { private Handler mHandler; + private TaskView mTaskView; public SplitScreen() { super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen); @@ -104,22 +117,55 @@ public class TaskSystemShortcut extends SystemShortcut if (!task.isDockable) { return null; } + mTaskView = taskView; return (v -> { - final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions(true); - final Consumer resultCallback = success -> { - if (success) { - launcher.getOverviewPanel().removeView(taskView); - } - }; - ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync( - task.key, options, resultCallback, mHandler); + AbstractFloatingView.closeOpenViews(launcher, true, + AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); - // TODO improve transition; see: - // DockedFirstAnimationFrameEvent - // RecentsTransitionHelper#composeDockAnimationSpec - // WindowManagerWrapper#overridePendingAppTransitionMultiThumbFuture + if (ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key.id, + ActivityOptionsCompat.makeSplitScreenOptions(true))) { + ISystemUiProxy sysUiProxy = RecentsModel.getInstance(launcher).getSystemUiProxy(); + try { + sysUiProxy.onSplitScreenInvoked(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to notify SysUI of split screen: ", e); + return; + } + + final Runnable animStartedListener = () -> { + mTaskView.getViewTreeObserver().addOnPreDrawListener(SplitScreen.this); + launcher.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()); + 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); + AppTransitionAnimationSpecsFuture future = + new AppTransitionAnimationSpecsFuture(mHandler) { + @Override + public List composeSpecs() { + return Collections.singletonList(new AppTransitionAnimationSpecCompat( + task.key.id, thumbnail, taskBounds)); + } + }; + WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture( + future, animStartedListener, mHandler, true /* scaleUp */); + } }); } + + @Override + public boolean onPreDraw() { + mTaskView.getViewTreeObserver().removeOnPreDrawListener(this); + WindowManagerWrapper.getInstance().endProlongedAnimations(); + return true; + } } public static class Pin extends TaskSystemShortcut { @@ -137,7 +183,11 @@ public class TaskSystemShortcut extends SystemShortcut if (sysUiProxy == null) { return null; } - if (!ActivityManagerWrapper.getInstance().isLockToAppEnabled()) { + if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) { + return null; + } + if (ActivityManagerWrapper.getInstance().isLockToAppActive()) { + // We shouldn't be able to pin while an app is locked. return null; } return view -> { diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java index f35f6a6f45..768fbda738 100644 --- a/quickstep/src/com/android/quickstep/TouchConsumer.java +++ b/quickstep/src/com/android/quickstep/TouchConsumer.java @@ -21,8 +21,6 @@ import android.support.annotation.IntDef; 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 @@ public interface TouchConsumer extends Consumer { 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 c16629279e..a522ef184e 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -21,15 +21,13 @@ import static android.view.MotionEvent.ACTION_MOVE; 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.OVERVIEW; -import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION; +import static com.android.launcher3.LauncherState.FAST_OVERVIEW; +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; @@ -40,15 +38,18 @@ import android.util.Log; 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; @@ -60,6 +61,8 @@ import com.android.systemui.shared.system.NavigationBarCompat.HitTarget; @TargetApi(Build.VERSION_CODES.O) public class TouchInteractionService extends Service { + public static final boolean DEBUG_SHOW_OVERVIEW_BUTTON = false; + private static final SparseArray sMotionEventNames; static { @@ -117,7 +120,6 @@ public class TouchInteractionService extends Service { @Override public void onQuickScrubStart() { mEventQueue.onQuickScrubStart(); - sQuickScrubEnabled = true; TraceHelper.partitionSection("SysUiBinder", "onQuickScrubStart"); } @@ -130,35 +132,37 @@ public class TouchInteractionService extends Service { public void onQuickScrubEnd() { mEventQueue.onQuickScrubEnd(); TraceHelper.endSection("SysUiBinder", "onQuickScrubEnd"); - sQuickScrubEnabled = false; } + + @Override + public void onOverviewToggle() { + mOverviewCommandHelper.onOverviewToggle(); + } + + @Override + public void onOverviewShown(boolean triggeredFromAltTab) { } + + @Override + public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { } }; private final TouchConsumer mNoOpTouchConsumer = (ev) -> {}; private static boolean sConnected = false; - private static boolean sQuickScrubEnabled = false; public static boolean isConnected() { return sConnected; } - public static boolean isQuickScrubEnabled() { - return sQuickScrubEnabled; - } - 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 Choreographer mMainThreadChoreographer; private Choreographer mBackgroundThreadChoreographer; - private MotionEventQueue mNoOpEventQueue; @Override public void onCreate() { @@ -166,19 +170,9 @@ public class TouchInteractionService extends Service { 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); sConnected = true; @@ -190,7 +184,6 @@ public class TouchInteractionService extends Service { @Override public void onDestroy() { sConnected = false; - sQuickScrubEnabled = false; super.onDestroy(); } @@ -201,31 +194,45 @@ public class TouchInteractionService extends Service { } 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, mISystemUiProxy, 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 { @@ -310,13 +317,12 @@ public class TouchInteractionService extends Service { 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(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 19942c3950..af09842790 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -15,9 +15,12 @@ */ 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; @@ -32,16 +35,17 @@ import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; -import android.content.pm.ActivityInfo; import android.content.res.Resources; import android.graphics.Matrix; import android.graphics.Matrix.ScaleToFit; 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; +import android.os.SystemClock; import android.support.annotation.UiThread; import android.support.annotation.WorkerThread; import android.util.Log; @@ -67,9 +71,12 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.ViewOnDrawExecutor; import com.android.quickstep.TouchConsumer.InteractionType; +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; @@ -77,6 +84,40 @@ import com.android.systemui.shared.system.WindowManagerWrapper; 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 { private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName(); @@ -189,11 +230,17 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper(); private Matrix mTmpMatrix = new Matrix(); + private final long mTouchTimeMs; + private long mLauncherFrameDrawnTime; + private final MetricsLogger mMetricsLogger = new MetricsLogger(); - WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context) { + WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs) { mContext = context; mRunningTaskId = runningTaskInfo.id; - mInputConsumer.registerInputConsumer(); + mTouchTimeMs = touchTimeMs; + // Register the input consumer on the UI thread, to ensure that it runs after any pending + // unregister calls + mMainExecutor.execute(mInputConsumer::registerInputConsumer); initStateCallbacks(); } @@ -323,7 +370,8 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { // For the duration of the gesture, lock the screen orientation to ensure that we do not // rotate mid-quickscrub - mLauncher.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); + mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK); + mRecentsView = mLauncher.getOverviewPanel(); mQuickScrubController = mRecentsView.getQuickScrubController(); mLauncherLayoutListener = new LauncherLayoutListener(mLauncher); @@ -416,11 +464,26 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { if (mLauncherDrawnCallback != null) { mLauncherDrawnCallback.run(); } + mLauncherFrameDrawnTime = SystemClock.uptimeMillis(); } private void initializeLauncherAnimationController() { mLauncherLayoutListener.setHandler(this); onLauncherLayoutChanged(); + + final long transitionDelay = mLauncherFrameDrawnTime - mTouchTimeMs; + // 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); + mMetricsLogger.write(builder); + if (LatencyTrackerCompat.isEnabled(mContext)) { + LatencyTrackerCompat.logToggleRecents((int) transitionDelay); + } } public void updateInteractionType(@InteractionType int interactionType) { @@ -442,6 +505,8 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { } private void onQuickInteractionStart() { + mLauncher.getStateManager().goToState(FAST_OVERVIEW, + mWasLauncherAlreadyVisible || mGestureStarted); mQuickScrubController.onQuickScrubStart(false); } @@ -509,8 +574,13 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) { if (app.mode == MODE_CLOSING) { transaction.setMatrix(app.leash, mTmpMatrix) - .setWindowCrop(app.leash, mClipRect) - .show(app.leash); + .setWindowCrop(app.leash, mClipRect); + + if (app.isNotInRecents) { + transaction.setAlpha(app.leash, 1 - shift); + } + + transaction.show(app.leash); } } transaction.apply(); @@ -525,9 +595,8 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { 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) { @@ -658,13 +727,14 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { /** 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(); @@ -685,7 +755,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { } private void invalidateHandler() { - mCurrentShift.cancelAnimation(); + mCurrentShift.finishAnimation(); if (mGestureEndCallback != null) { mGestureEndCallback.run(); @@ -701,7 +771,8 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { mLauncherLayoutListener.close(false); // Restore the requested orientation to the user preference after the gesture has ended - mLauncher.updateRequestedOrientation(); + mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_NONE); + mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, false /* animate */); } 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 0000000000..7989e845ca --- /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 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/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java similarity index 51% rename from quickstep/src/com/android/quickstep/RecentsView.java rename to quickstep/src/com/android/quickstep/views/RecentsView.java index ec0716c49c..23e6e5bb20 100644 --- a/quickstep/src/com/android/quickstep/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -14,40 +14,36 @@ * limitations under the License. */ -package com.android.quickstep; +package com.android.quickstep.views; -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 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.LayoutTransition; +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.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.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 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.os.Build; import android.util.AttributeSet; +import android.util.SparseBooleanArray; import android.view.LayoutInflater; import android.view.View; -import android.widget.FrameLayout; +import com.android.launcher3.BaseActivity; 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.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; @@ -62,29 +58,30 @@ import java.util.ArrayList; /** * A list of recent tasks. */ -public class RecentsView extends PagedView implements Insettable { +@TargetApi(Build.VERSION_CODES.P) +public abstract class RecentsView + extends PagedView implements OnSharedPreferenceChangeListener { + + private static final String PREF_FLIP_RECENTS = "pref_flip_recents"; 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; + protected final T mActivity; + private final QuickScrubController mQuickScrubController; + private final float mFastFlingVelocity; + private final RecentsModel mModel; - 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; + // 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 TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { + private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { @Override public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { - for (int i = mFirstTaskIndex; i < getChildCount(); i++) { + 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); @@ -94,47 +91,51 @@ public class RecentsView extends PagedView implements Insettable { } }; - 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; - public RecentsView(Context context) { - this(context, null); - } + private boolean mOverviewStateEnabled; + private boolean mTaskStackListenerRegistered; + private Runnable mNextPageSwitchRunnable; - public RecentsView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } + private PendingAnimation mPendingAnimation; 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); + mFastFlingVelocity = getResources() + .getDimensionPixelSize(R.dimen.recents_fast_fling_velocity); + mActivity = (T) BaseActivity.fromContext(context); + mQuickScrubController = new QuickScrubController(mActivity, this); mModel = RecentsModel.getInstance(context); - mScrollState.isRtl = mIsRtl; + 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 = mFirstTaskIndex; i < getChildCount(); i++) { + for (int i = 0; i < getChildCount(); i++) { final TaskView taskView = (TaskView) getChildAt(i); if (taskView.getTask().key.id == taskId) { taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData); @@ -145,23 +146,6 @@ public class RecentsView extends PagedView implements Insettable { return null; } - private void setupLayoutTransition() { - // We want to show layout transitions when pages are deleted, to close the gap. - mLayoutTransition = new LayoutTransition(); - mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING); - mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); - - mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING); - mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING); - setLayoutTransition(mLayoutTransition); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mFirstTaskIndex = getPageCount(); - } - @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); @@ -172,62 +156,37 @@ public class RecentsView extends PagedView implements Insettable { 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); + public void onViewRemoved(View child) { + super.onViewRemoved(child); - 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; + // 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 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++) { + for (int i = 0; i < getChildCount(); i++) { TaskView tv = (TaskView) getChildAt(i); if (tv.getTask().key.id == taskId) { return tv; @@ -236,14 +195,6 @@ public class RecentsView extends PagedView implements Insettable { return null; } - public void setStateController(RecentsViewStateController stateController) { - mStateController = stateController; - } - - public RecentsViewStateController getStateController() { - return mStateController; - } - public void setOverviewStateEnabled(boolean enabled) { mOverviewStateEnabled = enabled; updateTaskStackListenerState(); @@ -263,7 +214,10 @@ public class RecentsView extends PagedView implements Insettable { } private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) { - final RecentsTaskLoader loader = mModel.getRecentsTaskLoader(); + if (mPendingAnimation != null) { + mPendingAnimation.addEndListener((b) -> applyLoadPlan(loadPlan)); + return; + } TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null; if (stack == null) { removeAllViews(); @@ -276,9 +230,8 @@ public class RecentsView extends PagedView implements Insettable { // necessary) final LayoutInflater inflater = LayoutInflater.from(getContext()); final ArrayList tasks = new ArrayList<>(stack.getTasks()); - setLayoutTransition(null); - final int requiredChildCount = tasks.size() + mFirstTaskIndex; + 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); @@ -286,26 +239,36 @@ public class RecentsView extends PagedView implements Insettable { while (getChildCount() > requiredChildCount) { final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1); removeView(taskView); - loader.unloadTaskData(taskView.getTask()); } - setLayoutTransition(mLayoutTransition); + + // Unload existing visible task data + unloadVisibleTaskData(); // Rebind and reset all task views - for (int i = tasks.size() - 1; i >= 0; i--) { + 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(tasks.size() - i - 1 + mFirstTaskIndex); + final TaskView taskView = (TaskView) getChildAt(pageIndex); taskView.bind(task); - taskView.resetVisualProperties(); - loader.loadTaskData(task); } - updateCurveProperties(); + resetTaskVisuals(); applyIconScale(false /* animate */); if (oldChildCount != getChildCount()) { - mQuickScrubController.snapToPageForCurrentQuickScrubSection(); + mQuickScrubController.snapToNextTaskIfAvailable(); } } + public void resetTaskVisuals() { + for (int i = getChildCount() - 1; i >= 0; i--) { + ((TaskView) getChildAt(i)).resetVisualProperties(); + } + + updateCurveProperties(); + // Update the set of visible task's data + loadVisibleTaskData(); + } + private void updateTaskStackListenerState() { boolean registerStackListener = mOverviewStateEnabled && isAttachedToWindow() && getWindowVisibility() == VISIBLE; @@ -322,7 +285,7 @@ public class RecentsView extends PagedView implements Insettable { } } - private static Rect getPadding(DeviceProfile profile, Context context) { + protected static Rect getPadding(DeviceProfile profile, Context context) { WindowManagerWrapper.getInstance().getStableInsets(sTempStableInsets); Rect padding = new Rect(profile.workspacePadding); @@ -331,11 +294,14 @@ public class RecentsView extends PagedView implements Insettable { 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(padding.left, padding.right); - float availableHeight = profile.availableHeightPx - padding.top - - sTempStableInsets.top - Math.max(padding.bottom, - profile.heightPx * (1 - OverviewState.getVerticalProgress(profile, context))); + 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; @@ -352,33 +318,6 @@ public class RecentsView extends PagedView implements Insettable { 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(); @@ -392,9 +331,24 @@ public class RecentsView extends PagedView implements Insettable { } @Override - public void computeScroll() { - super.computeScroll(); + 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; } /** @@ -404,8 +358,7 @@ public class RecentsView extends PagedView implements Insettable { if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) { return; } - final int halfPageWidth = mScrollState.halfPageWidth = getNormalChildWidth() / 2; - mScrollState.lastScrollType = SCROLL_TYPE_NONE; + final int halfPageWidth = getNormalChildWidth() / 2; final int screenCenter = mInsets.left + getPaddingLeft() + getScrollX() + halfPageWidth; final int halfScreenWidth = getMeasuredWidth() / 2; final int pageSpacing = mPageSpacing; @@ -413,36 +366,72 @@ public class RecentsView extends PagedView implements Insettable { 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 pageCenter = page.getLeft() + page.getTranslationX() + halfPageWidth; + float distanceFromScreenCenter = screenCenter - pageCenter; float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing; mScrollState.linearInterpolation = Math.min(1, - Math.abs(mScrollState.distanceFromScreenCenter) / distanceToReachEdge); - mScrollState.lastScrollType = ((PageCallbacks) page).onPageScroll(mScrollState); + Math.abs(distanceFromScreenCenter) / distanceToReachEdge); + ((PageCallbacks) page).onPageScroll(mScrollState); } } - public void onTaskDismissed(TaskView taskView) { - ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id); - removeView(taskView); - if (getTaskCount() == 0) { - mLauncher.getStateManager().goToState(NORMAL); + /** + * 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); } - public int getTaskCount() { - return getChildCount() - mFirstTaskIndex; - } - - public int getRunningTaskId() { - return mRunningTaskId; - } - /** * Reloads the view if anything in recents changed. */ @@ -462,26 +451,24 @@ public class RecentsView extends PagedView implements Insettable { */ public void showTask(int runningTaskId) { boolean needsReload = false; - if (getTaskCount() == 0) { + if (getChildCount() == 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); + addView(taskView, 0); } + mRunningTaskId = runningTaskId; + setCurrentPage(0); if (!needsReload) { needsReload = !mModel.isLoadPlanValid(mLoadPlanId); } if (needsReload) { mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan); + } else { + loadVisibleTaskData(); } - mRunningTaskId = runningTaskId; - setCurrentPage(mFirstTaskIndex); - if (mCurrentPage >= mFirstTaskIndex) { - getPageAt(mCurrentPage).setAlpha(0); - } + getPageAt(mCurrentPage).setAlpha(0); } public QuickScrubController getQuickScrubController() { @@ -498,7 +485,7 @@ public class RecentsView extends PagedView implements Insettable { private void applyIconScale(boolean animate) { float scale = mFirstTaskIconScaledDown ? 0 : 1; - TaskView firstTask = (TaskView) getChildAt(mFirstTaskIndex); + TaskView firstTask = (TaskView) getChildAt(0); if (firstTask != null) { if (animate) { firstTask.animateIconToScale(scale); @@ -508,57 +495,94 @@ public class RecentsView extends PagedView implements Insettable { } } - @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 + * Updates the page UI based on scroll params. */ - int onPageScroll(ScrollState scrollState); + default void onPageScroll(ScrollState scrollState) {}; } public static class ScrollState { - public boolean isRtl; - public int lastScrollType; - - public int halfPageWidth; - public float distanceFromScreenCenter; + /** + * 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 float prevPageExtraWidth; + public PendingAnimation createTaskDismissAnimation(TaskView taskView, 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) { + 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 + taskView.setTranslationZ(0.1f); + + mPendingAnimation = pendingAnimation; + mPendingAnimation.addEndListener((isSuccess) -> { + if (isSuccess) { + 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); } } diff --git a/quickstep/src/com/android/quickstep/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java similarity index 98% rename from quickstep/src/com/android/quickstep/TaskMenuView.java rename to quickstep/src/com/android/quickstep/views/TaskMenuView.java index 6bbcb37395..94f440dcd8 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; @@ -40,6 +40,8 @@ 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.quickstep.TaskSystemShortcut; +import com.android.quickstep.TaskUtils; /** * Contains options for a recent task when long-pressing its icon. 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 9b9c6f218d..87bb53bb61 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.graphics.Shader; 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 @@ public class TaskThumbnailView extends View { 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 @@ public class TaskThumbnailView extends View { } 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 76% rename from quickstep/src/com/android/quickstep/TaskView.java rename to quickstep/src/com/android/quickstep/views/TaskView.java index b407f75ffa..7a575ad253 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; @@ -33,8 +30,8 @@ import android.widget.ImageView; 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 +44,15 @@ import java.util.function.Consumer; */ 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; @@ -159,38 +154,16 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback 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/drawable-v24/ic_info_shadow.xml b/res/drawable-v24/ic_setup_shadow.xml similarity index 94% rename from res/drawable-v24/ic_info_shadow.xml rename to res/drawable-v24/ic_setup_shadow.xml index 1fe2c46b4b..10aeee6e02 100644 --- a/res/drawable-v24/ic_info_shadow.xml +++ b/res/drawable-v24/ic_setup_shadow.xml @@ -15,5 +15,5 @@ --> diff --git a/res/drawable/all_apps_search_divider.xml b/res/drawable/bg_all_apps_searchbox.xml similarity index 78% rename from res/drawable/all_apps_search_divider.xml rename to res/drawable/bg_all_apps_searchbox.xml index 99905e4233..c3249279af 100644 --- a/res/drawable/all_apps_search_divider.xml +++ b/res/drawable/bg_all_apps_searchbox.xml @@ -1,5 +1,5 @@ - - - - + + + \ No newline at end of file diff --git a/res/drawable/ic_setting.xml b/res/drawable/ic_setting.xml index 08eba253dc..33cd6ce34a 100644 --- a/res/drawable/ic_setting.xml +++ b/res/drawable/ic_setting.xml @@ -17,9 +17,10 @@ Copyright (C) 2016 The Android Open Source Project android:width="@dimen/options_menu_icon_size" android:height="@dimen/options_menu_icon_size" android:viewportWidth="48.0" - android:viewportHeight="48.0"> + android:viewportHeight="48.0" + android:tint="?android:attr/textColorPrimary" > - - + layout="@layout/search_container_all_apps"/> - + \ No newline at end of file diff --git a/res/layout/all_apps_rv_layout.xml b/res/layout/all_apps_rv_layout.xml index 3c19f8c5b2..c353b361cf 100644 --- a/res/layout/all_apps_rv_layout.xml +++ b/res/layout/all_apps_rv_layout.xml @@ -22,5 +22,4 @@ android:layout_below="@id/search_container_all_apps" android:clipToPadding="false" android:descendantFocusability="afterDescendants" - android:focusable="true" - android:overScrollMode="never" /> + android:focusable="true" /> diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml index 4a3db1f136..4a2ad42254 100644 --- a/res/layout/deep_shortcut.xml +++ b/res/layout/deep_shortcut.xml @@ -35,7 +35,6 @@ android:textColor="?android:attr/textColorPrimary" android:fontFamily="sans-serif" launcher:layoutHorizontal="true" - launcher:deferShadowGeneration="true" launcher:iconDisplay="shortcut_popup" launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size" /> diff --git a/res/layout/drop_target_bar.xml b/res/layout/drop_target_bar.xml index d376bcf09f..2f21c605a5 100644 --- a/res/layout/drop_target_bar.xml +++ b/res/layout/drop_target_bar.xml @@ -32,18 +32,8 @@ android:gravity="center" android:text="@string/remove_drop_target_label" /> - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml index c795b81fee..bdd5d23476 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. --> - - - - - - - - - \ 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/search_container_all_apps.xml b/res/layout/search_container_all_apps.xml index fc07002cb5..14d7b53b65 100644 --- a/res/layout/search_container_all_apps.xml +++ b/res/layout/search_container_all_apps.xml @@ -17,53 +17,23 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@id/search_container_all_apps" android:layout_width="match_parent" - android:layout_height="@dimen/all_apps_search_bar_height" - android:layout_gravity="center|top" - android:layout_marginBottom="-8dp" - android:gravity="center|bottom" - android:paddingLeft="@dimen/dynamic_grid_edge_margin" - android:paddingRight="@dimen/dynamic_grid_edge_margin" - android:saveEnabled="false" > - - - - - - - - - \ No newline at end of file + android:layout_height="@dimen/all_apps_search_bar_field_height" + android:layout_centerHorizontal="true" + android:layout_gravity="top|center_horizontal" + android:layout_marginTop="8dp" + android:background="@drawable/bg_all_apps_searchbox" + android:elevation="1dp" + android:focusableInTouchMode="true" + android:gravity="center" + android:hint="@string/all_apps_search_bar_hint" + android:imeOptions="actionSearch|flagNoExtractUi" + android:inputType="text|textNoSuggestions|textCapWords" + android:maxLines="1" + android:padding="8dp" + android:saveEnabled="false" + android:scrollHorizontally="true" + android:singleLine="true" + android:textColor="?android:attr/textColorSecondary" + android:textColorHint="@drawable/all_apps_search_hint" + android:textSize="16sp" + android:translationY="24dp" /> \ No newline at end of file diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml index 1888e2254d..04f3d027dc 100644 --- a/res/layout/system_shortcut.xml +++ b/res/layout/system_shortcut.xml @@ -34,7 +34,6 @@ android:fontFamily="sans-serif" launcher:iconDisplay="shortcut_popup" launcher:layoutHorizontal="true" - launcher:deferShadowGeneration="true" android:focusable="false" /> - - + android:clipToPadding="false" /> - - \ 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 4cd03ce059..91baf7a769 100644 --- a/res/layout/widgets_list_row_view.xml +++ b/res/layout/widgets_list_row_view.xml @@ -42,7 +42,6 @@ android:textColor="?android:attr/textColorPrimary" android:textSize="16sp" android:textAlignment="viewStart" - launcher:deferShadowGeneration="true" launcher:iconDisplay="widget_section" launcher:iconSizeOverride="@dimen/widget_section_icon_size" launcher:layoutHorizontal="true" /> diff --git a/res/layout/work_tab_footer.xml b/res/layout/work_tab_footer.xml index 21ff55ebd4..379e9d0b44 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-af/strings.xml b/res/values-af/strings.xml index 1ff9a2d969..cfa14922e4 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -137,7 +137,8 @@ "Werk" "Werkprofiel" "Kry werkprogramme hier" - "Elke werkprogram het \'n oranje kenteken en word deur jou organisasie veilig gehou. Skuif programme na jou Tuisskerm vir makliker toegang." + + "Bestuur deur jou organisasie" "Kennisgewings en programme is af" diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index 67c26e79a0..07fe5ef7b1 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -137,7 +137,8 @@ "ሥራ" "የሥራ መገለጫ" "የስራ መተግበሪያዎችን እዚህ ያግኙ" - "እያንዳንዱ የሥራ መተግበሪያ ብርቱካናማ ባጅ አለው እና በእርስዎ ድርጅት በኩል ደህንነቱ ተጠብቋል። ለቀለለ መዳረሻ መተግበሪያዎችን ወደ የእርስዎ መነሻ ማያ ገጽ ያንቀሳቅሱ።" + + "በእርስዎ ድርጅት የሚተዳደር" "ማሳወቂያዎች እና መተግበሪያዎች ጠፍተዋል" diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 1b1d7ca6ba..95508e1212 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -141,7 +141,8 @@ "للعمل" "الملف الشخصي للعمل" "البحث عن تطبيقات العمل هنا" - "يحتوي كل تطبيق للعمل على شارة برتقالية اللون ويظل تحت حماية مؤسستك. يمكنك نقل التطبيقات إلى شاشتك الرئيسية لتسهيل الوصول." + + "ملف شخصي للعمل تديره مؤسستك" "الإشعارات والتطبيقات متوقفة." diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml index 00f71d03c3..d4afc535e4 100644 --- a/res/values-az/strings.xml +++ b/res/values-az/strings.xml @@ -137,7 +137,8 @@ "İş" "İş profili" "Burada iş tətbiqləri axtarın" - "Hər bir iş tətbiqində təşkilat tərəfindən qorunduğunu göstərən narıncı nişan var. Tətbiqləri daha asan giriş üçün Əsas Səhifə Ekranına köçürün." + + "Təşkilatınız tərəfindən idarə olunur" "Bildiriş və tətbiqlər deaktivdir" diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml index 0ee8b3ac49..4b577bad19 100644 --- a/res/values-b+sr+Latn/strings.xml +++ b/res/values-b+sr+Latn/strings.xml @@ -138,7 +138,8 @@ "Poslovne" "Profil za Work" "Pronađite poslovne aplikacije ovde" - "Svaka poslovna aplikacija ima narandžastu značku i štiti je vaša organizacija. Premestite aplikacije na početni ekran da biste im lakše pristupali." + + "Ovim upravlja organizacija" "Obaveštenja i aplikacije su isključeni" diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index 2f5eac7ec0..155ac3cdfe 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -139,7 +139,8 @@ "Праца" "Працоўны профіль" "Знайдзіце працоўныя праграмы тут" - "Кожная працоўная праграма мае аранжавы значок і знаходзіцца пад аховай вашай арганізацыі. Для больш простага доступу перамясціце праграмы на свой Галоўны экран." + + "Пад кіраваннем вашай арганізацыі" "Апавяшчэнні і праграмы выключаны" diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 94b7f13840..113c6d114b 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -137,7 +137,8 @@ "Служебни" "Служебен потребителски профил" "Тук можете да намерите служебните приложения" - "Всяко служебно приложение има оранжева значка и организацията ви се грижи за сигурността му. За по-лесен достъп преместете приложенията на началния си екран." + + "Управлява се от организацията ви" "Известията и приложенията са изключени" diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml index d9c6033b8a..ed57612ab5 100644 --- a/res/values-bn/strings.xml +++ b/res/values-bn/strings.xml @@ -137,7 +137,8 @@ "অফিস" "অফিসের প্রোফাইল" "এখানে কাজের অ্যাপ্সগুলি খুঁজুন" - "প্রতিটি কাজের অ্যাপে একটি করে কমলা ব্যাজ রয়েছে এবং অ্যাপগুলি আপনার প্রতিষ্ঠানের দ্বারা সুরক্ষিত। সহজে অ্যাক্সেস করার জন্য অ্যাপগুলি হোম স্ক্রিনে রাখুন।" + + "আপনার প্রতিষ্ঠানের দ্বারা পরিচালিত" "বিজ্ঞপ্তি এবং অ্যাপ বন্ধ আছে" diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml index 84b2b78189..a96abdee8e 100644 --- a/res/values-bs/strings.xml +++ b/res/values-bs/strings.xml @@ -41,7 +41,7 @@ "Pretraži više aplikacija" "Obavještenja" "Na ovom početnom ekranu nema više prostora." - "Nema više prostora u ladici Favoriti" + "Nema više prostora u ladici Omiljeno" "Spisak aplikacija" "Početna" "Ukloni" @@ -112,7 +112,7 @@ "Premjesti stavku" "Pomjeri stavku u red %1$s kolonu %2$s" "Pomjeri stavku na poziciju %1$s" - "Pomjeri stavku na poziciju %1$s među favoritima" + "Pomjeri stavku na poziciju %1$s među omiljenim" "Stavka je premještena" "Dodaj u folder: %1$s" "Dodaj u folder sa aplikacijom %1$s" @@ -138,7 +138,8 @@ "Poslovne" "Radni profil" "Pronađite poslovne aplikacije ovdje" - "Svaka poslovna aplikacija ima narandžastu značku i osigurava je vaša organizacija. Premjestite aplikacije na Početni ekran, radi lakšeg pristupa." + + "Upravlja vaša organizacija" "Notifikacije i aplikacije su isključene" diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 1ca68eb8b6..b9ba069fcb 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -137,7 +137,8 @@ "Feina" "Perfil professional" "Cerca aplicacions per a la feina aquí" - "Totes les aplicacions per a la feina tenen una insígnia taronja que indica que estan protegides per la teva organització. Mou les aplicacions a la pantalla d\'inici per poder-hi accedir més fàcilment." + + "Gestionat per la teva organització" "Les notificacions i les aplicacions estan desactivades" diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index e5fde42cba..608d297ff5 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -139,7 +139,8 @@ "Pracovní" "Pracovní profil" "Zde naleznete pracovní aplikace" - "Každý pracovní profil má oranžový odznak a je zabezpečen vaší organizací. Aplikace si můžete pro jednoduchost přesunout na plochu." + + "Spravováno vaší organizací" "Oznámení a aplikace jsou vypnuty" diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index 97d8a265e5..0aaedcab79 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -137,7 +137,8 @@ "Arbejde" "Arbejdsprofil" "Find arbejdsapps her" - "Alle arbejdsapps har et orange badge og beskyttes af din organisation. Flyt apps til din startskærm, så du nemmere kan få adgang til dem." + + "Administreret af din organisation" "Underretninger og apps er slået fra" diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 96acfba80d..5cc1451b3b 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -137,7 +137,8 @@ "Geschäftlich" "Arbeitsprofil" "Hier findest du Apps für die Arbeit" - "Jede App für die Arbeit hat ein orangefarbenes Logo. Deine Organisation kümmert sich um den entsprechenden Schutz. Damit du leichter auf Apps zugreifen kannst, verschiebe sie auf deinen Startbildschirm." + + "Wird von deiner Organisation verwaltet" "Benachrichtigungen und Apps sind deaktiviert" diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index 9328c5f311..21c9706f41 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -137,7 +137,8 @@ "Εργασίας" "Προφίλ εργασίας" "Βρείτε όλες τις εφαρμογές εργασίας εδώ" - "Κάθε εφαρμογή εργασίας φέρει ένα πορτοκαλί σήμα και διατηρείται ασφαλής από τον οργανισμό σας. Μετακινήστε τις εφαρμογές εργασίας στην Αρχική οθόνη, για να έχετε πιο εύκολη πρόσβαση." + + "Διαχειριζόμενο από τον οργανισμό σας" "Οι ειδοποιήσεις και οι εφαρμογές είναι απενεργοποιημένες" diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml index d7ab7d252b..c84efc786b 100644 --- a/res/values-en-rAU/strings.xml +++ b/res/values-en-rAU/strings.xml @@ -137,7 +137,8 @@ "Work" "Work profile" "Find work apps here" - "Each work app has an orange badge and is kept secure by your organisation. Move apps to your Home screen for easier access." + + "Managed by your organisation" "Notifications and apps are off" diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index d7ab7d252b..c84efc786b 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -137,7 +137,8 @@ "Work" "Work profile" "Find work apps here" - "Each work app has an orange badge and is kept secure by your organisation. Move apps to your Home screen for easier access." + + "Managed by your organisation" "Notifications and apps are off" diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index d7ab7d252b..c84efc786b 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -137,7 +137,8 @@ "Work" "Work profile" "Find work apps here" - "Each work app has an orange badge and is kept secure by your organisation. Move apps to your Home screen for easier access." + + "Managed by your organisation" "Notifications and apps are off" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 11cfa2a457..23bf97d5e9 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -137,7 +137,8 @@ "Laborales" "Perfil de trabajo" "Apps de trabajo" - "Cada app de trabajo tiene una insignia naranja y está protegida por tu organización. Mueve las apps a la pantalla principal para acceder a ellas con mayor facilidad." + + "Administrado por tu organización" "Las notificaciones y las apps están desactivadas" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 39da94c1f5..0fb401ab9d 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -137,7 +137,8 @@ "Trabajo" "Perfil de trabajo" "Aplicaciones de trabajo" - "Cada aplicación de trabajo tiene una insignia naranja y está protegida por tu organización. Mueve las aplicaciones a la pantalla de inicio para acceder a ellas más fácilmente." + + "Administrada por tu organización" "Las notificaciones y las aplicaciones están desactivadas" diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index 68a0429ecb..555f99708d 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -137,7 +137,8 @@ "Töö" "Tööprofiil" "Töörakendused leiate siit" - "Igal töörakendusel on oranž märk ja teie organisatsioon tagab selle turvalisuse. Teisaldage rakendused avaekraanile, et neile oleks lihtsam juurde pääseda." + + "Haldab teie organisatsioon" "Märguanded ja rakendused on välja lülitatud" diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index 27a56dd11c..80d705db0f 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -137,7 +137,8 @@ "Lanekoak" "Laneko profila" "Hemen dituzu laneko aplikazioak" - "Laneko aplikazio bakoitzak bereizgarri laranja bat dauka eta erakundeak babesten du. Aplikazioak errazago atzitzeko, eraman itzazu hasierako pantailara." + + "Erakundeak kudeatzen du" "Jakinarazpenak eta aplikazioak desaktibatuta daude" diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 128af9032f..5528119723 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -137,7 +137,8 @@ "محل کار" "نمایه کاری" "اینجا برنامه‌های کاری را پیدا کنید" - "همه برنامه‌های کاری نشان نارنجی‌رنگی دارند و توسط سازمان شما امن نگه داشته می‌شود. برنامه‌های کاری را برای دسترسی آسان‌تر به صفحه اصلی انتقال دهید." + + "توسط سازمانتان مدیریت می‌شود" "اعلان‌ها و برنامه‌ها خاموش هستند" diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index f5b08179b9..9560b66da7 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -137,7 +137,8 @@ "Työsovellukset" "Työprofiili" "Etsi työsovelluksia tästä" - "Kaikissa työsovelluksissa on oranssi merkki ja ne ovat organisaatiosi suojaamia. Voit siirtää työsovelluksia aloitusnäytölle käytön helpottamiseksi." + + "Organisaatiosi hallinnoima" "Ilmoitukset ja sovellukset ovat poissa käytöstä" diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index 40935354d7..c6961805fd 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -137,7 +137,8 @@ "Travail" "Profil professionnel" "Trouvez ici des applications professionnelles" - "Chaque application professionnelle comporte un badge orange, ce qui signifie qu\'elle est sécurisée par votre organisation. Vous pouvez déplacer vos applications vers l\'écran d\'accueil afin d\'y accéder plus facilement." + + "Géré par votre organisation" "Les notifications et les applications sont désactivées" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 520ad78a4f..e0997fc85a 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -137,7 +137,8 @@ "Professionnelles" "Profil professionnel" "Retrouvez ici vos applications professionnelles" - "Les applications professionnelles sont accompagnées d\'un badge orange et sont sécurisées par votre organisation. Vous pouvez les déplacer vers votre écran d\'accueil pour y accéder plus facilement." + + "Géré par votre organisation" "Les notifications et les applications sont désactivées" diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index 9a842b1902..219b76e5fe 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -137,7 +137,8 @@ "Traballo" "Perfil de traballo" "Buscar aplicacións do traballo aquí" - "As aplicacións do traballo teñen unha insignia laranxa e están protexidas pola túa organización. Traslada as aplicacións á pantalla de inicio para acceder a elas de forma máis fácil." + + "Perfil xestionado pola túa organización" "As notificacións e as aplicacións están desactivadas" diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index e030659847..68b4edd16c 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -137,7 +137,8 @@ "કાર્યાલયની ઍપ" "કાર્યાલયની પ્રોફાઇલ" "કાર્ય ઍપને અહીંથી મેળવો" - "દરેક કાર્ય ઍપ પાસે એક નારંગી બૅજ હોય છે અને તમારી સંસ્થા દ્વારા તેને સુરક્ષિત રાખવામાં આવે છે. વધુ સરળ ઍક્સેસ માટે ઍપને તમારી હોમ સ્ક્રીન પર ખસેડો." + + "તમારી સંસ્થા દ્વારા મેનેજ કરેલ" "નોટિફિકેશન અને ઍપ બંધ છે" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index aa1e8dd9f6..15a4deb945 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -137,7 +137,8 @@ "काम से जुड़े ऐप" "कार्य प्रोफ़ाइल" "काम से जुड़े सभी ऐप्लिकेशन यहां पाएं" - "काम से जुड़े हर ऐप्लिकेशन पर एक नारंगी रंग का बैज (निशान) होता है जिसकी सुरक्षा आपका संगठन करता है. आसानी से इस्तेमाल करने के लिए ऐप्लिकेशन को अपनी होम स्क्रीन पर ले जाएं." + + "आपका संगठन प्रबंधित कर रहा है" "सूचनाएं और ऐप्लिकेशन बंद हैं" diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index ec3c6b2abc..d28c108b1b 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -138,7 +138,8 @@ "Posao" "Radni profil" "Ovdje možete pronaći radne aplikacije" - "Svaka radna aplikacija ima narančastu značku i štiti je vaša organizacija. Premjestite aplikacije na početni zaslon radi lakšeg pristupa." + + "Pod upravljanjem vaše organizacije" "Obavijesti i aplikacije isključeni su" diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 697153a222..f69019649a 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -137,7 +137,8 @@ "Munkahelyi" "Munkaprofil" "Itt kereshet munkahelyi alkalmazásokat" - "Az egyes munkahelyi alkalmazásokon narancs jelvény található, és biztonságukról az Ön szervezete gondoskodik. A könnyebb hozzáférés érdekében helyezze át az alkalmazásokat a kezdőképernyőre." + + "Az Ön szervezete kezeli" "Az értesítések és az alkalmazások ki vannak kapcsolva" diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml index 02a561f9ab..e233a4404a 100644 --- a/res/values-hy/strings.xml +++ b/res/values-hy/strings.xml @@ -137,7 +137,8 @@ "Աշխատանքային" "Աշխատանքային պրոֆիլ" "Գտեք աշխատանքային հավելվածներ այստեղ" - "Աշխատանքային հավելվածները նշված են նարնջագույն նշանով, նման հավելվածների անվտանգությունը ապահովում է ձեր կազմակերպությունը։ Հարմարության համար աշխատանքային հավելվածները կարող եք տեղափոխել հիմնական էկրան։" + + "Կառավարվում է ձեր կազմակերպության կողմից" "Ծանուցումներն ու հավելվածներն անջատված են" diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index d115c73776..89e57e7019 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -137,7 +137,8 @@ "Kantor" "Profil kerja" "Temukan aplikasi kerja di sini" - "Setiap aplikasi kerja memiliki badge oranye dan dibuat tetap aman oleh organisasi. Pindahkan aplikasi ke Layar utama untuk memudahkan akses." + + "Dikelola oleh organisasi" "Notifikasi dan aplikasi nonaktif" diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml index ba9a47d85b..1e89142cb1 100644 --- a/res/values-is/strings.xml +++ b/res/values-is/strings.xml @@ -137,7 +137,8 @@ "Vinna" "Vinnusnið" "Hér finnurðu vinnuforrit" - "Öll vinnuforrit eru með appelsínugulu merki og fyrirtækið þitt tryggir öryggi þeirra. Færðu forrit yfir á heimaskjáinn fyrir auðveldari aðgang að þeim." + + "Stjórnað af fyrirtækinu þínu" "Slökkt er á tilkynningum og forritum" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 6c98d3e1b8..8584629e2d 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -137,7 +137,8 @@ "Lavoro" "Profilo di lavoro" "Qui puoi trovare le tue app di lavoro" - "Ogni app di lavoro è contrassegnata da un badge arancione e viene tenuta al sicuro dalla tua organizzazione. Sposta le app nella schermata Home per accedervi più facilmente." + + "Gestito dalla tua organizzazione" "Le notifiche e le app non sono attive" diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 43c8520877..961bd01117 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -139,7 +139,8 @@ "עבודה" "פרופיל עבודה" "ניתן למצוא כאן את אפליקציות העבודה" - "לכל אפליקציית עבודה יש תג כתום ואבטחתה מטופלת בידי הארגון. אפשר להעביר אפליקציות אל מסך דף הבית כדי להקל את הגישה אליהן." + + "מנוהל בידי הארגון" "הודעות ואפליקציות כבויות" diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 36f3c5e95e..75db7d6b61 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -137,7 +137,8 @@ "仕事用" "仕事用プロファイル" "ここには仕事用アプリが表示されます" - "仕事用アプリにはオレンジのバッジが表示され、組織によって安全に保護されています。仕事用アプリをホーム画面に移動すると、簡単にアクセスできます。" + + "組織によって管理されています" "通知とアプリは OFF です" diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml index b6d78778f9..5f3d47fc68 100644 --- a/res/values-ka/strings.xml +++ b/res/values-ka/strings.xml @@ -137,7 +137,8 @@ "სამსახური" "სამსახურის პროფილი" "აქ თავმოყრილია სამსახურის აპები" - "სამსახურის აპები მონიშნულია სტაფილოსფერი ბეჯით, რაც ნიშნავს, რომ მათ უსაფრთხოებას თქვენი ორგანიზაცია უზრუნველყოფს. მარტივი წვდომისთვის, შეგიძლიათ სამსახურის აპები მთავარი ეკრანზე გადაიტანოთ." + + "იმართება თქვენი ორგანიზაციის მიერ" "შეტყობინებები და აპები გამორთულია" diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml index 6c4deec4b4..12da5052f1 100644 --- a/res/values-kk/strings.xml +++ b/res/values-kk/strings.xml @@ -137,7 +137,8 @@ "Жұмыс" "Жұмыс профилі" "Жұмыс қолданбалары осы жерде берілген" - "Әрбір жұмыс қолданбасында қызғылт сары танымбелгі бар. Ол оның қауіпсіздігі ұйым арқылы қамтамасыз етілетінін білдіреді. Жұмыс қолданбаларына оңай кіру үшін, оларды Негізгі экранға жылжытуға болады." + + "Ұйым арқылы басқарылады" "Хабарландырулар мен қолданбалар өшірулі" diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml index d588bc19a7..9704194afc 100644 --- a/res/values-km/strings.xml +++ b/res/values-km/strings.xml @@ -137,7 +137,8 @@ "ការងារ" "កម្រងព័ត៌មានការងារ" "ស្វែង​រក​កម្មវិធី​ការងារ​នៅទីនេះ" - "កម្មវិធី​ការងារ​នីមួយៗ​មាន​ស្លាក​​ពណ៌​ទឹកក្រូច និងត្រូវ​បានរក្សាទុក​យ៉ាងមានសុវត្ថិភាព​ដោយស្ថាប័ន​របស់អ្នក។ សូម​ផ្លាស់ទី​កម្មវិធី​ទៅកាន់​អេក្រង់​ដើម​របស់អ្នក​ ដើម្បី​ងាយស្រួល​ចូលប្រើជាងមុន។" + + "គ្រប់គ្រងដោយ​ស្ថាប័ន​របស់អ្នក" "ការជូនដំណឹង​ និងកម្មវិធី​ត្រូវបានបិទ" diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml index a8f97847c8..1746cbb282 100644 --- a/res/values-kn/strings.xml +++ b/res/values-kn/strings.xml @@ -137,7 +137,8 @@ "ಕೆಲಸ" "ಕೆಲಸದ ಪ್ರೊಫೈಲ್" "ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಇಲ್ಲಿ ಹುಡುಕಿ" - "ಕೆಲಸದ ಪ್ರತಿ ಅಪ್ಲಿಕೇಶನ್ ಕಿತ್ತಳೆ ಬ್ಯಾಡ್ಜ್ ಹೊಂದಿದೆ ಮತ್ತು ನಿಮ್ಮ ಸಂಸ್ಥೆಯಿಂದ ಸುರಕ್ಷಿತವಾಗಿ ಇರಿಸಲಾಗುತ್ತದೆ. ಸುಲಭ ಪ್ರವೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಸರಿಸಿ." + + "ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗಿದೆ" "ಅಧಿಸೂಚನೆಗಳು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಆಫ್ ಆಗಿವೆ" diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 0ebbbe717b..580297fa50 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -137,7 +137,8 @@ "직장" "직장 프로필" "여기에서 업무용 앱 찾기" - "각 업무용 앱에는 주황색 배지가 있으며 업무용 앱은 조직에서 안전하게 보호됩니다. 앱을 홈 화면으로 이동하여 더 간편하게 사용하세요." + + "조직에서 관리" "알림 및 앱 사용 중지됨" diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml index 05652fc143..e6493dbc41 100644 --- a/res/values-ky/strings.xml +++ b/res/values-ky/strings.xml @@ -137,7 +137,8 @@ "Жумуш колдонмолору" "Жумуш профили" "Жумуш колдонмолорун бул жерден таап алыңыз" - "Ар бир жумуш колдонмосунун кызгылт сары бейджиги бар жана ал уюмуңуз тарабынан коопсуз сакталат. Колдонмолорго тез өтүү үчүн аларды Башкы экранга кошуп алыңыз." + + "Уюмуңуз тарабынан башкарылат" "Билдирүүлөр жана колдонмолор өчүрүлгөн" diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml index 40ffffe128..6cf23ad10a 100644 --- a/res/values-land/dimens.xml +++ b/res/values-land/dimens.xml @@ -25,7 +25,6 @@ 24dp - 120dp 48dp 4dp diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml index e446e7c50e..c0c9bb0702 100644 --- a/res/values-lo/strings.xml +++ b/res/values-lo/strings.xml @@ -137,7 +137,8 @@ "ວຽກ" "ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ" "ຊອກຫາແອັບວຽກຢູ່ບ່ອນນີ້" - "ແຕ່ລະແອັບວຽກຈະມີປ້າຍສີສົ້ມ ແລະ ຖືກຈັດເກັບໄວ້ຢ່າງປອດໄພໂດຍອົງກອນຂອງທ່ານ. ທ່ານສາມາດຍ້າຍແອັບໄປໃສ່ໜ້າຈໍຫຼັກເພື່ອໃຫ້ເຂົ້າໃຊ້ງ່າຍຂຶ້ນໄດ້." + + "ຈັດການໂດຍອົງກອນຂອງທ່ານ" "ການແຈ້ງເຕືອນ ແລະ ແອັບຖືກປິດໄວ້" diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index 2e37e98ae9..3e985cb094 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -139,7 +139,8 @@ "Darbo" "Darbo profilis" "Darbo programas rasite čia" - "Kiekvienai darbo programai priskirtas oranžinis ženklelis, o tokių programų sauga rūpinasi jūsų organizacija. Perkelkite darbo programas į pagrindinį ekraną, kad galėtumėte lengviau jas pasiekti." + + "Tvarko jūsų organizacija" "Programos ir pranešimai išjungti" diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 3b96ffa048..6a9d15791b 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -138,7 +138,8 @@ "Darba lietotnes" "Darba profils" "Meklējiet darba lietotnes šeit" - "Katrai darba lietotnei ir oranža emblēma, un jūsu organizācija aizsargā šīs lietotnes. Ērtākai piekļuvei pārvietojiet darba lietotnes uz sākuma ekrānu." + + "Pārvalda jūsu organizācija" "Paziņojumi un lietotnes ir izslēgtas" diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index 3a0fc2b633..01408ddd9f 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -137,7 +137,8 @@ "За работа" "Работен профил" "Најдете апликации за работа тука" - "Секоја апликација за работа има портокалова значка и е обезбедена од вашата организација. За полесен пристап, апликациите за работа преместете ги на почетниот екран." + + "Управувано од вашата организација" "Известувањата и апликациите се исклучени" diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml index 84f769b494..6e6340b5a0 100644 --- a/res/values-ml/strings.xml +++ b/res/values-ml/strings.xml @@ -137,7 +137,8 @@ "ജോലി" "ഔദ്യോഗിക പ്രൊഫൈൽ" "ഔദ്യോഗിക ആപ്പുകൾ ഇവിടെ കണ്ടെത്തുക" - "എല്ലാ ഔദ്യോഗിക ആപ്പിനും ഓറഞ്ച് നിറത്തിലുള്ള ഒരു ബാഡ്‌ജ് ഉണ്ട്, നിങ്ങളുടെ സ്ഥാപനം അത് സുരക്ഷിതമായി സൂക്ഷിക്കുന്നു. എളുപ്പത്തിൽ ആക്സസ് ചെയ്യാൻ ആപ്പുകളെ ഹോം സ്‌ക്രീനിലേക്ക് നീക്കുക." + + "നിങ്ങളുടെ സ്ഥാപനം നിയന്ത്രിക്കുന്നത്" "അറിയിപ്പുകളും ആപ്പുകളും ഓഫാണ്" diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml index 5e91a4601a..7119ccf700 100644 --- a/res/values-mn/strings.xml +++ b/res/values-mn/strings.xml @@ -137,7 +137,8 @@ "Ажил" "Ажлын профайл" "Ажлын аппыг эндээс олно уу" - "Ажлын апп тус бүр улбар шар тэмдэгтэй ба эдгээрийг танай байгууллагаас аюулгүй байлгадаг. Аппуудад хялбараар хандахын тулд тэдгээрийг Үндсэн Нүүрэнд зөөнө үү." + + "Танай байгууллагаас удирддаг" "Мэдэгдэл, апп унтраалттай байна" diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml index 94b75d7885..fd5d999195 100644 --- a/res/values-mr/strings.xml +++ b/res/values-mr/strings.xml @@ -137,7 +137,8 @@ "कार्यालय" "कार्य प्रोफाइल" "कामाची अ‍ॅप्स येथे मिळवा" - "प्रत्येक कार्य अ‍ॅपमध्ये नारिंगी बॅज असतो आणि तो तुमच्या संस्थेकडून सुरक्षित ठेवला जातो. अधिक सहज अ‍ॅक्सेससाठी अ‍ॅप्स तुमच्या होम स्क्रीनवर हलवा." + + "तुमच्या संस्थेकडून व्यवस्थापित" "सूचना आणि अॅप्स बंद आहेत" diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index 6e19421768..1fe38a6793 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -137,7 +137,8 @@ "Kerja" "Profil kerja" "Temui apl kerja di sini" - "Setiap apl kerja terdapat lencana berwarna oren dan dilindungi oleh organisasi anda. Alihkan apl ke Skrin Utama untuk akses yang lebh mudah." + + "Diurus oleh organisasi anda" "Pemberitahuan dan apl dimatikan" diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml index 3cf9208dfe..c004318377 100644 --- a/res/values-my/strings.xml +++ b/res/values-my/strings.xml @@ -137,7 +137,8 @@ "အလုပ်" "အလုပ်ပရိုဖိုင်" "အလုပ်အက်ပ်များကို ဤနေရာတွင်ရှာဖွေပါ" - "အလုပ်အက်ပ်တိုင်းတွင် လိမ္မော်ရောင်တံဆိပ် တစ်ခုစီရှိပြီး သင်၏ အဖွဲ့အစည်းက လုံခြုံအောင် ထားရှိပါသည်။ အသုံးပြုရ ပိုမိုလွယ်ကူစေရန် အက်ပ်များကို သင်၏ ပင်မမျက်နှာပြင်သို့ ရွှေ့ပါ။" + + "သင်၏ အဖွဲ့အစည်းက စီမံခန့်ခွဲထားပါသည်" "အကြောင်းကြားချက်များနှင့် အက်ပ်များကို ပိတ်ထားသည်" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 2bdd6ce40d..7a36062744 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -137,7 +137,8 @@ "Jobb" "Jobbprofil" "Finn jobbapper her" - "Alle jobbapper har et oransje merke og sikres av organisasjonen din. Flytt apper til startskjermen for å gjøre det enklere å finne dem." + + "Administreres av organisasjonen din" "Varsler og apper er slått av" diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml index d15e8b220d..602b162458 100644 --- a/res/values-ne/strings.xml +++ b/res/values-ne/strings.xml @@ -137,7 +137,8 @@ "कार्यसम्बन्धी" "कार्य प्रोफाइल" "कार्यसम्बन्धी अनुप्रयोगहरू यहाँ प्राप्त गर्नुहोस्" - "कार्यसम्बन्धी प्रत्येक अनुप्रयोगमा एउटा सुन्तला रङको ब्याज छ र यसलाई तपाईंको संगठनद्वारा सुरक्षित राखिएको छ । अझ सजिलो गरी पहुँच राख्नका लागि कार्यसम्बन्धी अनुप्रयोगहरूलाई तपाईंको गृहस्क्रिनमा सार्नुहोस्‌।" + + "तपाईंको सङ्गठनले व्यवस्थापन गरेको" "सूचना र अनुप्रयोगहरू निष्क्रिय छन्‌" diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 38c24a5a8a..a686838f55 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -137,7 +137,8 @@ "Werk" "Werkprofiel" "Zoek hier naar werk-apps" - "Elke werk-app heeft een oranje badge en wordt beveiligd door je organisatie. Verplaats apps naar je startscherm om gemakkelijker toegang te krijgen." + + "Beheerd door je organisatie" "Meldingen en apps zijn uitgeschakeld" diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml index 6b6c929364..f81c4a2e7a 100644 --- a/res/values-pa/strings.xml +++ b/res/values-pa/strings.xml @@ -137,7 +137,8 @@ "ਕਾਰਜ-ਸਥਾਨ" "ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ" "ਕਾਰਜ-ਸਥਾਨ ਐਪਾਂ ਇੱਥੇ ਲੱਭੋ" - "ਹਰੇਕ ਕਾਰਜ-ਸਥਾਨ ਐਪ ਦਾ ਇੱਕ ਸੰਤਰੀ ਬੈਜ ਹੁੰਦਾ ਹੈ ਅਤੇ ਉਸਨੂੰ ਤੁਹਾਡੀ ਸੰਸਥਾ ਰਾਹੀਂ ਸੁਰੱਖਿਅਤ ਰੱਖਿਆ ਜਾਂਦਾ ਹੈ। ਵਧੇਰੇ ਆਸਾਨ ਪਹੁੰਚ ਲਈ ਐਪਾਂ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਜਾਓ।" + + "ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ" "ਸੂਚਨਾਵਾਂ ਅਤੇ ਐਪਾਂ ਬੰਦ ਹਨ" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index c90ba1e231..77aeee267a 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -139,7 +139,8 @@ "Praca" "Profil służbowy" "Aplikacje do pracy" - "Każda aplikacja do pracy ma pomarańczową plakietkę, a o jej bezpieczeństwo dba Twoja organizacja. Aplikacje można przenieść na ekran główny, by były łatwiej dostępne." + + "Profil zarządzany przez Twoją organizację" "Powiadomienia i aplikacje są wyłączone" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index c370a8e0ff..cd473fafa1 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -137,7 +137,8 @@ "Trabalho" "Perfil de trabalho" "Encontrar as aplicações de trabalho aqui" - "Cada aplicação de trabalho apresenta um emblema laranja, pelo que a sua entidade a mantém em segurança. Pode mover as aplicações para o ecrã principal para facilitar o acesso." + + "Gerido pela sua entidade" "As notificações e as aplicações estão desativadas." diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index 0686ae796c..48e37efb64 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -137,7 +137,8 @@ "Comerciais" "Perfil de trabalho" "Localizar apps de trabalho aqui" - "Cada app de trabalho tem um selo laranja e é mantido em segurança pela sua organização. Mova os apps para sua tela inicial para facilitar o acesso." + + "Gerenciados pela sua organização" "As notificações e os apps estão desativados" diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 651b264a77..495ba4c2f9 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -138,7 +138,8 @@ "Profesionale" "Profil de serviciu" "Găsiți aplicații de serviciu aici" - "Fiecare aplicație de serviciu are o insignă portocalie și este păstrată în siguranță de organizația dvs. Mutați aplicațiile de serviciu pe ecranul de pornire pentru acces mai ușor." + + "Gestionat de organizația dvs." "Notificările și aplicațiile sunt dezactivate" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 9f43c56e1d..10490f38b5 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -67,7 +67,7 @@ В приложении \"%1$s\" %2$d уведомления "Стр. %1$d из %2$d" - "Главные экран %1$d из %2$d" + "Главный экран %1$d из %2$d" "Новый экран" "Папка открыта, %1$d x %2$d" "Нажмите, чтобы закрыть папку" @@ -139,7 +139,8 @@ "Рабочие" "Рабочий профиль" "Приложения для работы" - "Рабочие приложения отмечены оранжевым значком, который подтверждает, что ваша организация гарантирует их безопасность. Для удобства перенесите эти приложения на главный экран." + + "Управляется вашей организацией" "Уведомления и приложения отключены." diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml index bbcc25781f..5024fecf8b 100644 --- a/res/values-si/strings.xml +++ b/res/values-si/strings.xml @@ -137,7 +137,8 @@ "කාර්යාලය" "කාර්යාල පැතිකඩ" "මෙහි කාර්යාල යෙදුම් සොයා ගන්න" - "සෑම කාර්යාල යෙදුමකම තැඹිලි ලාංඡනයක් ඇත ඇති අතර එය ඔබේ සංවිධානය විසින් සුරක්ෂිතව තබා ගනී. වඩා පහසුවෙන් පිවිසීමට යෙදුම් ඔබගේ මුල් පිටු තිරය වෙත ගෙන යන්න." + + "ඔබේ සංවිධානය විසින් කළමනාකරණය කරනු ලැබේ" "දැනුම්දීම් සහ යෙදුම් ක්‍රියාවිරහිතයි" diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index a3bc4ec577..58baac4851 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -139,7 +139,8 @@ "Pracovné" "Pracovný profil" "Tu nájdete pracovné aplikácie" - "Všetky pracovné aplikácie majú oranžový štítok a sú bezpečne uchovávané vašou organizáciou. Ak chcete mať k aplikáciám ľahší prístup, presuňte ich na plochu." + + "Spravované vašou organizáciou" "Upozornenia a aplikácie sú vypnuté" diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 337cb2de07..758c5b2185 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -139,7 +139,8 @@ "Služba" "Delovni profil" "Tukaj poiščite delovne aplikacije" - "Vsaka delovna aplikacija ima oranžno značko. Za varnost teh aplikacij skrbi vaša organizacija. Za preprostejši dostop premaknite aplikacije na začetni zaslon." + + "Upravlja vaša organizacija" "Obvestila in aplikacije – izklopljeno" diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml index e79f0d448b..d260a4b774 100644 --- a/res/values-sq/strings.xml +++ b/res/values-sq/strings.xml @@ -137,7 +137,8 @@ "Punë" "Profili i punës" "Gjej këtu aplikacionet e punës" - "Secili aplikacion pune ka një distinktiv portokalli dhe mbahet i sigurt nga organizata jote. Zhvendosi aplikacionet e punës në ekranin tënd kryesor për qasje më të lehtë." + + "Menaxhohet nga organizata jote" "Njoftimet dhe aplikacionet janë joaktive" diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 7d5e28df03..c190e758e1 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -138,7 +138,8 @@ "Пословне" "Профил за Work" "Пронађите пословне апликације овде" - "Свака пословна апликација има наранџасту значку и штити је ваша организација. Преместите апликације на почетни екран да бисте им лакше приступали." + + "Овим управља организација" "Обавештења и апликације су искључени" diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index c886780e83..85e814b813 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -137,7 +137,8 @@ "Arbete" "Jobbprofil" "Här hittar du jobbappar" - "Alla jobbappar har ett orange märke och organisationen ser till att de är skyddade. Flytta apparna till startskärmen så kommer du åt dem lättare." + + "Hanteras av organisationen" "Aviseringar och appar är inaktiverade" diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 8925c8935b..a9dc8a6e84 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -139,7 +139,8 @@ "Kazini" "Wasifu wa kazini" "Pata programu za kazi hapa" - "Kila programu ya kazi ina beji ya rangi ya machungwa na hulindwa na shirika lako. Hamishia programu kwenye skrini yako ya kwanza ili uzifikie kwa urahisi." + + "Inasimamiwa na shirika lako" "Vipenge vya arifa na programu vimezimwa" diff --git a/res/values-sw720dp/styles.xml b/res/values-sw720dp/styles.xml index 72894dcf37..f322e9f31b 100644 --- a/res/values-sw720dp/styles.xml +++ b/res/values-sw720dp/styles.xml @@ -26,7 +26,6 @@ true true ?android:attr/textColorSecondary - @layout/search_container_all_apps diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index fc68b82869..25bfc02f44 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -137,7 +137,8 @@ "பணி" "பணி விவரம்" "பணி ஆப்ஸை இங்கு காணலாம்" - "ஒவ்வொரு பணிப் பயன்பாடும் ஆரஞ்சு நிற பேட்ஜைக் கொண்டிருக்கும். இவை, உங்கள் நிறுவனத்தால் பாதுகாப்பாக வைக்கப்பட்டுள்ளன. இந்த ஆப்ஸை எளிதாக அணுக, முகப்புத் திரைக்கு நகர்த்திக்கொள்ளவும்." + + "உங்கள் நிறுவனம் நிர்வகிக்கிறது" "ஆப்ஸும் அறிவிப்புகளும் ஆஃப் செய்யப்பட்டுள்ளன" diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index fb8a71b1e3..6af501138f 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -137,7 +137,8 @@ "కార్యాలయం" "కార్యాలయ ప్రొఫైల్" "కార్యాలయ యాప్‌లను ఇక్కడ కనుగొనండి" - "ప్రతి కార్యాలయ యాప్‌కు నారింజ బ్యాడ్జ్‌ ఉంది మరియు మీ సంస్థ ద్వారా సురక్షితంగా ఉంచబడుతుంది. సులభ యాక్సెస్ కోసం యాప్‌లను మీ హోమ్ స్క్రీన్‌కి తరలించండి." + + "మీ సంస్థ ద్వారా నిర్వహించబడతాయి" "నోటిఫికేషన్‌లు మరియు యాప్‌లు ఆఫ్ చేయబడ్డాయి" diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index 6f2bc710a6..866bfc913c 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -137,7 +137,8 @@ "งาน" "โปรไฟล์งาน" "หาแอปงานที่นี่" - "แอปงานแต่ละแอปมีป้ายสีส้มและได้รับการรักษาความปลอดภัยจากองค์กรของคุณ ย้ายแอปไปยังหน้าจอหลักเพื่อให้เข้าถึงได้ง่ายขึ้น" + + "จัดการโดยองค์กร" "ปิดการแจ้งเตือนและแอปอยู่" diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index 5aad29a652..d0a820d917 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -137,7 +137,8 @@ "Trabaho" "Profile sa trabaho" "Maghanap ng mga app para sa trabaho rito" - "Ang bawat app para sa trabaho ay may orange na badge at pinapanatiling ligtas ng iyong organisasyon. Ilipat ang mga app sa iyong Home screen para mas madaling ma-access." + + "Pinamamahalaan ng iyong organisasyon" "Naka-off ang mga notification at app" diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index a0ebe6f050..1f75b6781e 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -137,7 +137,8 @@ "İş" "İş profili" "İş uygulamalarını burada bulabilirsiniz" - "Her iş uygulamasında, uygulama güvenliğinin kuruluşunuz tarafından sağlandığını gösteren turuncu bir rozet bulunur. Uygulamaları daha kolay erişim için Ana ekranınıza taşıyın." + + "Kuruluşunuz tarafından yönetiliyor" "Bildirimler ve uygulamalar kapalı" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index ffced576bc..095ff5ba30 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -139,7 +139,8 @@ "Робочі додатки" "Робочий профіль" "Робочі додатки містяться тут" - "Кожний робочий додаток має оранжевий значок. Його захищає організація. Для швидкого доступу перенесіть додатки на головний екран." + + "Профілем керує ваша організація" "Сповіщення та додатки вимкнено" diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml index cd657383d9..ea8a4d7e70 100644 --- a/res/values-ur/strings.xml +++ b/res/values-ur/strings.xml @@ -137,7 +137,8 @@ "دفتری" "دفتری پروفائل" "یہاں دفتری ایپس تلاش کریں" - "ہر دفتری ایپ میں نارنجی بَیج ہوتا ہے اور اسے آپ کی تنظیم محفوظ رکھتی ہے۔ زیادہ آسان رسائی کیلئے ایپس کو اپنی ہوم اسکرین پر منتقل کریں۔" + + "آپ کی تنظیم کے زیر انتظام" "اطلاعات اور ایپس آف ہیں" diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml index 200c2c0a16..70dc41fa73 100644 --- a/res/values-uz/strings.xml +++ b/res/values-uz/strings.xml @@ -137,7 +137,8 @@ "Ishchi" "Ishchi profil" "Ishga oid ilovalarni shu yerdan topish mumkin" - "Apelsinrangli nishonga ega har bir ishga oid ilova tashkilotingiz tomonidan himoyalanadi. Ishga oid ilovalarga osonroq kirish uchun ularni bosh ekranga chiqaring." + + "Tashkilotingiz tomonidan boshqariladi" "Bildirishnomalar va ilovalar faol emas" diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index a5b48922b0..1b8558f40d 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -137,7 +137,8 @@ "Cơ quan" "Hồ sơ công việc" "Tìm ứng dụng công việc tại đây" - "Mỗi ứng dụng công việc đều có một huy hiệu màu cam và được tổ chức của bạn bảo mật. Bạn có thể di chuyển ứng dụng đến Màn hình chính để truy cập dễ dàng hơn." + + "Do tổ chức của bạn quản lý" "Thông báo và ứng dụng đang tắt" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 71e06e7aa8..694125711d 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -137,7 +137,8 @@ "工作" "工作资料" "请在此处查找工作应用" - "每个工作应用均有一个橙色徽标,并由贵单位负责确保其安全。请将工作应用移到主屏幕,以便轻松访问。" + + "由贵单位管理" "通知和应用均已关闭" diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index 7f792f8063..86c52465b1 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -137,7 +137,8 @@ "商務" "工作設定檔" "請在此處尋找工作應用程式" - "每個工作應用程式都有橙色徽章,並由您的機構負責保持安全。您可以將工作應用程式移至主畫面,以便輕鬆存取。" + + "由您的機構管理" "通知和應用程式已關閉" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index b95e838119..1bac58a124 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -137,7 +137,8 @@ "公司" "Work 設定檔" "在這裡尋找辦公應用程式" - "每個辦公應用程式都有橘色徽章,並由貴機構負責管理及確保其安全。請將辦公應用程式移至主螢幕以便輕鬆存取。" + + "由貴機構所管理" "已關閉通知和應用程式" diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 65d7d4c60d..323144bd23 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -137,7 +137,8 @@ "Umsebenzi" "Iphrofayela yomsebenzi" "Thola izinhlelo zokusebenza lapha" - "Uhlo lokusebenza ngalunye lomsebenzi linebheji ewolintshi futhi igcinwa iphephile inhlangano yakho. Hambisa izinhlelo zokusebenza esikrinini sakho sasekhaya ngokufinyelela okulula." + + "Kuphethwe inhlangano yakho" "Izaziso nezinhlelo zokusebenza kuvaliwe" diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 1351dfa847..64ca05e3c2 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -44,7 +44,6 @@ - diff --git a/res/values/config.xml b/res/values/config.xml index 065ad362ec..3f727cf38e 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -116,6 +116,9 @@ + + + 150 80 @@ -124,7 +127,7 @@ - + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 1f468445c9..f8f9c2ae99 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -23,10 +23,6 @@ 24dp 1dp 8dp - 80dp - 120dp - 80dp - 25dp 8dp 8dp @@ -79,7 +75,7 @@ 0dp 48dp - 60dp + 30dp 40dp 144dp 700dp @@ -227,5 +223,5 @@ 70dp - 48dp + 24dp diff --git a/res/values/drawables.xml b/res/values/drawables.xml index fea17b1530..1367174b1b 100644 --- a/res/values/drawables.xml +++ b/res/values/drawables.xml @@ -14,7 +14,7 @@ limitations under the License. --> - @drawable/ic_info_no_shadow + @drawable/ic_setting @drawable/ic_remove_no_shadow @drawable/ic_uninstall_no_shadow \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 381830c5db..b39cb04057 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -80,6 +80,9 @@ Apps list + Personal apps list + Work apps list + Home @@ -169,16 +172,8 @@ Home settings Disabled by your admin - - Overview - - Allow Home screen rotation - - When phone is rotated - - Current Display setting doesn\'t permit rotation Notification dots @@ -191,6 +186,8 @@ To show Notification Dots, turn on app notifications for %1$s Change settings + + Show notification dots Add icon to Home screen @@ -282,15 +279,6 @@ Move to Home screen - - Move screen to left - - - Move screen to right - - - Screen moved - Resize diff --git a/res/values/styles.xml b/res/values/styles.xml index 8cc4743a32..ac6a6b1b53 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -25,7 +25,6 @@ true true #FF757575 - @layout/search_container_all_apps