Revert "Merge branch 'ub-launcher3-master' into pi-dev"

Original CL loses the commit history. I believe this is due to doing the merge on master and cherry picking to pi-dev. Tested locally that reverting this results in no conflicts when doing the merge properly on pi-dev.

This reverts commit 3f7df53dda.

Bug: 74794600
Test: manual test
Change-Id: I58f3bb1bd5ce789be380bac9716efd2627a90f92
This commit is contained in:
Jonathan Miranda
2018-03-27 00:10:24 +00:00
committed by Jon
parent 3f7df53dda
commit 6cf6dd8bce
273 changed files with 5529 additions and 4244 deletions
+3 -5
View File
@@ -87,11 +87,9 @@
android:process=":wallpaper_chooser" android:process=":wallpaper_chooser"
android:permission="android.permission.BIND_JOB_SERVICE" /> android:permission="android.permission.BIND_JOB_SERVICE" />
<service <service android:name="com.android.launcher3.notification.NotificationListener"
android:name="com.android.launcher3.notification.NotificationListener" android:enabled="@bool/notification_badging_enabled"
android:label="@string/icon_badging_service_title" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
android:enabled="@bool/notification_badging_enabled"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter> <intent-filter>
<action android:name="android.service.notification.NotificationListenerService" /> <action android:name="android.service.notification.NotificationListenerService" />
</intent-filter> </intent-filter>
+1 -1
View File
@@ -71,7 +71,7 @@
android:clearTaskOnLaunch="true" android:clearTaskOnLaunch="true"
android:stateNotNeeded="true" android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan" android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified" android:screenOrientation="nosensor"
android:configChanges="keyboard|keyboardHidden|navigation" android:configChanges="keyboard|keyboardHidden|navigation"
android:resizeableActivity="true" android:resizeableActivity="true"
android:resumeWhilePausing="true" android:resumeWhilePausing="true"
-5
View File
@@ -102,11 +102,6 @@
public <init>(...); public <init>(...);
} }
# InstantAppResolver
-keep class com.android.quickstep.InstantAppResolverImpl {
public <init>(...);
}
-keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** { -keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** {
*; *;
} }
+2 -7
View File
@@ -36,13 +36,8 @@
android:restoreAnyVersion="true" android:restoreAnyVersion="true"
android:supportsRtl="true" > android:supportsRtl="true" >
<service <service android:name="com.android.quickstep.TouchInteractionService"
android:name="com.android.quickstep.TouchInteractionService" android:exported="true" />
android:permission="android.permission.STATUS_BAR_SERVICE" >
<intent-filter>
<action android:name="android.intent.action.QUICKSTEP_SERVICE" />
</intent-filter>
</service>
<!-- STOPSHIP: Change exported to false once all the integration is complete. <!-- STOPSHIP: Change exported to false once all the integration is complete.
It is set to true so that the activity can be started from command line --> It is set to true so that the activity can be started from command line -->
Binary file not shown.
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<com.android.launcher3.views.OptionsPopupView <com.android.launcher3.uioverrides.OptionsPopupView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto" xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -94,4 +94,4 @@
</FrameLayout> </FrameLayout>
</com.android.launcher3.views.OptionsPopupView> </com.android.launcher3.uioverrides.OptionsPopupView>
+6 -2
View File
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<com.android.quickstep.views.LauncherRecentsView <com.android.quickstep.RecentsView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@style/HomeScreenElementTheme" android:theme="@style/HomeScreenElementTheme"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -24,4 +24,8 @@
android:alpha="0.0" android:alpha="0.0"
android:visibility="invisible" > android:visibility="invisible" >
</com.android.quickstep.views.LauncherRecentsView> <com.android.launcher3.uioverrides.WorkspaceCard
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.android.quickstep.RecentsView>
+3 -3
View File
@@ -13,12 +13,12 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<com.android.quickstep.views.TaskView xmlns:android="http://schemas.android.com/apk/res/android" <com.android.quickstep.TaskView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:elevation="4dp"> android:elevation="4dp">
<com.android.quickstep.views.TaskThumbnailView <com.android.quickstep.TaskThumbnailView
android:id="@+id/snapshot" android:id="@+id/snapshot"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -29,4 +29,4 @@
android:layout_width="@dimen/task_thumbnail_icon_size" android:layout_width="@dimen/task_thumbnail_icon_size"
android:layout_height="@dimen/task_thumbnail_icon_size" android:layout_height="@dimen/task_thumbnail_icon_size"
android:layout_gravity="top|center_horizontal" /> android:layout_gravity="top|center_horizontal" />
</com.android.quickstep.views.TaskView> </com.android.quickstep.TaskView>
+2 -2
View File
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<com.android.quickstep.views.TaskMenuView <com.android.quickstep.TaskMenuView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/bg_popup_item_width" android:layout_width="@dimen/bg_popup_item_width"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -33,4 +33,4 @@
android:paddingTop="18dp" android:paddingTop="18dp"
android:drawablePadding="8dp" android:drawablePadding="8dp"
android:gravity="center_horizontal"/> android:gravity="center_horizontal"/>
</com.android.quickstep.views.TaskMenuView> </com.android.quickstep.TaskMenuView>
+7 -4
View File
@@ -16,21 +16,24 @@
<resources> <resources>
<dimen name="options_menu_icon_size">24dp</dimen>
<dimen name="task_thumbnail_top_margin">24dp</dimen> <dimen name="task_thumbnail_top_margin">24dp</dimen>
<dimen name="task_thumbnail_icon_size">48dp</dimen> <dimen name="task_thumbnail_icon_size">48dp</dimen>
<dimen name="task_menu_background_radius">12dp</dimen> <dimen name="task_menu_background_radius">12dp</dimen>
<dimen name="task_corner_radius">2dp</dimen> <dimen name="task_corner_radius">2dp</dimen>
<dimen name="task_fade_length">20dp</dimen> <dimen name="task_fade_length">20dp</dimen>
<dimen name="recents_page_spacing">10dp</dimen> <dimen name="recents_page_spacing">10dp</dimen>
<dimen name="recents_page_fade_length">100dp</dimen>
<!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
loading full resolution screenshots. -->
<dimen name="recents_fast_fling_velocity">600dp</dimen>
<dimen name="quickstep_fling_threshold_velocity">500dp</dimen> <dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
<dimen name="quickstep_fling_min_velocity">250dp</dimen> <dimen name="quickstep_fling_min_velocity">250dp</dimen>
<dimen name="workspace_overview_offset_x">-24dp</dimen>
<!-- TODO: This can be calculated using other resource values -->
<dimen name="all_apps_search_box_full_height">90dp</dimen>
<!-- Launcher app transition --> <!-- Launcher app transition -->
<dimen name="content_trans_y">25dp</dimen> <dimen name="content_trans_y">25dp</dimen>
<dimen name="workspace_trans_y">80dp</dimen> <dimen name="workspace_trans_y">80dp</dimen>
-2
View File
@@ -16,7 +16,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_transition_manager_class" translatable="false">com.android.launcher3.LauncherAppTransitionManagerImpl</string> <string name="app_transition_manager_class" translatable="false">com.android.launcher3.LauncherAppTransitionManagerImpl</string>
<string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
</resources> </resources>
@@ -16,8 +16,7 @@
package com.android.launcher3; package com.android.launcher3;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; 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.getNextFrameNumber;
import static com.android.systemui.shared.recents.utilities.Utilities.getSurface; import static com.android.systemui.shared.recents.utilities.Utilities.getSurface;
@@ -32,13 +31,11 @@ import android.animation.ObjectAnimator;
import android.animation.ValueAnimator; import android.animation.ValueAnimator;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.ActivityOptions; import android.app.ActivityOptions;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
@@ -50,18 +47,14 @@ import android.view.animation.Interpolator;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.InsettableFrameLayout.LayoutParams; import com.android.launcher3.InsettableFrameLayout.LayoutParams;
import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.graphics.DrawableFactory; 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;
import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds;
import com.android.quickstep.views.RecentsView; import com.android.quickstep.RecentsView;
import com.android.systemui.shared.recents.model.Task; import com.android.quickstep.TaskView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityCompat; import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@@ -81,16 +74,12 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
private static final String TAG = "LauncherTransition"; private static final String TAG = "LauncherTransition";
private static final int REFRESH_RATE_MS = 16; 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 = private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
"android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"; "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 RECENTS_LAUNCH_DURATION = 336;
private static final int LAUNCHER_RESUME_START_DELAY = 100; private static final int LAUNCHER_RESUME_START_DELAY = 150;
private static final int CLOSING_TRANSITION_DURATION_MS = 350; 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. // Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down.
@@ -162,7 +151,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
@Override @Override
public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) { public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
if (hasControlRemoteAppTransitionPermission()) { if (hasControlRemoteAppTransitionPermission()) {
TaskView taskView = findTaskViewToLaunch(launcher, v);
try { try {
RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) { RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) {
@Override @Override
@@ -172,8 +160,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
// processed before the next frame. // processed before the next frame.
postAtFrontOfQueueAsynchronously(v.getHandler(), () -> { postAtFrontOfQueueAsynchronously(v.getHandler(), () -> {
final boolean removeTrackingView; final boolean removeTrackingView;
LauncherTransitionAnimator animator = composeRecentsLaunchAnimator( LauncherTransitionAnimator animator =
taskView == null ? v : taskView, targets); composeRecentsLaunchAnimator(v, targets);
if (animator != null) { if (animator != null) {
// We are animating the task view directly, do not remove it after // We are animating the task view directly, do not remove it after
removeTrackingView = false; removeTrackingView = false;
@@ -213,10 +201,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
} }
}; };
int duration = taskView != null ? RECENTS_LAUNCH_DURATION : APP_LAUNCH_DURATION; return ActivityOptionsCompat.makeRemoteAnimation(
int statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION; new RemoteAnimationAdapterCompat(runner, 500, 380));
return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
runner, duration, statusBarTransitionDelay));
} catch (NoClassDefFoundError e) { } catch (NoClassDefFoundError e) {
// Gracefully fall back to default launch options if the user's platform doesn't // Gracefully fall back to default launch options if the user's platform doesn't
// have the latest changes. // have the latest changes.
@@ -225,66 +211,20 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
return getDefaultActivityLaunchOptions(launcher, v); 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. * Composes the animations for a launch from the recents list if possible.
*/ */
private LauncherTransitionAnimator composeRecentsLaunchAnimator(View v, private LauncherTransitionAnimator composeRecentsLaunchAnimator(View v,
RemoteAnimationTargetCompat[] targets) { 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 // Ensure recents is actually visible
if (!mLauncher.getStateManager().getState().overviewUi) { if (!mLauncher.isInState(LauncherState.OVERVIEW)) {
return null; return null;
} }
// Resolve the opening task id // Resolve the opening task id
int openingTaskId = -1; int openingTaskId = -1;
for (RemoteAnimationTargetCompat target : targets) { for (RemoteAnimationTargetCompat target : targets) {
if (target.mode == MODE_OPENING) { if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) {
openingTaskId = target.taskId; openingTaskId = target.taskId;
break; break;
} }
@@ -297,40 +237,15 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
// If the opening task id is not currently visible in overview, then fall back to normal app // If the opening task id is not currently visible in overview, then fall back to normal app
// icon launch animation // icon launch animation
RecentsView recentsView = mLauncher.getOverviewPanel();
TaskView taskView = recentsView.getTaskView(openingTaskId); TaskView taskView = recentsView.getTaskView(openingTaskId);
if (taskView == null || !recentsView.isTaskViewVisible(taskView)) { if (taskView == null || !recentsView.isTaskViewVisible(taskView)) {
return null; return null;
} }
// Found a visible recents task that matches the opening app, lets launch the app from there // Found a visible recents task that matches the opening app, lets launch the app from there
Animator launcherAnim; return new LauncherTransitionAnimator(getRecentsLauncherAnimator(recentsView, taskView),
AnimatorListenerAdapter windowAnimEndListener; getRecentsWindowAnimator(taskView, targets));
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);
} }
/** /**
@@ -345,16 +260,15 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
int launchedTaskIndex = recentsView.indexOfChild(v); int launchedTaskIndex = recentsView.indexOfChild(v);
int centerTaskIndex = recentsView.getCurrentPage(); int centerTaskIndex = recentsView.getCurrentPage();
boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex; boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex;
boolean isRtl = recentsView.isRtl();
if (launchingCenterTask) { if (launchingCenterTask) {
if (launchedTaskIndex - 1 >= 0) { if (launchedTaskIndex - 1 >= recentsView.getFirstTaskIndex()) {
TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1); TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1);
ObjectAnimator adjacentTask1ScaleAndTranslate = ObjectAnimator adjacentTask1ScaleAndTranslate =
LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1, LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1,
new PropertyListBuilder() new PropertyListBuilder()
.scale(adjacentPage1.getScaleX() * mRecentsScale) .scale(adjacentPage1.getScaleX() * mRecentsScale)
.translationY(mRecentsTransY) .translationY(mRecentsTransY)
.translationX(isRtl ? mRecentsTransX : -mRecentsTransX) .translationX(mIsRtl ? mRecentsTransX : -mRecentsTransX)
.build()); .build());
launcherAnimator.play(adjacentTask1ScaleAndTranslate); launcherAnimator.play(adjacentTask1ScaleAndTranslate);
} }
@@ -365,11 +279,11 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
new PropertyListBuilder() new PropertyListBuilder()
.scale(adjacentTask2.getScaleX() * mRecentsScale) .scale(adjacentTask2.getScaleX() * mRecentsScale)
.translationY(mRecentsTransY) .translationY(mRecentsTransY)
.translationX(isRtl ? -mRecentsTransX : mRecentsTransX) .translationX(mIsRtl ? -mRecentsTransX : mRecentsTransX)
.build()); .build());
launcherAnimator.play(adjacentTask2ScaleAndTranslate); launcherAnimator.play(adjacentTask2ScaleAndTranslate);
} }
} else { } else if (centerTaskIndex >= recentsView.getFirstTaskIndex()) {
// We are launching an adjacent task, so parallax the center and other adjacent task. // We are launching an adjacent task, so parallax the center and other adjacent task.
TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex); TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex);
float translationX = Math.abs(v.getTranslationX()); float translationX = Math.abs(v.getTranslationX());
@@ -377,11 +291,11 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
LauncherAnimUtils.ofPropertyValuesHolder(centerTask, LauncherAnimUtils.ofPropertyValuesHolder(centerTask,
new PropertyListBuilder() new PropertyListBuilder()
.scale(v.getScaleX()) .scale(v.getScaleX())
.translationX(isRtl ? -translationX : translationX) .translationX(mIsRtl ? -translationX : translationX)
.build()); .build());
launcherAnimator.play(centerTaskParallaxToRight); launcherAnimator.play(centerTaskParallaxToRight);
int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex); int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex);
if (otherAdjacentTaskIndex >= 0 if (otherAdjacentTaskIndex >= recentsView.getFirstTaskIndex()
&& otherAdjacentTaskIndex < recentsView.getPageCount()) { && otherAdjacentTaskIndex < recentsView.getPageCount()) {
TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt( TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt(
otherAdjacentTaskIndex); otherAdjacentTaskIndex);
@@ -389,7 +303,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask, LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask,
new PropertyListBuilder() new PropertyListBuilder()
.translationX(otherAdjacentTask.getTranslationX() .translationX(otherAdjacentTask.getTranslationX()
+ (isRtl ? -translationX : translationX)) + (mIsRtl ? -translationX : translationX))
.build()); .build());
launcherAnimator.play(otherAdjacentTaskParallaxToRight); launcherAnimator.play(otherAdjacentTaskParallaxToRight);
} }
@@ -400,7 +314,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
launcherAnimator.play(allAppsSlideOut); launcherAnimator.play(allAppsSlideOut);
Workspace workspace = mLauncher.getWorkspace(); Workspace workspace = mLauncher.getWorkspace();
float[] workspaceScaleAndTranslation = NORMAL float[] workspaceScaleAndTranslation = LauncherState.NORMAL
.getWorkspaceScaleAndTranslation(mLauncher); .getWorkspaceScaleAndTranslation(mLauncher);
Animator recenterWorkspace = LauncherAnimUtils.ofPropertyValuesHolder( Animator recenterWorkspace = LauncherAnimUtils.ofPropertyValuesHolder(
workspace, new PropertyListBuilder() workspace, new PropertyListBuilder()
@@ -410,6 +324,9 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
launcherAnimator.play(recenterWorkspace); launcherAnimator.play(recenterWorkspace);
CellLayout currentWorkspacePage = (CellLayout) workspace.getPageAt( CellLayout currentWorkspacePage = (CellLayout) workspace.getPageAt(
workspace.getCurrentPage()); workspace.getCurrentPage());
Animator hideWorkspaceScrim = ObjectAnimator.ofInt(
currentWorkspacePage.getScrimBackground(), DRAWABLE_ALPHA, 0);
launcherAnimator.play(hideWorkspaceScrim);
launcherAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); launcherAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
launcherAnimator.setDuration(RECENTS_LAUNCH_DURATION); launcherAnimator.setDuration(RECENTS_LAUNCH_DURATION);
@@ -420,7 +337,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
* @return Animator that controls the window of the opening targets for the recents launch * @return Animator that controls the window of the opening targets for the recents launch
* animation. * animation.
*/ */
private ValueAnimator getRecentsWindowAnimator(TaskView v, MutableBoolean skipLauncherChanges, private ValueAnimator getRecentsWindowAnimator(TaskView v,
RemoteAnimationTargetCompat[] targets) { RemoteAnimationTargetCompat[] targets) {
Rect taskViewBounds = new Rect(); Rect taskViewBounds = new Rect();
mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds); mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds);
@@ -456,15 +373,13 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
final float percent = animation.getAnimatedFraction(); final float percent = animation.getAnimatedFraction();
TaskWindowBounds tw = recentsInterpolator.interpolate(percent); TaskWindowBounds tw = recentsInterpolator.interpolate(percent);
if (!skipLauncherChanges.value) { v.setScaleX(tw.taskScale);
v.setScaleX(tw.taskScale); v.setScaleY(tw.taskScale);
v.setScaleY(tw.taskScale); v.setTranslationX(tw.taskX);
v.setTranslationX(tw.taskX); v.setTranslationY(tw.taskY);
v.setTranslationY(tw.taskY); // Defer fading out the view until after the app window gets faded in
// Defer fading out the view until after the app window gets faded in v.setAlpha(getValue(1f, 0f, 75, 75,
v.setAlpha(getValue(1f, 0f, 75, 75, appAnimator.getDuration() * percent, Interpolators.LINEAR));
appAnimator.getDuration() * percent, Interpolators.LINEAR));
}
matrix.setScale(tw.winScale, tw.winScale); matrix.setScale(tw.winScale, tw.winScale);
matrix.postTranslate(tw.winX, tw.winY); matrix.postTranslate(tw.winX, tw.winY);
@@ -486,10 +401,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
matrix.postTranslate(target.position.x, target.position.y); matrix.postTranslate(target.position.x, target.position.y);
t.setMatrix(target.leash, matrix); t.setMatrix(target.leash, matrix);
t.setWindowCrop(target.leash, crop); t.setWindowCrop(target.leash, crop);
t.deferTransactionUntil(target.leash, surface, getNextFrameNumber(surface));
if (!skipLauncherChanges.value) {
t.deferTransactionUntil(target.leash, surface, frameNumber);
}
} }
if (isFirstFrame) { if (isFirstFrame) {
t.show(target.leash); t.show(target.leash);
@@ -501,6 +413,13 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
isFirstFrame = false; 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; return appAnimator;
} }
@@ -578,40 +497,26 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
* @return Animator that controls the icon used to launch the target. * @return Animator that controls the icon used to launch the target.
*/ */
private AnimatorSet getIconAnimator(View v) { private AnimatorSet getIconAnimator(View v) {
final boolean isBubbleTextView = v instanceof BubbleTextView; boolean isBubbleTextView = v instanceof BubbleTextView;
mFloatingView = new View(mLauncher); mFloatingView = new View(mLauncher);
if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) { if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) {
// Create a copy of the app icon // Create a copy of the app icon
mFloatingView.setBackground( ItemInfoWithIcon info = (ItemInfoWithIcon) v.getTag();
DrawableFactory.get(mLauncher).newIcon((ItemInfoWithIcon) v.getTag())); FastBitmapDrawable d = DrawableFactory.get(mLauncher).newIcon(info);
d.setIsDisabled(info.isDisabled());
mFloatingView.setBackground(d);
} }
// Position the floating view exactly on top of the original // Position the floating view exactly on top of the original
Rect rect = new Rect(); Rect rect = new Rect();
final boolean isDeepShortcutTextView = v instanceof DeepShortcutTextView mDragLayer.getDescendantRectRelativeToSelf(v, rect);
&& v.getParent() != null && v.getParent() instanceof DeepShortcutView; int viewLocationStart = mIsRtl
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 ? mDeviceProfile.widthPx - rect.right
: rect.left; : rect.left;
final int viewLocationTop = rect.top; int viewLocationTop = rect.top;
float startScale = 1f; if (isBubbleTextView) {
if (isBubbleTextView && !isDeepShortcutTextView) { ((BubbleTextView) v).getIconBounds(rect);
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()); LayoutParams lp = new LayoutParams(rect.width(), rect.height());
lp.ignoreInsets = true; lp.ignoreInsets = true;
@@ -639,8 +544,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
// Adjust the duration to change the "curve" of the app icon to the center. // Adjust the duration to change the "curve" of the app icon to the center.
boolean isBelowCenterY = lp.topMargin < centerY; boolean isBelowCenterY = lp.topMargin < centerY;
x.setDuration(isBelowCenterY ? APP_LAUNCH_DURATION : APP_LAUNCH_CURVED_DURATION); x.setDuration(isBelowCenterY ? 500 : 233);
y.setDuration(isBelowCenterY ? APP_LAUNCH_CURVED_DURATION : APP_LAUNCH_DURATION); y.setDuration(isBelowCenterY ? 233 : 500);
x.setInterpolator(Interpolators.AGGRESSIVE_EASE); x.setInterpolator(Interpolators.AGGRESSIVE_EASE);
y.setInterpolator(Interpolators.AGGRESSIVE_EASE); y.setInterpolator(Interpolators.AGGRESSIVE_EASE);
appIconAnimatorSet.play(x); appIconAnimatorSet.play(x);
@@ -651,10 +556,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
float maxScaleX = mDeviceProfile.widthPx / (float) rect.width(); float maxScaleX = mDeviceProfile.widthPx / (float) rect.width();
float maxScaleY = mDeviceProfile.heightPx / (float) rect.height(); float maxScaleY = mDeviceProfile.heightPx / (float) rect.height();
float scale = Math.max(maxScaleX, maxScaleY); float scale = Math.max(maxScaleX, maxScaleY);
ObjectAnimator scaleAnim = ObjectAnimator ObjectAnimator sX = ObjectAnimator.ofFloat(mFloatingView, View.SCALE_X, 1f, scale);
.ofFloat(mFloatingView, SCALE_PROPERTY, startScale, scale); ObjectAnimator sY = ObjectAnimator.ofFloat(mFloatingView, View.SCALE_Y, 1f, scale);
scaleAnim.setDuration(APP_LAUNCH_DURATION).setInterpolator(Interpolators.EXAGGERATED_EASE); sX.setDuration(500);
appIconAnimatorSet.play(scaleAnim); sY.setDuration(500);
sX.setInterpolator(Interpolators.EXAGGERATED_EASE);
sY.setInterpolator(Interpolators.EXAGGERATED_EASE);
appIconAnimatorSet.play(sX);
appIconAnimatorSet.play(sY);
// Fade out the app icon. // Fade out the app icon.
ObjectAnimator alpha = ObjectAnimator.ofFloat(mFloatingView, View.ALPHA, 1f, 0f); ObjectAnimator alpha = ObjectAnimator.ofFloat(mFloatingView, View.ALPHA, 1f, 0f);
@@ -671,13 +580,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
*/ */
private ValueAnimator getWindowAnimators(View v, RemoteAnimationTargetCompat[] targets) { private ValueAnimator getWindowAnimators(View v, RemoteAnimationTargetCompat[] targets) {
Rect bounds = new Rect(); Rect bounds = new Rect();
boolean isDeepShortcutTextView = v instanceof DeepShortcutTextView if (v instanceof BubbleTextView) {
&& 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); ((BubbleTextView) v).getIconBounds(bounds);
} else { } else {
mDragLayer.getDescendantRectRelativeToSelf(v, bounds); mDragLayer.getDescendantRectRelativeToSelf(v, bounds);
@@ -688,7 +591,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
Matrix matrix = new Matrix(); Matrix matrix = new Matrix();
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
appAnimator.setDuration(APP_LAUNCH_DURATION); appAnimator.setDuration(500);
appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
boolean isFirstFrame = true; boolean isFirstFrame = true;
@@ -810,7 +713,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
postAtFrontOfQueueAsynchronously(handler, () -> { postAtFrontOfQueueAsynchronously(handler, () -> {
if ((Utilities.getPrefs(mLauncher) if ((Utilities.getPrefs(mLauncher)
.getBoolean("pref_use_screenshot_for_swipe_up", false) .getBoolean("pref_use_screenshot_for_swipe_up", false)
&& mLauncher.getStateManager().getState().overviewUi) && mLauncher.isInState(LauncherState.OVERVIEW))
|| !launcherIsATargetWithMode(targets, MODE_OPENING)) { || !launcherIsATargetWithMode(targets, MODE_OPENING)) {
// We use a separate transition for Overview mode. And we can skip the // 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. // animation in cases where Launcher is not in the set of opening targets.
@@ -847,7 +750,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
Matrix matrix = new Matrix(); Matrix matrix = new Matrix();
float height = mLauncher.getDeviceProfile().heightPx; float height = mLauncher.getDeviceProfile().heightPx;
float width = mLauncher.getDeviceProfile().widthPx; float width = mLauncher.getDeviceProfile().widthPx;
float endX = (mLauncher.<RecentsView>getOverviewPanel().isRtl() ? -width : width) * 1.16f; float endX = (Utilities.isRtl(mLauncher.getResources()) ? -width : width) * 1.16f;
ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1); ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
closingAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS); closingAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
@@ -27,20 +27,11 @@ import android.animation.AnimatorSet;
*/ */
public class LauncherTransitionAnimator { public class LauncherTransitionAnimator {
private final MutableBoolean mLauncherAnimCancelState;
private AnimatorSet mAnimatorSet; private AnimatorSet mAnimatorSet;
private Animator mLauncherAnimator; private Animator mLauncherAnimator;
private Animator mWindowAnimator; private Animator mWindowAnimator;
LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator) { LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator) {
this(launcherAnimator, windowAnimator, new MutableBoolean(false));
}
LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator,
MutableBoolean launcherAnimCancelState) {
mLauncherAnimCancelState = launcherAnimCancelState;
if (launcherAnimator != null) { if (launcherAnimator != null) {
mLauncherAnimator = launcherAnimator; mLauncherAnimator = launcherAnimator;
} }
@@ -59,7 +50,6 @@ public class LauncherTransitionAnimator {
public void cancel() { public void cancel() {
mAnimatorSet.cancel(); mAnimatorSet.cancel();
mLauncherAnimCancelState.value = true;
} }
public boolean isRunning() { public boolean isRunning() {
@@ -68,7 +58,6 @@ public class LauncherTransitionAnimator {
public void finishLauncherAnimation() { public void finishLauncherAnimation() {
if (mLauncherAnimator != null) { if (mLauncherAnimator != null) {
mLauncherAnimCancelState.value = true;
mLauncherAnimator.end(); mLauncherAnimator.end();
} }
} }
@@ -1,25 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3;
public class MutableBoolean {
public boolean value;
public MutableBoolean(boolean value) {
this.value = value;
}
}
@@ -25,7 +25,6 @@ import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherState;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/** /**
@@ -33,8 +32,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
*/ */
public class AllAppsState extends LauncherState { 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) { private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) {
@Override @Override
@@ -59,8 +57,7 @@ public class AllAppsState extends LauncherState {
@Override @Override
public String getDescription(Launcher launcher) { public String getDescription(Launcher launcher) {
AllAppsContainerView appsView = launcher.getAppsView(); return launcher.getString(R.string.all_apps_button_label);
return appsView.getDescription();
} }
@Override @Override
@@ -31,12 +31,13 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; 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.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.VerticalSwipeController; import com.android.launcher3.util.VerticalSwipeController;
import com.android.quickstep.views.RecentsView; import com.android.quickstep.RecentsView;
class EventLogTags { class EventLogTags {
private EventLogTags() { private EventLogTags() {
@@ -141,6 +142,11 @@ public class EdgeSwipeController extends VerticalSwipeController implements
} }
} }
@Override
protected void initSprings() {
mSpringHandlers = new SpringAnimationHandler[0];
}
@Override @Override
protected float getShiftRange() { protected float getShiftRange() {
return getShiftRange(mLauncher); return getShiftRange(mLauncher);
@@ -1,50 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.uioverrides;
import 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);
}
}
@@ -13,14 +13,29 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.android.launcher3.uioverrides; package com.android.launcher3.uioverrides;
/** import android.view.MotionEvent;
* A dummy overview state
*/
public class FastOverviewState extends OverviewState {
public FastOverviewState(int id) { import com.android.launcher3.util.TouchController;
super(id); import com.android.quickstep.TouchInteractionService;
/**
* Consumes touches when quick scrub is enabled.
*/
public class IgnoreTouchesInQuickScrub implements TouchController {
public IgnoreTouchesInQuickScrub() {
}
@Override
public boolean onControllerTouchEvent(MotionEvent ev) {
return true;
}
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
return TouchInteractionService.isQuickScrubEnabled();
} }
} }
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.android.launcher3.views; package com.android.launcher3.uioverrides;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
@@ -29,7 +29,6 @@ import android.util.AttributeSet;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewOutlineProvider; import android.view.ViewOutlineProvider;
import android.widget.Toast; import android.widget.Toast;
@@ -43,22 +42,19 @@ import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.RevealOutlineAnimation; import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.graphics.ColorScrim; import com.android.launcher3.graphics.GradientView;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.widget.WidgetsFullSheet; import com.android.launcher3.widget.WidgetsFullSheet;
/** /**
* Popup shown on long pressing an empty space in launcher * Popup shown on long pressing an empty space in launcher
*/ */
public class OptionsPopupView extends AbstractFloatingView public class OptionsPopupView extends AbstractFloatingView implements OnClickListener {
implements OnClickListener, OnLongClickListener {
private final float mOutlineRadius; private final float mOutlineRadius;
private final Launcher mLauncher; private final Launcher mLauncher;
private final PointF mTouchPoint = new PointF(); private final PointF mTouchPoint = new PointF();
private final ColorScrim mScrim; private final GradientView mGradientView;
protected Animator mOpenCloseAnimator; protected Animator mOpenCloseAnimator;
@@ -79,55 +75,39 @@ public class OptionsPopupView extends AbstractFloatingView
}); });
mLauncher = Launcher.getLauncher(context); mLauncher = Launcher.getLauncher(context);
mScrim = ColorScrim.createExtractedColorScrim(this);
mGradientView = (GradientView) mLauncher.getLayoutInflater().inflate(
R.layout.widgets_bottom_sheet_scrim, mLauncher.getDragLayer(), false);
mGradientView.setProgress(1, false);
mGradientView.setAlpha(0);
} }
@Override @Override
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
attachListeners(findViewById(R.id.wallpaper_button)); findViewById(R.id.wallpaper_button).setOnClickListener(this);
attachListeners(findViewById(R.id.widget_button)); findViewById(R.id.widget_button).setOnClickListener(this);
attachListeners(findViewById(R.id.settings_button)); findViewById(R.id.settings_button).setOnClickListener(this);
}
private void attachListeners(View view) {
view.setOnClickListener(this);
view.setOnLongClickListener(this);
} }
@Override @Override
public void onClick(View view) { public void onClick(View view) {
handleViewClick(view, Action.Touch.TAP);
}
@Override
public boolean onLongClick(View view) {
return handleViewClick(view, Action.Touch.LONGPRESS);
}
private boolean handleViewClick(View view, int action) {
if (view.getId() == R.id.wallpaper_button) { if (view.getId() == R.id.wallpaper_button) {
mLauncher.onClickWallpaperPicker(null); mLauncher.onClickWallpaperPicker(null);
logTap(action, ControlType.WALLPAPER_BUTTON);
close(true); close(true);
return true;
} else if (view.getId() == R.id.widget_button) { } else if (view.getId() == R.id.widget_button) {
logTap(action, ControlType.WIDGETS_BUTTON); if (mLauncher.getPackageManager().isSafeMode()) {
if (onWidgetsClicked(mLauncher)) { Toast.makeText(mLauncher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
} else {
WidgetsFullSheet.show(mLauncher, true /* animated */);
close(true); close(true);
return true;
} }
} else if (view.getId() == R.id.settings_button) { } else if (view.getId() == R.id.settings_button) {
startSettings(mLauncher); mLauncher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
logTap(action, ControlType.SETTINGS_BUTTON); .setPackage(mLauncher.getPackageName())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
close(true); close(true);
return true;
} }
return false;
}
private void logTap(int action, int controlType) {
mLauncher.getUserEventDispatcher().logActionOnControl(action, controlType);
} }
@Override @Override
@@ -169,7 +149,7 @@ public class OptionsPopupView extends AbstractFloatingView
fadeOut.setInterpolator(Interpolators.DEACCEL); fadeOut.setInterpolator(Interpolators.DEACCEL);
closeAnim.play(fadeOut); closeAnim.play(fadeOut);
Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 0); Animator gradientAlpha = ObjectAnimator.ofFloat(mGradientView, ALPHA, 0);
gradientAlpha.setInterpolator(Interpolators.DEACCEL); gradientAlpha.setInterpolator(Interpolators.DEACCEL);
closeAnim.play(gradientAlpha); closeAnim.play(gradientAlpha);
@@ -197,6 +177,7 @@ public class OptionsPopupView extends AbstractFloatingView
} }
mIsOpen = false; mIsOpen = false;
mLauncher.getDragLayer().removeView(this); mLauncher.getDragLayer().removeView(this);
mLauncher.getDragLayer().removeView(mGradientView);
} }
@Override @Override
@@ -232,7 +213,7 @@ public class OptionsPopupView extends AbstractFloatingView
.createRevealAnimator(this, false); .createRevealAnimator(this, false);
openAnim.play(revealAnim); openAnim.play(revealAnim);
Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 1); Animator gradientAlpha = ObjectAnimator.ofFloat(mGradientView, ALPHA, 1);
gradientAlpha.setInterpolator(Interpolators.ACCEL); gradientAlpha.setInterpolator(Interpolators.ACCEL);
openAnim.play(gradientAlpha); openAnim.play(gradientAlpha);
@@ -288,23 +269,8 @@ public class OptionsPopupView extends AbstractFloatingView
lp.y = Utilities.boundToRange((int) (y - height / 2), insets.top + margin, lp.y = Utilities.boundToRange((int) (y - height / 2), insets.top + margin,
maxHeight - insets.bottom - height - margin); maxHeight - insets.bottom - height - margin);
launcher.getDragLayer().addView(view.mGradientView);
launcher.getDragLayer().addView(view); launcher.getDragLayer().addView(view);
view.animateOpen(); view.animateOpen();
} }
public static boolean onWidgetsClicked(Launcher launcher) {
if (launcher.getPackageManager().isSafeMode()) {
Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
return false;
} else {
WidgetsFullSheet.show(launcher, true /* animated */);
return true;
}
}
public static void startSettings(Launcher launcher) {
launcher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
.setPackage(launcher.getPackageName())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
} }
@@ -16,17 +16,20 @@
package com.android.launcher3.uioverrides; package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS; import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2; import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
import android.view.View; import android.view.View;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace; import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.views.RecentsView; import com.android.quickstep.RecentsView;
/** /**
* Definition for overview state * Definition for overview state
@@ -34,26 +37,27 @@ import com.android.quickstep.views.RecentsView;
public class OverviewState extends LauncherState { public class OverviewState extends LauncherState {
private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
| FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI; | FLAG_DISABLE_RESTORE;
public OverviewState(int id) { public OverviewState(int id) {
this(id, OVERVIEW_TRANSITION_MS, STATE_FLAGS); super(id, ContainerType.TASKSWITCHER, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
}
protected OverviewState(int id, int transitionDuration, int stateFlags) {
super(id, ContainerType.TASKSWITCHER, transitionDuration, stateFlags);
} }
@Override @Override
public float[] getWorkspaceScaleAndTranslation(Launcher launcher) { public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
Rect pageRect = new Rect(); Rect pageRect = new Rect();
RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, pageRect); RecentsView.getScaledDownPageRect(launcher.getDeviceProfile(), launcher, pageRect);
RecentsView rv = launcher.getOverviewPanel();
if (launcher.getWorkspace().getNormalChildWidth() <= 0 || pageRect.isEmpty()) { if (launcher.getWorkspace().getNormalChildWidth() <= 0 || pageRect.isEmpty()) {
return super.getWorkspaceScaleAndTranslation(launcher); return super.getWorkspaceScaleAndTranslation(launcher);
} }
return getScaleAndTranslationForPageRect(launcher, pageRect); float overlap = 0;
if (rv.getCurrentPage() >= rv.getFirstTaskIndex()) {
overlap = launcher.getResources().getDimension(R.dimen.workspace_overview_offset_x);
}
return getScaleAndTranslationForPageRect(launcher, overlap, pageRect);
} }
@Override @Override
@@ -69,8 +73,8 @@ public class OverviewState extends LauncherState {
} }
@Override @Override
public void onStateTransitionEnd(Launcher launcher) { public float getVerticalProgress(Launcher launcher) {
launcher.getRotationHelper().setCurrentStateRequest(REQUEST_ROTATE); return getVerticalProgress(launcher.getDeviceProfile(), launcher);
} }
@Override @Override
@@ -79,25 +83,51 @@ public class OverviewState extends LauncherState {
} }
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) { public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) { final int centerPage = launcher.getWorkspace().getNextPage();
return new PageAlphaProvider(ACCEL_2) {
@Override @Override
public float getPageAlpha(int pageIndex) { public float getPageAlpha(int pageIndex) {
return 0; return pageIndex != centerPage ? 0 : 1f;
} }
}; };
} }
public static float[] getScaleAndTranslationForPageRect(Launcher launcher, Rect pageRect) { public static float[] getScaleAndTranslationForPageRect(Launcher launcher, float offsetX,
Rect pageRect) {
Workspace ws = launcher.getWorkspace(); Workspace ws = launcher.getWorkspace();
float childWidth = ws.getNormalChildWidth(); float childWidth = ws.getNormalChildWidth();
float childHeight = ws.getNormalChildHeight();
float scale = pageRect.width() / childWidth; float scale = pageRect.height() / childHeight;
Rect insets = launcher.getDragLayer().getInsets(); Rect insets = launcher.getDragLayer().getInsets();
float halfHeight = ws.getExpectedHeight() / 2; float halfHeight = ws.getExpectedHeight() / 2;
float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top); float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
float translationY = pageRect.top - childTop; float translationY = pageRect.top - childTop;
return new float[] {scale, 0, translationY}; // 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);
} }
} }
@@ -15,14 +15,10 @@
*/ */
package com.android.launcher3.uioverrides; 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.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet; import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator; import android.animation.ValueAnimator;
import android.util.Log; import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -36,13 +32,19 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto; 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.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; 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.launcher3.util.TouchController;
import com.android.quickstep.PendingAnimation; import com.android.quickstep.RecentsView;
import com.android.quickstep.views.RecentsView; import com.android.quickstep.TaskView;
import com.android.quickstep.views.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;
/** /**
* Touch controller for swipe interaction in Overview state * Touch controller for swipe interaction in Overview state
@@ -63,7 +65,6 @@ public class OverviewSwipeController extends AnimatorListenerAdapter
private final RecentsView mRecentsView; private final RecentsView mRecentsView;
private final int[] mTempCords = new int[2]; private final int[] mTempCords = new int[2];
private PendingAnimation mPendingAnimation;
private AnimatorPlaybackController mCurrentAnimation; private AnimatorPlaybackController mCurrentAnimation;
private boolean mCurrentAnimationIsGoingUp; private boolean mCurrentAnimationIsGoingUp;
@@ -131,21 +132,28 @@ public class OverviewSwipeController extends AnimatorListenerAdapter
mTaskBeingDragged = null; mTaskBeingDragged = null;
mSwipeDownEnabled = true; mSwipeDownEnabled = true;
View view = mRecentsView.getChildAt(mRecentsView.getCurrentPage()); int currentPage = mRecentsView.getCurrentPage();
if (view instanceof TaskView && mLauncher.getDragLayer().isEventOverView(view, ev)) { if (currentPage == 0) {
// The tile can be dragged down to open the task. // User is on home tile
mTaskBeingDragged = (TaskView) view;
directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH; 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 { } else {
mNoIntercept = true; View view = mRecentsView.getChildAt(currentPage);
mStartingTarget = ContainerType.WORKSPACE; if (mLauncher.getDragLayer().isEventOverView(view, ev) &&
return false; 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;
}
} }
} }
@@ -177,11 +185,6 @@ public class OverviewSwipeController extends AnimatorListenerAdapter
if (mCurrentAnimation != null) { if (mCurrentAnimation != null) {
mCurrentAnimation.setPlayFraction(0); mCurrentAnimation.setPlayFraction(0);
} }
if (mPendingAnimation != null) {
mPendingAnimation.finish(false);
mPendingAnimation = null;
}
mCurrentAnimationIsGoingUp = goingUp; mCurrentAnimationIsGoingUp = goingUp;
float range = mLauncher.getAllAppsController().getShiftRange(); float range = mLauncher.getAllAppsController().getShiftRange();
long maxDuration = (long) (2 * range); long maxDuration = (long) (2 * range);
@@ -198,11 +201,19 @@ public class OverviewSwipeController extends AnimatorListenerAdapter
} }
} else { } else {
if (goingUp) { if (goingUp) {
mPendingAnimation = mRecentsView AnimatorSet anim = new AnimatorSet();
.createTaskDismissAnimation(mTaskBeingDragged, maxDuration); ObjectAnimator translate = ObjectAnimator.ofFloat(
mCurrentAnimation = AnimatorPlaybackController mTaskBeingDragged, View.TRANSLATION_Y, -mTaskBeingDragged.getBottom());
.wrap(mPendingAnimation.anim, maxDuration); translate.setInterpolator(LINEAR);
mEndDisplacement = -mTaskBeingDragged.getHeight(); 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();
} else { } else {
AnimatorSet anim = new AnimatorSet(); AnimatorSet anim = new AnimatorSet();
// TODO: Setup a zoom animation // TODO: Setup a zoom animation
@@ -288,17 +299,15 @@ public class OverviewSwipeController extends AnimatorListenerAdapter
} }
private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) { private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) {
if (mPendingAnimation != null) {
mPendingAnimation.finish(wasSuccess);
mPendingAnimation = null;
}
if (mTaskBeingDragged == null) { if (mTaskBeingDragged == null) {
LauncherState state = wasSuccess ? LauncherState state = wasSuccess ?
(mCurrentAnimationIsGoingUp ? ALL_APPS : NORMAL) : OVERVIEW; (mCurrentAnimationIsGoingUp ? ALL_APPS : NORMAL) : OVERVIEW;
mLauncher.getStateManager().goToState(state, false); mLauncher.getStateManager().goToState(state, false);
} else if (wasSuccess) { } else if (wasSuccess) {
if (!mCurrentAnimationIsGoingUp) { if (mCurrentAnimationIsGoingUp) {
mRecentsView.onTaskDismissed(mTaskBeingDragged);
} else {
mTaskBeingDragged.launchTask(false); mTaskBeingDragged.launchTask(false);
mLauncher.getUserEventDispatcher().logTaskLaunch(logAction, mLauncher.getUserEventDispatcher().logTaskLaunch(logAction,
Direction.DOWN, mTaskBeingDragged.getTask().getTopComponent()); Direction.DOWN, mTaskBeingDragged.getTask().getTopComponent());
@@ -16,7 +16,7 @@
package com.android.launcher3.uioverrides; package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.LauncherState.OVERVIEW;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
@@ -28,71 +28,84 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.PagedView; import com.android.launcher3.PagedView;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.Interpolators;
import com.android.quickstep.AnimatedFloat; import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.views.RecentsView; import com.android.quickstep.RecentsView;
import com.android.quickstep.views.TaskView; import com.android.quickstep.TaskView;
public class RecentsViewStateController implements StateHandler { public class RecentsViewStateController implements StateHandler {
private final Launcher mLauncher; private final Launcher mLauncher;
private final RecentsView mRecentsView; private final RecentsView mRecentsView;
private final WorkspaceCard mWorkspaceCard;
private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::onTransitionProgress); private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::onTransitionProgress);
// The fraction representing the visibility of the RecentsView. This allows delaying the // The fraction representing the visibility of the RecentsView. This allows delaying the
// overall transition while the RecentsView is being shown or hidden. // overall transition while the RecentsView is being shown or hidden.
private final AnimatedFloat mVisibilityMultiplier = new AnimatedFloat(this::onVisibilityProgress); private final AnimatedFloat mVisibilityMultiplier = new AnimatedFloat(this::onVisibilityProgress);
private boolean mIsRecentsSlidingInOrOut; private boolean mIsRecentsScrollingToFirstTask;
public RecentsViewStateController(Launcher launcher) { public RecentsViewStateController(Launcher launcher) {
mLauncher = launcher; mLauncher = launcher;
mRecentsView = launcher.getOverviewPanel(); mRecentsView = launcher.getOverviewPanel();
mRecentsView.setStateController(this);
mWorkspaceCard = (WorkspaceCard) mRecentsView.getChildAt(0);
mWorkspaceCard.setup(launcher);
} }
@Override @Override
public void setState(LauncherState state) { public void setState(LauncherState state) {
setVisibility(state.overviewUi); mWorkspaceCard.setWorkspaceScrollingEnabled(state == OVERVIEW);
setTransitionProgress(state.overviewUi ? 1 : 0); setVisibility(state == OVERVIEW);
if (state.overviewUi) { setTransitionProgress(state == OVERVIEW ? 1 : 0);
mRecentsView.resetTaskVisuals(); if (state == OVERVIEW) {
for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
((TaskView) mRecentsView.getPageAt(i)).resetVisualProperties();
}
mRecentsView.updateCurveProperties();
} }
} }
@Override @Override
public void setStateWithAnimation(final LauncherState toState, public void setStateWithAnimation(final LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config) { AnimatorSetBuilder builder, AnimationConfig config) {
LauncherState fromState = mLauncher.getStateManager().getState(); boolean settingEnabled = Utilities.getPrefs(mLauncher)
mIsRecentsSlidingInOrOut = fromState == NORMAL && toState.overviewUi .getBoolean("pref_scroll_to_first_task", false);
|| fromState.overviewUi && toState == NORMAL; mIsRecentsScrollingToFirstTask = mLauncher.isInState(NORMAL) && toState == OVERVIEW
&& settingEnabled;
// TODO: Instead of animating the workspace translationX, move the contents
mWorkspaceCard.setWorkspaceScrollingEnabled(mIsRecentsScrollingToFirstTask);
// Scroll to the workspace card before changing to the NORMAL state. // Scroll to the workspace card before changing to the NORMAL state.
int currPage = mRecentsView.getCurrentPage(); int currPage = mRecentsView.getCurrentPage();
if (fromState.overviewUi && toState == NORMAL && currPage != 0 && !config.userControlled) { if (toState == NORMAL && currPage != 0 && !config.userControlled) {
int maxSnapDuration = PagedView.SLOW_PAGE_SNAP_ANIMATION_DURATION; int maxSnapDuration = PagedView.SLOW_PAGE_SNAP_ANIMATION_DURATION;
int durationPerPage = maxSnapDuration / 10; int durationPerPage = maxSnapDuration / 10;
int snapDuration = Math.min(maxSnapDuration, durationPerPage * currPage); int snapDuration = Math.min(maxSnapDuration, durationPerPage * currPage);
mRecentsView.snapToPage(0, snapDuration); mRecentsView.snapToPage(0, snapDuration);
// Let the snapping animation play for a bit before we translate off screen. builder.setStartDelay(snapDuration);
builder.setStartDelay(snapDuration / 4);
} }
ObjectAnimator progressAnim = ObjectAnimator progressAnim =
mTransitionProgress.animateToValue(toState.overviewUi ? 1 : 0); mTransitionProgress.animateToValue(toState == OVERVIEW ? 1 : 0);
progressAnim.setDuration(config.duration); progressAnim.setDuration(config.duration);
progressAnim.setInterpolator(Interpolators.LINEAR); progressAnim.setInterpolator(Interpolators.LINEAR);
progressAnim.addListener(new AnimationSuccessListener() { progressAnim.addListener(new AnimationSuccessListener() {
@Override @Override
public void onAnimationSuccess(Animator animator) { public void onAnimationSuccess(Animator animator) {
mWorkspaceCard.setWorkspaceScrollingEnabled(toState == OVERVIEW);
mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen()); mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen());
} }
}); });
builder.play(progressAnim); builder.play(progressAnim);
ObjectAnimator visibilityAnim = animateVisibility(toState.overviewUi); ObjectAnimator visibilityAnim = animateVisibility(toState == OVERVIEW);
visibilityAnim.setDuration(config.duration); visibilityAnim.setDuration(config.duration);
visibilityAnim.setInterpolator(Interpolators.LINEAR); visibilityAnim.setInterpolator(Interpolators.LINEAR);
builder.play(visibilityAnim); builder.play(visibilityAnim);
@@ -131,14 +144,11 @@ public class RecentsViewStateController implements StateHandler {
private void onTransitionProgress() { private void onTransitionProgress() {
applyProgress(); applyProgress();
if (mIsRecentsSlidingInOrOut) { if (mIsRecentsScrollingToFirstTask) {
float interpolatedProgress = ACCEL.getInterpolation(mTransitionProgress.value); int scrollForFirstTask = mRecentsView.getScrollForPage(mRecentsView.getFirstTaskIndex());
// Slide in from the side as we swipe. int scrollForPage0 = mRecentsView.getScrollForPage(0);
int translation = mRecentsView.getWidth(); mRecentsView.setScrollX((int) (mTransitionProgress.value * scrollForFirstTask
if (mRecentsView.isRtl()) { + (1 - mTransitionProgress.value) * scrollForPage0));
translation = -translation;
}
mRecentsView.setTranslationX(translation * (1 - interpolatedProgress));
} }
} }
@@ -148,9 +158,5 @@ public class RecentsViewStateController implements StateHandler {
private void applyProgress() { private void applyProgress() {
mRecentsView.setAlpha(mTransitionProgress.value * mVisibilityMultiplier.value); mRecentsView.setAlpha(mTransitionProgress.value * mVisibilityMultiplier.value);
if (mIsRecentsSlidingInOrOut) {
// While animating into recents, update the visible task data as needed
mRecentsView.loadVisibleTaskData();
}
} }
} }
@@ -19,6 +19,7 @@ import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity; 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 static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
import android.animation.Animator; import android.animation.Animator;
@@ -26,6 +27,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet; import android.animation.AnimatorSet;
import android.animation.ValueAnimator; import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener; import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.support.animation.SpringAnimation;
import android.util.Log; import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -36,9 +38,11 @@ import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
@@ -48,6 +52,8 @@ import com.android.launcher3.util.FloatRange;
import com.android.launcher3.util.TouchController; import com.android.launcher3.util.TouchController;
import com.android.quickstep.TouchInteractionService; import com.android.quickstep.TouchInteractionService;
import java.util.ArrayList;
/** /**
* Handles vertical touch gesture on the DragLayer * Handles vertical touch gesture on the DragLayer
*/ */
@@ -106,6 +112,8 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter
// Ratio of transition process [0, 1] to drag displacement (px) // Ratio of transition process [0, 1] to drag displacement (px)
private float mProgressMultiplier; private float mProgressMultiplier;
private SpringAnimationHandler[] mSpringHandlers;
public TwoStepSwipeController(Launcher l) { public TwoStepSwipeController(Launcher l) {
mLauncher = l; mLauncher = l;
mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL); mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
@@ -148,6 +156,29 @@ 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<SpringAnimationHandler> handlers = new ArrayList<>();
handlers.add(handler);
SpringAnimation searchSpring = appsView.getSearchUiManager().getSpringForFling();
if (searchSpring != null) {
SpringAnimationHandler searchHandler =
new SpringAnimationHandler(Y_DIRECTION, handler.getFactory());
searchHandler.add(searchSpring, true /* setDefaultValues */);
handlers.add(searchHandler);
}
mSpringHandlers = handlers.toArray(new SpringAnimationHandler[handlers.size()]);
}
@Override @Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) { public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) { if (ev.getAction() == MotionEvent.ACTION_DOWN) {
@@ -183,6 +214,10 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter
mDetector.setDetectableScrollConditions( mDetector.setDetectableScrollConditions(
directionsToDetectScroll, ignoreSlopWhenSettling); directionsToDetectScroll, ignoreSlopWhenSettling);
if (mSpringHandlers == null) {
initSprings();
}
} }
if (mNoIntercept) { if (mNoIntercept) {
@@ -195,6 +230,9 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter
@Override @Override
public boolean onControllerTouchEvent(MotionEvent ev) { public boolean onControllerTouchEvent(MotionEvent ev) {
for (SpringAnimationHandler h : mSpringHandlers) {
h.addMovement(ev);
}
return mDetector.onTouchEvent(ev); return mDetector.onTouchEvent(ev);
} }
@@ -245,6 +283,10 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter
mDragPauseDetector.clearDisabledFlags(FLAG_OVERVIEW_DISABLED_FLING); mDragPauseDetector.clearDisabledFlags(FLAG_OVERVIEW_DISABLED_FLING);
updatePauseDetectorRangeFlag(); updatePauseDetectorRangeFlag();
} }
for (SpringAnimationHandler h : mSpringHandlers) {
h.skipToEnd();
}
} }
private float getShiftRange() { private float getShiftRange() {
@@ -287,6 +329,13 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter
targetState = (progress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState; 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; float endProgress;
if (mDragPauseDetector.isTriggered() && targetState == NORMAL) { if (mDragPauseDetector.isTriggered() && targetState == NORMAL) {
@@ -18,29 +18,37 @@ package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.NORMAL;
import android.view.View; import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.view.View.AccessibilityDelegate; import android.view.View.AccessibilityDelegate;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.graphics.BitmapRenderer;
import com.android.launcher3.util.TouchController; import com.android.launcher3.util.TouchController;
import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.RecentsModel; import com.android.quickstep.RecentsView;
import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.recents.view.RecentsTransition;
public class UiFactory { 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) { public static TouchController[] createTouchControllers(Launcher launcher) {
if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) { if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) {
return new TouchController[] { return new TouchController[] {
new IgnoreTouchesInQuickScrub(),
new EdgeSwipeController(launcher), new EdgeSwipeController(launcher),
new TwoStepSwipeController(launcher), new TwoStepSwipeController(launcher),
new OverviewSwipeController(launcher)}; new OverviewSwipeController(launcher)};
} else { } else {
return new TouchController[] { return new TouchController[] {
new IgnoreTouchesInQuickScrub(),
new TwoStepSwipeController(launcher), new TwoStepSwipeController(launcher),
new OverviewSwipeController(launcher)}; new OverviewSwipeController(launcher)};
} }
@@ -56,40 +64,28 @@ public class UiFactory {
new RecentsViewStateController(launcher)}; new RecentsViewStateController(launcher)};
} }
public static void onWorkspaceLongPress(Launcher launcher, PointF touchPoint) {
OptionsPopupView.show(launcher, touchPoint.x, touchPoint.y);
}
public static void onLauncherStateOrFocusChanged(Launcher launcher) { public static void onLauncherStateOrFocusChanged(Launcher launcher) {
boolean shouldBackButtonBeVisible = launcher == null OverviewInteractionState.setBackButtonVisible(launcher, launcher == null
|| !launcher.isInState(NORMAL) || !launcher.isInState(NORMAL) || !launcher.hasWindowFocus());
|| !launcher.hasWindowFocus(); }
if (!shouldBackButtonBeVisible) {
// Show the back button if there is a floating view visible. public static Bitmap createFromRenderer(int width, int height, boolean forceSoftwareRenderer,
DragLayer dragLayer = launcher.getDragLayer(); BitmapRenderer renderer) {
for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) { if (USE_HARDWARE_BITMAP && !forceSoftwareRenderer) {
View child = dragLayer.getChildAt(i); return RecentsTransition.createHardwareBitmap(width, height, renderer::render);
if (child instanceof AbstractFloatingView) { } else {
shouldBackButtonBeVisible = true; Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
break; renderer.render(new Canvas(result));
} return result;
}
} }
OverviewInteractionState.setBackButtonVisible(launcher, shouldBackButtonBeVisible);
} }
public static void resetOverview(Launcher launcher) { public static void resetOverview(Launcher launcher) {
RecentsView recents = launcher.getOverviewPanel(); RecentsView recents = launcher.getOverviewPanel();
recents.reset(); 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);
}
}
} }
@@ -0,0 +1,127 @@
/*
* 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;
}
}
@@ -77,12 +77,6 @@ public class AnimatedFloat {
} }
} }
public void finishAnimation() {
if (mValueAnimator != null && mValueAnimator.isRunning()) {
mValueAnimator.end();
}
}
public ObjectAnimator getCurrentAnimation() { public ObjectAnimator getCurrentAnimation() {
return mValueAnimator; return mValueAnimator;
} }
@@ -23,7 +23,6 @@ import com.android.quickstep.TouchConsumer.InteractionType;
public abstract class BaseSwipeInteractionHandler extends InternalStateHandler { public abstract class BaseSwipeInteractionHandler extends InternalStateHandler {
protected Runnable mGestureEndCallback; protected Runnable mGestureEndCallback;
protected boolean mIsGoingToHome;
public void setGestureEndCallback(Runnable gestureEndCallback) { public void setGestureEndCallback(Runnable gestureEndCallback) {
mGestureEndCallback = gestureEndCallback; mGestureEndCallback = gestureEndCallback;
@@ -1,99 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import android.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);
}
}
@@ -1,57 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.quickstep.views.RecentsView;
public class FallbackRecentsView extends RecentsView<RecentsActivity> implements Insettable {
public FallbackRecentsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOverviewStateEnabled(true);
}
@Override
protected void onAllTasksRemoved() {
mActivity.finish();
}
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
DeviceProfile dp = mActivity.getDeviceProfile();
Rect padding = getPadding(dp, getContext());
verticalCenter(padding, dp);
setPadding(padding.left, padding.top, padding.right, padding.bottom);
}
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;
}
}
@@ -1,77 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import com.android.launcher3.AppInfo;
import com.android.launcher3.util.InstantAppResolver;
import java.util.ArrayList;
import java.util.List;
/**
* Implementation of InstantAppResolver using platform APIs
*/
@SuppressWarnings("unused")
public class InstantAppResolverImpl extends InstantAppResolver {
private static final String TAG = "InstantAppResolverImpl";
public static final String COMPONENT_CLASS_MARKER = "@instantapp";
private final PackageManager mPM;
public InstantAppResolverImpl(Context context)
throws NoSuchMethodException, ClassNotFoundException {
mPM = context.getPackageManager();
}
@Override
public boolean isInstantApp(ApplicationInfo info) {
return info.isInstantApp();
}
@Override
public boolean isInstantApp(AppInfo info) {
ComponentName cn = info.getTargetComponent();
return cn != null && cn.getClassName().equals(COMPONENT_CLASS_MARKER);
}
@Override
public List<ApplicationInfo> getInstantApps() {
try {
List<ApplicationInfo> result = new ArrayList<>();
for (InstantAppInfo iai : mPM.getInstantApps()) {
ApplicationInfo info = iai.getApplicationInfo();
if (info != null) {
result.add(info);
}
}
return result;
} catch (SecurityException se) {
Log.w(TAG, "getInstantApps failed. Launcher may not be the default home app.", se);
} catch (Exception e) {
Log.e(TAG, "Error calling API: getInstantApps", e);
}
return super.getInstantApps();
}
}
@@ -53,8 +53,6 @@ public class MotionEventQueue {
ACTION_VIRTUAL | (4 << ACTION_POINTER_INDEX_SHIFT); ACTION_VIRTUAL | (4 << ACTION_POINTER_INDEX_SHIFT);
private static final int ACTION_RESET = private static final int ACTION_RESET =
ACTION_VIRTUAL | (5 << ACTION_POINTER_INDEX_SHIFT); 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 EventArray mEmptyArray = new EventArray();
private final Object mExecutionLock = new Object(); private final Object mExecutionLock = new Object();
@@ -78,10 +76,10 @@ public class MotionEventQueue {
public MotionEventQueue(Choreographer choreographer, TouchConsumer consumer) { public MotionEventQueue(Choreographer choreographer, TouchConsumer consumer) {
mMainChoreographer = choreographer; mMainChoreographer = choreographer;
mConsumer = consumer; mConsumer = consumer;
mCurrentChoreographer = mMainChoreographer; mCurrentChoreographer = mMainChoreographer;
mCurrentRunnable = mMainFrameCallback; mCurrentRunnable = mMainFrameCallback;
setInterimChoreographerLocked(consumer.getIntrimChoreographer(this));
setInterimChoreographer(consumer.getIntrimChoreographer(this));
} }
public void setInterimChoreographer(Choreographer choreographer) { public void setInterimChoreographer(Choreographer choreographer) {
@@ -158,9 +156,6 @@ public class MotionEventQueue {
case ACTION_RESET: case ACTION_RESET:
mConsumer.reset(); mConsumer.reset();
break; break;
case ACTION_DEFER_INIT:
mConsumer.deferInit();
break;
default: default:
Log.e(TAG, "Invalid virtual event: " + event.getAction()); Log.e(TAG, "Invalid virtual event: " + event.getAction());
} }
@@ -209,14 +204,6 @@ public class MotionEventQueue {
queueVirtualAction(ACTION_RESET, 0); queueVirtualAction(ACTION_RESET, 0);
} }
public void deferInit() {
queueVirtualAction(ACTION_DEFER_INIT, 0);
}
public TouchConsumer getConsumer() {
return mConsumer;
}
private static class EventArray extends ArrayList<MotionEvent> { private static class EventArray extends ArrayList<MotionEvent> {
public int lastEventAction = ACTION_CANCEL; public int lastEventAction = ACTION_CANCEL;
@@ -17,6 +17,7 @@ package com.android.quickstep;
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL; 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.INTERACTION_QUICK_SWITCH;
import static com.android.quickstep.TouchConsumer.isInteractionQuick; import static com.android.quickstep.TouchConsumer.isInteractionQuick;
@@ -50,8 +51,6 @@ import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.TouchConsumer.InteractionType; 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.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -320,14 +319,13 @@ public class NavBarSwipeInteractionHandler extends BaseSwipeInteractionHandler i
/** Animates to the given progress, where 0 is the current app and 1 is overview. */ /** Animates to the given progress, where 0 is the current app and 1 is overview. */
private void animateToProgress(float progress, long duration) { private void animateToProgress(float progress, long duration) {
mIsGoingToHome = Float.compare(progress, 1) == 0;
ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration); ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
anim.setInterpolator(Interpolators.SCROLL); anim.setInterpolator(Interpolators.SCROLL);
anim.addListener(new AnimationSuccessListener() { anim.addListener(new AnimationSuccessListener() {
@Override @Override
public void onAnimationSuccess(Animator animator) { public void onAnimationSuccess(Animator animator) {
mStateCallback.setState(mIsGoingToHome mStateCallback.setState((Float.compare(mCurrentShift.value, 0) == 0)
? STATE_SCALED_SNAPSHOT_RECENTS : STATE_SCALED_SNAPSHOT_APP); ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS);
} }
}); });
anim.start(); anim.start();
@@ -16,20 +16,19 @@
package com.android.quickstep; package com.android.quickstep;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.ActivityManager.TaskDescription;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.LruCache; import android.util.LruCache;
import android.util.SparseArray; import android.util.SparseArray;
import com.android.launcher3.FastBitmapDrawable; import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.graphics.BitmapInfo; import com.android.launcher3.graphics.BitmapInfo;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.graphics.LauncherIcons;
import com.android.systemui.shared.recents.model.IconLoader; import com.android.systemui.shared.recents.model.IconLoader;
import com.android.systemui.shared.recents.model.TaskKeyLruCache; import com.android.systemui.shared.recents.model.TaskKeyLruCache;
@@ -41,13 +40,11 @@ import com.android.systemui.shared.recents.model.TaskKeyLruCache;
public class NormalizedIconLoader extends IconLoader { public class NormalizedIconLoader extends IconLoader {
private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>(); private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>();
private final DrawableFactory mDrawableFactory;
private LauncherIcons mLauncherIcons; private LauncherIcons mLauncherIcons;
public NormalizedIconLoader(Context context, TaskKeyLruCache<Drawable> iconCache, public NormalizedIconLoader(Context context, TaskKeyLruCache<Drawable> iconCache,
LruCache<ComponentName, ActivityInfo> activityInfoCache) { LruCache<ComponentName, ActivityInfo> activityInfoCache) {
super(context, iconCache, activityInfoCache); super(context, iconCache, activityInfoCache);
mDrawableFactory = DrawableFactory.get(context);
} }
@Override @Override
@@ -56,7 +53,7 @@ public class NormalizedIconLoader extends IconLoader {
BitmapInfo info = mDefaultIcons.get(userId); BitmapInfo info = mDefaultIcons.get(userId);
if (info == null) { if (info == null) {
info = getBitmapInfo(Resources.getSystem() info = getBitmapInfo(Resources.getSystem()
.getDrawable(android.R.drawable.sym_def_app_icon), userId, 0, false); .getDrawable(android.R.drawable.sym_def_app_icon), userId);
mDefaultIcons.put(userId, info); mDefaultIcons.put(userId, info);
} }
@@ -65,31 +62,23 @@ public class NormalizedIconLoader extends IconLoader {
} }
@Override @Override
protected Drawable createBadgedDrawable(Drawable drawable, int userId, TaskDescription desc) { protected Drawable createBadgedDrawable(Drawable drawable, int userId) {
return new FastBitmapDrawable(getBitmapInfo(drawable, userId, desc.getPrimaryColor(), return new FastBitmapDrawable(getBitmapInfo(drawable, userId));
false));
} }
private synchronized BitmapInfo getBitmapInfo(Drawable drawable, int userId, private synchronized BitmapInfo getBitmapInfo(Drawable drawable, int userId) {
int primaryColor, boolean isInstantApp) {
if (mLauncherIcons == null) { if (mLauncherIcons == null) {
mLauncherIcons = LauncherIcons.obtain(mContext); mLauncherIcons = LauncherIcons.obtain(mContext);
} }
mLauncherIcons.setWrapperBackgroundColor(primaryColor);
// User version code O, so that the icon is always wrapped in an adaptive icon container. // User version code O, so that the icon is always wrapped in an adaptive icon container.
return mLauncherIcons.createBadgedIconBitmap(drawable, UserHandle.of(userId), return mLauncherIcons.createBadgedIconBitmap(drawable, UserHandle.of(userId),
Build.VERSION_CODES.O, isInstantApp); Build.VERSION_CODES.O);
} }
@Override @Override
protected Drawable getBadgedActivityIcon(ActivityInfo activityInfo, int userId, protected Drawable getBadgedActivityIcon(ActivityInfo activityInfo, int userId) {
TaskDescription desc) { return createBadgedDrawable(
BitmapInfo bitmapInfo = getBitmapInfo( activityInfo.loadUnbadgedIcon(mContext.getPackageManager()), userId);
activityInfo.loadUnbadgedIcon(mContext.getPackageManager()),
userId,
desc.getPrimaryColor(),
activityInfo.applicationInfo.isInstantApp());
return mDrawableFactory.newIcon(bitmapInfo, activityInfo);
} }
} }
@@ -23,11 +23,9 @@ import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID; import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.quickstep.RemoteRunnable.executeSafely; 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_BACK;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW; import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions; import android.app.ActivityOptions;
import android.content.Context; import android.content.Context;
@@ -39,9 +37,10 @@ import android.graphics.Color;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Build; import android.metrics.LogMaker;
import android.os.Bundle; import android.os.Bundle;
import android.os.Looper; import android.os.Looper;
import android.os.SystemClock;
import android.util.Log; import android.util.Log;
import android.view.Choreographer; import android.view.Choreographer;
import android.view.Display; import android.view.Display;
@@ -64,20 +63,50 @@ import com.android.systemui.shared.system.RecentsAnimationListener;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; 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 * Touch consumer for handling events originating from an activity other than Launcher
*/ */
@TargetApi(Build.VERSION_CODES.P)
public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer { public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer {
private static final String TAG = "ActivityTouchConsumer"; private static final String TAG = "ActivityTouchConsumer";
private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150; 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 RunningTaskInfo mRunningTask;
private final RecentsModel mRecentsModel; private final RecentsModel mRecentsModel;
@@ -86,7 +115,6 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
private final MainThreadExecutor mMainThreadExecutor; private final MainThreadExecutor mMainThreadExecutor;
private final Choreographer mBackgroundThreadChoreographer; private final Choreographer mBackgroundThreadChoreographer;
private final boolean mIsDeferredDownTarget;
private final PointF mDownPos = new PointF(); private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF(); private final PointF mLastPos = new PointF();
private int mActivePointerId = INVALID_POINTER_ID; private int mActivePointerId = INVALID_POINTER_ID;
@@ -96,24 +124,26 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
private BaseSwipeInteractionHandler mInteractionHandler; private BaseSwipeInteractionHandler mInteractionHandler;
private int mDisplayRotation; private int mDisplayRotation;
private Rect mStableInsets = new Rect(); private Rect mStableInsets = new Rect();
private @HitTarget int mDownHitTarget = HIT_TARGET_NONE;
private VelocityTracker mVelocityTracker; private VelocityTracker mVelocityTracker;
private MotionEventQueue mEventQueue; private MotionEventQueue mEventQueue;
private boolean mIsGoingToHome;
private final MetricsLogger mMetricsLogger = new MetricsLogger();
public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo, public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo,
RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy, RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy,
MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer, MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer,
@HitTarget int downHitTarget, VelocityTracker velocityTracker) { @HitTarget int downHitTarget) {
super(base); super(base);
mRunningTask = runningTaskInfo; mRunningTask = runningTaskInfo;
mRecentsModel = recentsModel; mRecentsModel = recentsModel;
mHomeIntent = homeIntent; mHomeIntent = homeIntent;
mVelocityTracker = velocityTracker; mVelocityTracker = VelocityTracker.obtain();
mISystemUiProxy = systemUiProxy; mISystemUiProxy = systemUiProxy;
mMainThreadExecutor = mainThreadExecutor; mMainThreadExecutor = mainThreadExecutor;
mBackgroundThreadChoreographer = backgroundThreadChoreographer; mBackgroundThreadChoreographer = backgroundThreadChoreographer;
mIsDeferredDownTarget = Arrays.binarySearch(DEFERRED_HIT_TARGETS, downHitTarget) >= 0; mDownHitTarget = downHitTarget;
} }
@Override @Override
@@ -132,7 +162,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
// Start the window animation on down to give more time for launcher to draw if the // 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 // user didn't start the gesture over the back button
if (!isUsingScreenShot() && !mIsDeferredDownTarget) { if (!isUsingScreenShot() && mDownHitTarget != HIT_TARGET_BACK) {
startTouchTrackingForWindowAnimation(ev.getEventTime()); startTouchTrackingForWindowAnimation(ev.getEventTime());
} }
@@ -174,7 +204,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
if (isUsingScreenShot()) { if (isUsingScreenShot()) {
startTouchTrackingForScreenshotAnimation(); startTouchTrackingForScreenshotAnimation();
} else if (mIsDeferredDownTarget) { } else if (mDownHitTarget == HIT_TARGET_BACK) {
// If we deferred starting the window animation on touch down, then // If we deferred starting the window animation on touch down, then
// start tracking now // start tracking now
startTouchTrackingForWindowAnimation(ev.getEventTime()); startTouchTrackingForWindowAnimation(ev.getEventTime());
@@ -282,7 +312,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
private void startTouchTrackingForWindowAnimation(long touchTimeMs) { private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
// Create the shared handler // Create the shared handler
final WindowTransformSwipeHandler handler = final WindowTransformSwipeHandler handler =
new WindowTransformSwipeHandler(mRunningTask, this, touchTimeMs); new WindowTransformSwipeHandler(mRunningTask, this);
// Preload the plan // Preload the plan
mRecentsModel.loadTasks(mRunningTask.id, null); mRecentsModel.loadTasks(mRunningTask.id, null);
@@ -320,6 +350,16 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
TraceHelper.endSection("RecentsController", "Finishing no handler"); TraceHelper.endSection("RecentsController", "Finishing no handler");
controller.finish(false /* toHome */); 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() { public void onAnimationCanceled() {
@@ -377,7 +417,6 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
if (mInteractionHandler != null) { if (mInteractionHandler != null) {
final BaseSwipeInteractionHandler handler = mInteractionHandler; final BaseSwipeInteractionHandler handler = mInteractionHandler;
mInteractionHandler = null; mInteractionHandler = null;
mIsGoingToHome = handler.mIsGoingToHome;
mMainThreadExecutor.execute(handler::reset); mMainThreadExecutor.execute(handler::reset);
} }
} }
@@ -432,15 +471,4 @@ 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;
}
} }
@@ -1,120 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import 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;
}
}
@@ -15,9 +15,7 @@
*/ */
package com.android.quickstep; 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_HIDE_BACK_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
@@ -62,7 +60,7 @@ public class OverviewInteractionState {
} }
}; };
private static int sFlags = DEBUG_SHOW_OVERVIEW_BUTTON ? FLAG_SHOW_OVERVIEW_BUTTON : 0; private static int sFlags;
public static void setBackButtonVisible(Context context, boolean visible) { public static void setBackButtonVisible(Context context, boolean visible) {
updateFlagOnUi(context, FLAG_HIDE_BACK_BUTTON, !visible); updateFlagOnUi(context, FLAG_HIDE_BACK_BUTTON, !visible);
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.os.Build;
import java.util.ArrayList;
import java.util.function.Consumer;
/**
* Utility class to keep track of a running animation.
*
* This class allows attaching end callbacks to an animation is intended to be used with
* {@link com.android.launcher3.anim.AnimatorPlaybackController}, since in that case
* AnimationListeners are not properly dispatched.
*/
@TargetApi(Build.VERSION_CODES.O)
public class PendingAnimation {
private final ArrayList<Consumer<Boolean>> mEndListeners = new ArrayList<>();
public final AnimatorSet anim;
public PendingAnimation(AnimatorSet anim) {
this.anim = anim;
}
public void finish(boolean isSuccess) {
for (Consumer<Boolean> listeners : mEndListeners) {
listeners.accept(isSuccess);
}
mEndListeners.clear();
}
public void addEndListener(Consumer<Boolean> listener) {
mEndListeners.add(listener);
}
}
@@ -19,14 +19,13 @@ package com.android.quickstep;
import android.view.HapticFeedbackConstants; import android.view.HapticFeedbackConstants;
import com.android.launcher3.Alarm; import com.android.launcher3.Alarm;
import com.android.launcher3.BaseActivity; import com.android.launcher3.Launcher;
import com.android.launcher3.OnAlarmListener; import com.android.launcher3.OnAlarmListener;
import com.android.launcher3.Utilities; 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.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.quickstep.views.RecentsView; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.views.TaskView;
/** /**
* Responds to quick scrub callbacks to page through and launch recent tasks. * Responds to quick scrub callbacks to page through and launch recent tasks.
@@ -36,7 +35,8 @@ import com.android.quickstep.views.TaskView;
*/ */
public class QuickScrubController implements OnAlarmListener { public class QuickScrubController implements OnAlarmListener {
public static final int QUICK_SWITCH_START_DURATION = 210; public static final int QUICK_SWITCH_START_DURATION = 133;
public static final int QUICK_SWITCH_SNAP_DURATION = 120;
private static final boolean ENABLE_AUTO_ADVANCE = true; private static final boolean ENABLE_AUTO_ADVANCE = true;
private static final int NUM_QUICK_SCRUB_SECTIONS = 3; private static final int NUM_QUICK_SCRUB_SECTIONS = 3;
@@ -47,17 +47,15 @@ public class QuickScrubController implements OnAlarmListener {
private final Alarm mAutoAdvanceAlarm; private final Alarm mAutoAdvanceAlarm;
private final RecentsView mRecentsView; private final RecentsView mRecentsView;
private final BaseActivity mActivity; private final Launcher mLauncher;
private boolean mInQuickScrub; private boolean mInQuickScrub;
private int mQuickScrubSection; private int mQuickScrubSection;
private boolean mStartedFromHome; private int mStartPage;
private boolean mHasAlarmRun; private boolean mHasAlarmRun;
private boolean mQuickSwitched;
private boolean mFinishedTransitionToQuickScrub;
public QuickScrubController(BaseActivity activity, RecentsView recentsView) { public QuickScrubController(Launcher launcher, RecentsView recentsView) {
mActivity = activity; mLauncher = launcher;
mRecentsView = recentsView; mRecentsView = recentsView;
if (ENABLE_AUTO_ADVANCE) { if (ENABLE_AUTO_ADVANCE) {
mAutoAdvanceAlarm = new Alarm(); mAutoAdvanceAlarm = new Alarm();
@@ -67,14 +65,10 @@ public class QuickScrubController implements OnAlarmListener {
public void onQuickScrubStart(boolean startingFromHome) { public void onQuickScrubStart(boolean startingFromHome) {
mInQuickScrub = true; mInQuickScrub = true;
mStartedFromHome = startingFromHome; mStartPage = startingFromHome ? 0 : mRecentsView.getFirstTaskIndex();
mQuickScrubSection = 0; mQuickScrubSection = 0;
mHasAlarmRun = false; mHasAlarmRun = false;
mQuickSwitched = false; mLauncher.getUserEventDispatcher().resetActionDurationMillis();
mFinishedTransitionToQuickScrub = false;
snapToNextTaskIfAvailable();
mActivity.getUserEventDispatcher().resetActionDurationMillis();
} }
public void onQuickScrubEnd() { public void onQuickScrubEnd() {
@@ -84,7 +78,11 @@ public class QuickScrubController implements OnAlarmListener {
} }
int page = mRecentsView.getNextPage(); int page = mRecentsView.getNextPage();
Runnable launchTaskRunnable = () -> { Runnable launchTaskRunnable = () -> {
((TaskView) mRecentsView.getPageAt(page)).launchTask(true); if (page < mRecentsView.getFirstTaskIndex()) {
mRecentsView.getPageAt(page).performClick();
} else {
((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
}
}; };
int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen()) int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
* QUICKSCRUB_END_SNAP_DURATION_PER_PAGE; * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
@@ -95,8 +93,8 @@ public class QuickScrubController implements OnAlarmListener {
// No page move needed, just launch it // No page move needed, just launch it
launchTaskRunnable.run(); launchTaskRunnable.run();
} }
mActivity.getUserEventDispatcher().logActionOnControl(Touch.DRAGDROP, mLauncher.getUserEventDispatcher().logActionOnControl(Touch.DRAGDROP,
ControlType.QUICK_SCRUB_BUTTON, null, mStartedFromHome ? ControlType.QUICK_SCRUB_BUTTON, null, mStartPage == 0 ?
ContainerType.WORKSPACE : ContainerType.APP); ContainerType.WORKSPACE : ContainerType.APP);
} }
@@ -104,9 +102,7 @@ public class QuickScrubController implements OnAlarmListener {
int quickScrubSection = Math.round(progress * NUM_QUICK_SCRUB_SECTIONS); int quickScrubSection = Math.round(progress * NUM_QUICK_SCRUB_SECTIONS);
if (quickScrubSection != mQuickScrubSection) { if (quickScrubSection != mQuickScrubSection) {
int pageToGoTo = mRecentsView.getNextPage() + quickScrubSection - mQuickScrubSection; int pageToGoTo = mRecentsView.getNextPage() + quickScrubSection - mQuickScrubSection;
if (mFinishedTransitionToQuickScrub) { goToPageWithHaptic(pageToGoTo);
goToPageWithHaptic(pageToGoTo);
}
if (ENABLE_AUTO_ADVANCE) { if (ENABLE_AUTO_ADVANCE) {
if (quickScrubSection == NUM_QUICK_SCRUB_SECTIONS || quickScrubSection == 0) { if (quickScrubSection == NUM_QUICK_SCRUB_SECTIONS || quickScrubSection == 0) {
mAutoAdvanceAlarm.setAlarm(mHasAlarmRun mAutoAdvanceAlarm.setAlarm(mHasAlarmRun
@@ -120,45 +116,36 @@ public class QuickScrubController implements OnAlarmListener {
} }
public void onQuickSwitch() { public void onQuickSwitch() {
mQuickSwitched = true; for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
quickSwitchIfReady(); TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
} if (taskView.getTask().key.id != mRecentsView.getRunningTaskId()) {
Runnable launchTaskRunnable = () -> taskView.launchTask(true);
public void onFinishedTransitionToQuickScrub() { if (mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION)) {
mFinishedTransitionToQuickScrub = true; // Snap to the new page then launch it
quickSwitchIfReady(); mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable);
} } else {
// No need to move page, just launch task directly
/** launchTaskRunnable.run();
* 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. break;
*/ }
private void quickSwitchIfReady() {
if (mQuickSwitched && mFinishedTransitionToQuickScrub) {
onQuickScrubEnd();
mActivity.getUserEventDispatcher().logActionOnControl(Touch.FLING,
ControlType.QUICK_SCRUB_BUTTON, null, mStartedFromHome ?
ContainerType.WORKSPACE : ContainerType.APP);
} }
mLauncher.getUserEventDispatcher().logActionOnControl(Touch.FLING,
ControlType.QUICK_SCRUB_BUTTON, null, mStartPage == 0 ?
ContainerType.WORKSPACE : ContainerType.APP);
} }
public void snapToNextTaskIfAvailable() { public void snapToPageForCurrentQuickScrubSection() {
if (mInQuickScrub && mRecentsView.getChildCount() > 0) { if (mInQuickScrub) {
int toPage = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1; goToPageWithHaptic(mRecentsView.getFirstTaskIndex() + mQuickScrubSection);
goToPageWithHaptic(toPage, QUICK_SWITCH_START_DURATION);
} }
} }
private void goToPageWithHaptic(int pageToGoTo) { private void goToPageWithHaptic(int pageToGoTo) {
goToPageWithHaptic(pageToGoTo, -1); pageToGoTo = Utilities.boundToRange(pageToGoTo, mStartPage, mRecentsView.getPageCount() - 1);
}
private void goToPageWithHaptic(int pageToGoTo, int overrideDuration) {
pageToGoTo = Utilities.boundToRange(pageToGoTo, 0, mRecentsView.getPageCount() - 1);
if (pageToGoTo != mRecentsView.getNextPage()) { if (pageToGoTo != mRecentsView.getNextPage()) {
int duration = overrideDuration > -1 ? overrideDuration int duration = Math.abs(pageToGoTo - mRecentsView.getNextPage())
: Math.abs(pageToGoTo - mRecentsView.getNextPage()) * QUICKSCRUB_SNAP_DURATION_PER_PAGE;
* QUICKSCRUB_SNAP_DURATION_PER_PAGE;
mRecentsView.snapToPage(pageToGoTo, duration); mRecentsView.snapToPage(pageToGoTo, duration);
mRecentsView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, mRecentsView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
@@ -171,7 +158,7 @@ public class QuickScrubController implements OnAlarmListener {
if (mQuickScrubSection == NUM_QUICK_SCRUB_SECTIONS if (mQuickScrubSection == NUM_QUICK_SCRUB_SECTIONS
&& currPage < mRecentsView.getPageCount() - 1) { && currPage < mRecentsView.getPageCount() - 1) {
goToPageWithHaptic(currPage + 1); goToPageWithHaptic(currPage + 1);
} else if (mQuickScrubSection == 0 && currPage > 0) { } else if (mQuickScrubSection == 0 && currPage > mStartPage) {
goToPageWithHaptic(currPage - 1); goToPageWithHaptic(currPage - 1);
} }
mHasAlarmRun = true; mHasAlarmRun = true;
@@ -15,29 +15,34 @@
*/ */
package com.android.quickstep; package com.android.quickstep;
import android.app.ListActivity;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle;
import android.support.annotation.Nullable;
import android.widget.ArrayAdapter;
import com.android.launcher3.BaseActivity; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
import com.android.launcher3.InvariantDeviceProfile; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions;
import com.android.launcher3.LauncherAppState; import com.android.systemui.shared.recents.model.RecentsTaskLoader;
import com.android.launcher3.R; import com.android.systemui.shared.recents.model.Task;
/** /**
* A simple activity to show the recently launched tasks * A simple activity to show the recently launched tasks
*/ */
public class RecentsActivity extends BaseActivity { public class RecentsActivity extends ListActivity {
private ArrayAdapter<Task> mAdapter;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// In case we are reusing IDP, create a copy so that we dont conflict with Launcher RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(this);
// activity. plan.preloadPlan(new PreloadOptions(), new RecentsTaskLoader(this, 1, 1, 0), -1,
LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); UserHandle.myUserId());
setDeviceProfile(appState != null
? appState.getInvariantDeviceProfile().getDeviceProfile(this).copy(this)
: new InvariantDeviceProfile(this).getDeviceProfile(this));
setContentView(R.layout.fallback_recents_activity); mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
mAdapter.addAll(plan.getTaskStack().getTasks());
setListAdapter(mAdapter);
} }
} }
@@ -16,8 +16,6 @@
package com.android.quickstep; package com.android.quickstep;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
@@ -53,6 +51,7 @@ import java.util.function.Consumer;
*/ */
@TargetApi(Build.VERSION_CODES.O) @TargetApi(Build.VERSION_CODES.O)
public class RecentsModel extends TaskStackChangeListener { public class RecentsModel extends TaskStackChangeListener {
// We do not need any synchronization for this variable as its only written on UI thread. // We do not need any synchronization for this variable as its only written on UI thread.
private static RecentsModel INSTANCE; private static RecentsModel INSTANCE;
@@ -84,16 +83,10 @@ public class RecentsModel extends TaskStackChangeListener {
private int mTaskChangeId; private int mTaskChangeId;
private ISystemUiProxy mSystemUiProxy; private ISystemUiProxy mSystemUiProxy;
private boolean mClearAssistCacheOnStackChange = true; private boolean mClearAssistCacheOnStackChange = true;
private final boolean mPreloadTasksInBackground;
private RecentsModel(Context context) { private RecentsModel(Context context) {
mContext = context; mContext = context;
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
mPreloadTasksInBackground = !activityManager.isLowRamDevice();
mMainThreadExecutor = new MainThreadExecutor();
Resources res = context.getResources(); Resources res = context.getResources();
mRecentsTaskLoader = new RecentsTaskLoader(mContext, mRecentsTaskLoader = new RecentsTaskLoader(mContext,
res.getInteger(R.integer.config_recentsMaxThumbnailCacheSize), res.getInteger(R.integer.config_recentsMaxThumbnailCacheSize),
@@ -107,6 +100,8 @@ public class RecentsModel extends TaskStackChangeListener {
} }
}; };
mRecentsTaskLoader.startLoader(mContext); mRecentsTaskLoader.startLoader(mContext);
mMainThreadExecutor = new MainThreadExecutor();
ActivityManagerWrapper.getInstance().registerTaskStackListener(this); ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
mTaskChangeId = 1; mTaskChangeId = 1;
@@ -167,31 +162,6 @@ 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) { public boolean isLoadPlanValid(int resultId) {
return mTaskChangeId == resultId; return mTaskChangeId == resultId;
} }
@@ -208,19 +178,6 @@ public class RecentsModel extends TaskStackChangeListener {
return mSystemUiProxy; 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 @WorkerThread
public void preloadAssistData(int taskId, Bundle data) { public void preloadAssistData(int taskId, Bundle data) {
mMainThreadExecutor.execute(() -> { mMainThreadExecutor.execute(() -> {
@@ -1,56 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import android.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));
}
}
@@ -14,36 +14,40 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.quickstep.views; package com.android.quickstep;
import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.quickstep.TaskView.CURVE_FACTOR;
import static com.android.quickstep.TaskView.CURVE_INTERPOLATOR;
import android.animation.AnimatorSet; import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.graphics.Bitmap;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 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.Rect;
import android.os.Build; import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.FrameLayout;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.PagedView; import com.android.launcher3.PagedView;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.uioverrides.OverviewState;
import com.android.quickstep.PendingAnimation; import com.android.launcher3.uioverrides.RecentsViewStateController;
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.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.RecentsTaskLoader; import com.android.systemui.shared.recents.model.RecentsTaskLoader;
import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task;
@@ -58,30 +62,29 @@ import java.util.ArrayList;
/** /**
* A list of recent tasks. * A list of recent tasks.
*/ */
@TargetApi(Build.VERSION_CODES.P) public class RecentsView extends PagedView implements Insettable {
public abstract class RecentsView<T extends BaseActivity>
extends PagedView implements OnSharedPreferenceChangeListener {
private static final String PREF_FLIP_RECENTS = "pref_flip_recents";
private static final Rect sTempStableInsets = new Rect(); private static final Rect sTempStableInsets = new Rect();
protected final T mActivity; public static final int SCROLL_TYPE_NONE = 0;
private final QuickScrubController mQuickScrubController; public static final int SCROLL_TYPE_TASK = 1;
private final float mFastFlingVelocity; public static final int SCROLL_TYPE_WORKSPACE = 2;
private final RecentsModel mModel;
private final Launcher mLauncher;
private QuickScrubController mQuickScrubController;
private final ScrollState mScrollState = new ScrollState(); private final ScrollState mScrollState = new ScrollState();
// Keeps track of the previously known visible tasks for purposes of loading/unloading task data private boolean mOverviewStateEnabled;
private final SparseBooleanArray mHasVisibleTaskData = new SparseBooleanArray(); private boolean mTaskStackListenerRegistered;
private LayoutTransition mLayoutTransition;
private Runnable mNextPageSwitchRunnable;
/** /**
* TODO: Call reloadIdNeeded in onTaskStackChanged. * TODO: Call reloadIdNeeded in onTaskStackChanged.
*/ */
private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
@Override @Override
public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
for (int i = 0; i < getChildCount(); i++) { for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
final TaskView taskView = (TaskView) getChildAt(i); final TaskView taskView = (TaskView) getChildAt(i);
if (taskView.getTask().key.id == taskId) { if (taskView.getTask().key.id == taskId) {
taskView.getThumbnail().setThumbnail(taskView.getTask(), snapshot); taskView.getThumbnail().setThumbnail(taskView.getTask(), snapshot);
@@ -91,51 +94,47 @@ public abstract class RecentsView<T extends BaseActivity>
} }
}; };
private RecentsViewStateController mStateController;
private int mFirstTaskIndex;
private final RecentsModel mModel;
private int mLoadPlanId = -1; private int mLoadPlanId = -1;
// Only valid until the launcher state changes to NORMAL // Only valid until the launcher state changes to NORMAL
private int mRunningTaskId = -1; private int mRunningTaskId = -1;
private Bitmap mScrim;
private Paint mFadePaint;
private Shader mFadeShader;
private Matrix mFadeMatrix;
private boolean mScrimOnLeft;
private boolean mFirstTaskIconScaledDown = false; private boolean mFirstTaskIconScaledDown = false;
private boolean mOverviewStateEnabled; public RecentsView(Context context) {
private boolean mTaskStackListenerRegistered; this(context, null);
private Runnable mNextPageSwitchRunnable; }
private PendingAnimation mPendingAnimation; public RecentsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) { public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing)); setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
enableFreeScroll(true); enableFreeScroll(true);
setupLayoutTransition();
setClipToOutline(true); setClipToOutline(true);
mFastFlingVelocity = getResources() mLauncher = Launcher.getLauncher(context);
.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity); mQuickScrubController = new QuickScrubController(mLauncher, this);
mActivity = (T) BaseActivity.fromContext(context);
mQuickScrubController = new QuickScrubController(mActivity, this);
mModel = RecentsModel.getInstance(context); mModel = RecentsModel.getInstance(context);
onSharedPreferenceChanged(Utilities.getPrefs(context), PREF_FLIP_RECENTS); mScrollState.isRtl = mIsRtl;
}
@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) { public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData) {
for (int i = 0; i < getChildCount(); i++) { for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
final TaskView taskView = (TaskView) getChildAt(i); final TaskView taskView = (TaskView) getChildAt(i);
if (taskView.getTask().key.id == taskId) { if (taskView.getTask().key.id == taskId) {
taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData); taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
@@ -146,6 +145,23 @@ public abstract class RecentsView<T extends BaseActivity>
return null; 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 @Override
protected void onWindowVisibilityChanged(int visibility) { protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility); super.onWindowVisibilityChanged(visibility);
@@ -156,37 +172,62 @@ public abstract class RecentsView<T extends BaseActivity>
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
updateTaskStackListenerState(); updateTaskStackListenerState();
Utilities.getPrefs(getContext()).registerOnSharedPreferenceChangeListener(this);
} }
@Override @Override
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
super.onDetachedFromWindow(); super.onDetachedFromWindow();
updateTaskStackListenerState(); updateTaskStackListenerState();
Utilities.getPrefs(getContext()).unregisterOnSharedPreferenceChangeListener(this);
} }
@Override @Override
public void onViewRemoved(View child) { public void setInsets(Rect insets) {
super.onViewRemoved(child); 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);
// Clear the task data for the removed child if it was visible setPadding(padding.left, padding.top, padding.right, 0);
Task task = ((TaskView) child).getTask();
if (mHasVisibleTaskData.get(task.key.id)) { if (dp.isVerticalBarLayout()) {
mHasVisibleTaskData.delete(task.key.id); boolean wasScrimOnLeft = mScrimOnLeft;
RecentsTaskLoader loader = mModel.getRecentsTaskLoader(); mScrimOnLeft = dp.isSeascape();
loader.unloadTaskData(task);
loader.getHighResThumbnailLoader().onTaskInvisible(task); if (mScrim == null || wasScrimOnLeft != mScrimOnLeft) {
Drawable scrim = getContext().getDrawable(mScrimOnLeft
? R.drawable.recents_horizontal_scrim_left
: R.drawable.recents_horizontal_scrim_right);
if (scrim instanceof BitmapDrawable) {
mScrim = ((BitmapDrawable) scrim).getBitmap();
mFadePaint = new Paint();
mFadePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
mFadeShader = new BitmapShader(mScrim, TileMode.CLAMP, TileMode.REPEAT);
mFadeMatrix = new Matrix();
} else {
mScrim = null;
}
}
} else {
mScrim = null;
mFadePaint = null;
mFadeShader = null;
mFadeMatrix = null;
} }
} }
public int getFirstTaskIndex() {
return mFirstTaskIndex;
}
public boolean isTaskViewVisible(TaskView tv) { public boolean isTaskViewVisible(TaskView tv) {
// For now, just check if it's the active task or an adjacent task // For now, just check if it's the active task or an adjacent task
return Math.abs(indexOfChild(tv) - getNextPage()) <= 1; return Math.abs(indexOfChild(tv) - getNextPage()) <= 1;
} }
public TaskView getTaskView(int taskId) { public TaskView getTaskView(int taskId) {
for (int i = 0; i < getChildCount(); i++) { for (int i = getFirstTaskIndex(); i < getChildCount(); i++) {
TaskView tv = (TaskView) getChildAt(i); TaskView tv = (TaskView) getChildAt(i);
if (tv.getTask().key.id == taskId) { if (tv.getTask().key.id == taskId) {
return tv; return tv;
@@ -195,6 +236,14 @@ public abstract class RecentsView<T extends BaseActivity>
return null; return null;
} }
public void setStateController(RecentsViewStateController stateController) {
mStateController = stateController;
}
public RecentsViewStateController getStateController() {
return mStateController;
}
public void setOverviewStateEnabled(boolean enabled) { public void setOverviewStateEnabled(boolean enabled) {
mOverviewStateEnabled = enabled; mOverviewStateEnabled = enabled;
updateTaskStackListenerState(); updateTaskStackListenerState();
@@ -214,10 +263,7 @@ public abstract class RecentsView<T extends BaseActivity>
} }
private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) { private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) {
if (mPendingAnimation != null) { final RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
mPendingAnimation.addEndListener((b) -> applyLoadPlan(loadPlan));
return;
}
TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null; TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null;
if (stack == null) { if (stack == null) {
removeAllViews(); removeAllViews();
@@ -230,8 +276,9 @@ public abstract class RecentsView<T extends BaseActivity>
// necessary) // necessary)
final LayoutInflater inflater = LayoutInflater.from(getContext()); final LayoutInflater inflater = LayoutInflater.from(getContext());
final ArrayList<Task> tasks = new ArrayList<>(stack.getTasks()); final ArrayList<Task> tasks = new ArrayList<>(stack.getTasks());
setLayoutTransition(null);
final int requiredChildCount = tasks.size(); final int requiredChildCount = tasks.size() + mFirstTaskIndex;
for (int i = getChildCount(); i < requiredChildCount; i++) { for (int i = getChildCount(); i < requiredChildCount; i++) {
final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false); final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false);
addView(taskView); addView(taskView);
@@ -239,36 +286,26 @@ public abstract class RecentsView<T extends BaseActivity>
while (getChildCount() > requiredChildCount) { while (getChildCount() > requiredChildCount) {
final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1); final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1);
removeView(taskView); removeView(taskView);
loader.unloadTaskData(taskView.getTask());
} }
setLayoutTransition(mLayoutTransition);
// Unload existing visible task data
unloadVisibleTaskData();
// Rebind and reset all task views // Rebind and reset all task views
for (int i = requiredChildCount - 1; i >= 0; i--) { for (int i = tasks.size() - 1; i >= 0; i--) {
final int pageIndex = requiredChildCount - i - 1;
final Task task = tasks.get(i); final Task task = tasks.get(i);
final TaskView taskView = (TaskView) getChildAt(pageIndex); final TaskView taskView = (TaskView) getChildAt(tasks.size() - i - 1 + mFirstTaskIndex);
taskView.bind(task); taskView.bind(task);
taskView.resetVisualProperties();
loader.loadTaskData(task);
} }
resetTaskVisuals(); updateCurveProperties();
applyIconScale(false /* animate */); applyIconScale(false /* animate */);
if (oldChildCount != getChildCount()) { if (oldChildCount != getChildCount()) {
mQuickScrubController.snapToNextTaskIfAvailable(); mQuickScrubController.snapToPageForCurrentQuickScrubSection();
} }
} }
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() { private void updateTaskStackListenerState() {
boolean registerStackListener = mOverviewStateEnabled && isAttachedToWindow() boolean registerStackListener = mOverviewStateEnabled && isAttachedToWindow()
&& getWindowVisibility() == VISIBLE; && getWindowVisibility() == VISIBLE;
@@ -285,7 +322,7 @@ public abstract class RecentsView<T extends BaseActivity>
} }
} }
protected static Rect getPadding(DeviceProfile profile, Context context) { private static Rect getPadding(DeviceProfile profile, Context context) {
WindowManagerWrapper.getInstance().getStableInsets(sTempStableInsets); WindowManagerWrapper.getInstance().getStableInsets(sTempStableInsets);
Rect padding = new Rect(profile.workspacePadding); Rect padding = new Rect(profile.workspacePadding);
@@ -294,14 +331,11 @@ public abstract class RecentsView<T extends BaseActivity>
float overviewHeight, overviewWidth; float overviewHeight, overviewWidth;
if (profile.isVerticalBarLayout()) { 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. // Use the same padding on both sides for symmetry.
float availableWidth = taskWidth - 2 * Math.max(maxPadding, scrimLength); float availableWidth = taskWidth - 2 * Math.max(padding.left, padding.right);
float availableHeight = profile.availableHeightPx - padding.top - padding.bottom float availableHeight = profile.availableHeightPx - padding.top
- sTempStableInsets.top; - sTempStableInsets.top - Math.max(padding.bottom,
profile.heightPx * (1 - OverviewState.getVerticalProgress(profile, context)));
float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight); float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
overviewHeight = taskHeight * scaledRatio; overviewHeight = taskHeight * scaledRatio;
overviewWidth = taskWidth * scaledRatio; overviewWidth = taskWidth * scaledRatio;
@@ -318,6 +352,33 @@ public abstract class RecentsView<T extends BaseActivity>
return padding; 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) { public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) {
Rect targetPadding = getPadding(grid, context); Rect targetPadding = getPadding(grid, context);
Rect insets = grid.getInsets(); Rect insets = grid.getInsets();
@@ -331,24 +392,9 @@ public abstract class RecentsView<T extends BaseActivity>
} }
@Override @Override
protected boolean computeScrollHelper() { public void computeScroll() {
boolean scrolling = super.computeScrollHelper(); super.computeScroll();
boolean isFlingingFast = false;
updateCurveProperties(); 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;
} }
/** /**
@@ -358,7 +404,8 @@ public abstract class RecentsView<T extends BaseActivity>
if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) { if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
return; return;
} }
final int halfPageWidth = getNormalChildWidth() / 2; final int halfPageWidth = mScrollState.halfPageWidth = getNormalChildWidth() / 2;
mScrollState.lastScrollType = SCROLL_TYPE_NONE;
final int screenCenter = mInsets.left + getPaddingLeft() + getScrollX() + halfPageWidth; final int screenCenter = mInsets.left + getPaddingLeft() + getScrollX() + halfPageWidth;
final int halfScreenWidth = getMeasuredWidth() / 2; final int halfScreenWidth = getMeasuredWidth() / 2;
final int pageSpacing = mPageSpacing; final int pageSpacing = mPageSpacing;
@@ -366,72 +413,36 @@ public abstract class RecentsView<T extends BaseActivity>
final int pageCount = getPageCount(); final int pageCount = getPageCount();
for (int i = 0; i < pageCount; i++) { for (int i = 0; i < pageCount; i++) {
View page = getPageAt(i); View page = getPageAt(i);
float pageCenter = page.getLeft() + page.getTranslationX() + halfPageWidth; int pageCenter = page.getLeft() + halfPageWidth;
float distanceFromScreenCenter = screenCenter - pageCenter; mScrollState.distanceFromScreenCenter = screenCenter - pageCenter;
float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing; float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
mScrollState.linearInterpolation = Math.min(1, mScrollState.linearInterpolation = Math.min(1,
Math.abs(distanceFromScreenCenter) / distanceToReachEdge); Math.abs(mScrollState.distanceFromScreenCenter) / distanceToReachEdge);
((PageCallbacks) page).onPageScroll(mScrollState); mScrollState.lastScrollType = ((PageCallbacks) page).onPageScroll(mScrollState);
} }
} }
/** public void onTaskDismissed(TaskView taskView) {
* Iterates through all thet asks, and loads the associated task data for newly visible tasks, ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
* and unloads the associated task data for tasks that are no longer visible. removeView(taskView);
*/ if (getTaskCount() == 0) {
public void loadVisibleTaskData() { mLauncher.getStateManager().goToState(NORMAL);
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() { public void reset() {
unloadVisibleTaskData();
mRunningTaskId = -1; mRunningTaskId = -1;
setCurrentPage(0); setCurrentPage(0);
} }
public int getTaskCount() {
return getChildCount() - mFirstTaskIndex;
}
public int getRunningTaskId() {
return mRunningTaskId;
}
/** /**
* Reloads the view if anything in recents changed. * Reloads the view if anything in recents changed.
*/ */
@@ -451,24 +462,26 @@ public abstract class RecentsView<T extends BaseActivity>
*/ */
public void showTask(int runningTaskId) { public void showTask(int runningTaskId) {
boolean needsReload = false; boolean needsReload = false;
if (getChildCount() == 0) { if (getTaskCount() == 0) {
needsReload = true; needsReload = true;
// Add an empty view for now // Add an empty view for now
setLayoutTransition(null);
final TaskView taskView = (TaskView) LayoutInflater.from(getContext()) final TaskView taskView = (TaskView) LayoutInflater.from(getContext())
.inflate(R.layout.task, this, false); .inflate(R.layout.task, this, false);
addView(taskView, 0); addView(taskView, mFirstTaskIndex);
setLayoutTransition(mLayoutTransition);
} }
mRunningTaskId = runningTaskId;
setCurrentPage(0);
if (!needsReload) { if (!needsReload) {
needsReload = !mModel.isLoadPlanValid(mLoadPlanId); needsReload = !mModel.isLoadPlanValid(mLoadPlanId);
} }
if (needsReload) { if (needsReload) {
mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan); mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
} else {
loadVisibleTaskData();
} }
getPageAt(mCurrentPage).setAlpha(0); mRunningTaskId = runningTaskId;
setCurrentPage(mFirstTaskIndex);
if (mCurrentPage >= mFirstTaskIndex) {
getPageAt(mCurrentPage).setAlpha(0);
}
} }
public QuickScrubController getQuickScrubController() { public QuickScrubController getQuickScrubController() {
@@ -485,7 +498,7 @@ public abstract class RecentsView<T extends BaseActivity>
private void applyIconScale(boolean animate) { private void applyIconScale(boolean animate) {
float scale = mFirstTaskIconScaledDown ? 0 : 1; float scale = mFirstTaskIconScaledDown ? 0 : 1;
TaskView firstTask = (TaskView) getChildAt(0); TaskView firstTask = (TaskView) getChildAt(mFirstTaskIndex);
if (firstTask != null) { if (firstTask != null) {
if (animate) { if (animate) {
firstTask.animateIconToScale(scale); firstTask.animateIconToScale(scale);
@@ -495,94 +508,57 @@ public abstract class RecentsView<T extends BaseActivity>
} }
} }
@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 { public interface PageCallbacks {
/** /**
* Updates the page UI based on scroll params. * 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
*/ */
default void onPageScroll(ScrollState scrollState) {}; int onPageScroll(ScrollState scrollState);
} }
public static class ScrollState { public static class ScrollState {
/** public boolean isRtl;
* The progress from 0 to 1, where 0 is the center public int lastScrollType;
* of the screen and 1 is the edge of the screen.
*/ public int halfPageWidth;
public float distanceFromScreenCenter;
public float linearInterpolation; public float linearInterpolation;
}
public PendingAnimation createTaskDismissAnimation(TaskView taskView, long duration) { public float prevPageExtraWidth;
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);
} }
} }
@@ -0,0 +1,52 @@
/*
* 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);
}
}
@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.quickstep.views; package com.android.quickstep;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorSet; import android.animation.AnimatorSet;
@@ -40,8 +40,6 @@ import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.shortcuts.DeepShortcutView; 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. * Contains options for a recent task when long-pressing its icon.
@@ -16,39 +16,27 @@
package com.android.quickstep; package com.android.quickstep;
import android.app.ActivityOptions;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewTreeObserver.OnPreDrawListener;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.ItemInfo; import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo; import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.util.InstantAppResolver; 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.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task; 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.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat; 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; import java.util.function.Consumer;
/** /**
@@ -98,10 +86,9 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
} }
} }
public static class SplitScreen extends TaskSystemShortcut implements OnPreDrawListener { public static class SplitScreen extends TaskSystemShortcut {
private Handler mHandler; private Handler mHandler;
private TaskView mTaskView;
public SplitScreen() { public SplitScreen() {
super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen); super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen);
@@ -117,55 +104,22 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
if (!task.isDockable) { if (!task.isDockable) {
return null; return null;
} }
mTaskView = taskView;
return (v -> { return (v -> {
AbstractFloatingView.closeOpenViews(launcher, true, final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions(true);
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); final Consumer<Boolean> resultCallback = success -> {
if (success) {
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.<RecentsView>getOverviewPanel().removeView(taskView); launcher.<RecentsView>getOverviewPanel().removeView(taskView);
}; }
};
ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(
task.key, options, resultCallback, mHandler);
final int[] position = new int[2]; // TODO improve transition; see:
taskView.getLocationOnScreen(position); // DockedFirstAnimationFrameEvent
final int width = (int) (taskView.getWidth() * taskView.getScaleX()); // RecentsTransitionHelper#composeDockAnimationSpec
final int height = (int) (taskView.getHeight() * taskView.getScaleY()); // WindowManagerWrapper#overridePendingAppTransitionMultiThumbFuture
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<AppTransitionAnimationSpecCompat> 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 { public static class Pin extends TaskSystemShortcut {
@@ -183,11 +137,7 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
if (sysUiProxy == null) { if (sysUiProxy == null) {
return null; return null;
} }
if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) { if (!ActivityManagerWrapper.getInstance().isLockToAppEnabled()) {
return null;
}
if (ActivityManagerWrapper.getInstance().isLockToAppActive()) {
// We shouldn't be able to pin while an app is locked.
return null; return null;
} }
return view -> { return view -> {
@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.quickstep.views; package com.android.quickstep;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
@@ -33,10 +33,9 @@ import android.graphics.Shader;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskOverlayFactory.TaskOverlay; import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -75,7 +74,6 @@ public class TaskThumbnailView extends View {
mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius); mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
mFadeLength = getResources().getDimension(R.dimen.task_fade_length); mFadeLength = getResources().getDimension(R.dimen.task_fade_length);
mOverlay = TaskOverlayFactory.get(context).createOverlay(this); mOverlay = TaskOverlayFactory.get(context).createOverlay(this);
mPaint.setFilterBitmap(true);
} }
public void bind() { public void bind() {
@@ -153,8 +151,7 @@ public class TaskThumbnailView extends View {
} else { } else {
final Configuration configuration = final Configuration configuration =
getContext().getApplicationContext().getResources().getConfiguration(); getContext().getApplicationContext().getResources().getConfiguration();
final DeviceProfile profile = BaseActivity.fromContext(getContext()) final DeviceProfile profile = Launcher.getLauncher(getContext()).getDeviceProfile();
.getDeviceProfile();
if (configuration.orientation == mThumbnailData.orientation) { if (configuration.orientation == mThumbnailData.orientation) {
// If we are in the same orientation as the screenshot, just scale it to the // If we are in the same orientation as the screenshot, just scale it to the
// width of the task view // width of the task view
@@ -14,7 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.quickstep.views; package com.android.quickstep;
import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
import android.animation.TimeInterpolator; import android.animation.TimeInterpolator;
import android.app.ActivityOptions; import android.app.ActivityOptions;
@@ -30,8 +33,8 @@ import android.widget.ImageView;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.quickstep.views.RecentsView.PageCallbacks; import com.android.quickstep.RecentsView.PageCallbacks;
import com.android.quickstep.views.RecentsView.ScrollState; import com.android.quickstep.RecentsView.ScrollState;
import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskCallbacks; import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -44,15 +47,17 @@ import java.util.function.Consumer;
*/ */
public class TaskView extends FrameLayout implements TaskCallbacks, PageCallbacks { public class TaskView extends FrameLayout implements TaskCallbacks, PageCallbacks {
/** A curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */ /** Designates how "curvy" the carousel is from 0 to 1, where 0 is a straight line. */
private static final TimeInterpolator CURVE_INTERPOLATOR public static final float CURVE_FACTOR = 0.25f;
= x -> (float) -Math.cos(x * Math.PI) / 2f + .5f; /** 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)));
/** /**
* The alpha of a black scrim on a page in the carousel as it leaves the screen. * 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. * In the resting position of the carousel, the adjacent pages have about half this scrim.
*/ */
private static final float MAX_PAGE_SCRIM_ALPHA = 0.4f; private static final float MAX_PAGE_SCRIM_ALPHA = 0.8f;
private static final long SCALE_ICON_DURATION = 120; private static final long SCALE_ICON_DURATION = 120;
@@ -154,16 +159,38 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
setScaleY(1f); setScaleY(1f);
setTranslationX(0f); setTranslationX(0f);
setTranslationY(0f); setTranslationY(0f);
setTranslationZ(0);
setAlpha(1f); setAlpha(1f);
} }
@Override @Override
public void onPageScroll(ScrollState scrollState) { public int onPageScroll(ScrollState scrollState) {
float curveInterpolation = float curveInterpolation =
CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation); 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); 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 { private static final class TaskOutlineProvider extends ViewOutlineProvider {
@@ -21,6 +21,8 @@ import android.support.annotation.IntDef;
import android.view.Choreographer; import android.view.Choreographer;
import android.view.MotionEvent; import android.view.MotionEvent;
import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -62,14 +64,4 @@ public interface TouchConsumer extends Consumer<MotionEvent> {
default Choreographer getIntrimChoreographer(MotionEventQueue queue) { default Choreographer getIntrimChoreographer(MotionEventQueue queue) {
return null; return null;
} }
default void deferInit() { }
default boolean deferNextEventToMainThread() {
return false;
}
default boolean forceToLauncherConsumer() {
return false;
}
} }
@@ -21,13 +21,15 @@ import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN; import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.LauncherState.FAST_OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.NORMAL; import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.RunningTaskInfo;
import android.app.Service; import android.app.Service;
import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.graphics.PointF; import android.graphics.PointF;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
@@ -38,18 +40,15 @@ import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.Choreographer; import android.view.Choreographer;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherState;
import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.uioverrides.UiFactory; import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.util.TraceHelper; 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.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -61,8 +60,6 @@ import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
@TargetApi(Build.VERSION_CODES.O) @TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service { public class TouchInteractionService extends Service {
public static final boolean DEBUG_SHOW_OVERVIEW_BUTTON = false;
private static final SparseArray<String> sMotionEventNames; private static final SparseArray<String> sMotionEventNames;
static { static {
@@ -120,6 +117,7 @@ public class TouchInteractionService extends Service {
@Override @Override
public void onQuickScrubStart() { public void onQuickScrubStart() {
mEventQueue.onQuickScrubStart(); mEventQueue.onQuickScrubStart();
sQuickScrubEnabled = true;
TraceHelper.partitionSection("SysUiBinder", "onQuickScrubStart"); TraceHelper.partitionSection("SysUiBinder", "onQuickScrubStart");
} }
@@ -132,37 +130,35 @@ public class TouchInteractionService extends Service {
public void onQuickScrubEnd() { public void onQuickScrubEnd() {
mEventQueue.onQuickScrubEnd(); mEventQueue.onQuickScrubEnd();
TraceHelper.endSection("SysUiBinder", "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 final TouchConsumer mNoOpTouchConsumer = (ev) -> {};
private static boolean sConnected = false; private static boolean sConnected = false;
private static boolean sQuickScrubEnabled = false;
public static boolean isConnected() { public static boolean isConnected() {
return sConnected; return sConnected;
} }
public static boolean isQuickScrubEnabled() {
return sQuickScrubEnabled;
}
private ActivityManagerWrapper mAM; private ActivityManagerWrapper mAM;
private RunningTaskInfo mRunningTask;
private RecentsModel mRecentsModel; private RecentsModel mRecentsModel;
private Intent mHomeIntent;
private ComponentName mLauncher;
private MotionEventQueue mEventQueue; private MotionEventQueue mEventQueue;
private MainThreadExecutor mMainThreadExecutor; private MainThreadExecutor mMainThreadExecutor;
private ISystemUiProxy mISystemUiProxy; private ISystemUiProxy mISystemUiProxy;
private OverviewCommandHelper mOverviewCommandHelper;
private Choreographer mMainThreadChoreographer; private Choreographer mMainThreadChoreographer;
private Choreographer mBackgroundThreadChoreographer; private Choreographer mBackgroundThreadChoreographer;
private MotionEventQueue mNoOpEventQueue;
@Override @Override
public void onCreate() { public void onCreate() {
@@ -170,9 +166,19 @@ public class TouchInteractionService extends Service {
mAM = ActivityManagerWrapper.getInstance(); mAM = ActivityManagerWrapper.getInstance();
mRecentsModel = RecentsModel.getInstance(this); mRecentsModel = RecentsModel.getInstance(this);
mMainThreadExecutor = new MainThreadExecutor(); mMainThreadExecutor = new MainThreadExecutor();
mOverviewCommandHelper = new OverviewCommandHelper(this);
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);
mMainThreadChoreographer = Choreographer.getInstance(); mMainThreadChoreographer = Choreographer.getInstance();
mEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer); mNoOpEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
mEventQueue = mNoOpEventQueue;
sConnected = true; sConnected = true;
@@ -184,6 +190,7 @@ public class TouchInteractionService extends Service {
@Override @Override
public void onDestroy() { public void onDestroy() {
sConnected = false; sConnected = false;
sQuickScrubEnabled = false;
super.onDestroy(); super.onDestroy();
} }
@@ -194,45 +201,31 @@ public class TouchInteractionService extends Service {
} }
private void onBinderPreMotionEvent(@HitTarget int downHitTarget) { private void onBinderPreMotionEvent(@HitTarget int downHitTarget) {
mRunningTask = mAM.getRunningTask();
mEventQueue.reset(); mEventQueue.reset();
TouchConsumer oldConsumer = mEventQueue.getConsumer();
if (oldConsumer.deferNextEventToMainThread()) { if (mRunningTask == null) {
mEventQueue = mNoOpEventQueue;
} else if (mRunningTask.topActivity.equals(mLauncher)) {
mEventQueue = getLauncherEventQueue();
} else {
mEventQueue = new MotionEventQueue(mMainThreadChoreographer, mEventQueue = new MotionEventQueue(mMainThreadChoreographer,
new DeferredTouchConsumer((v) -> getCurrentTouchConsumer(downHitTarget, new OtherActivityTouchConsumer(this, mRunningTask, mRecentsModel,
oldConsumer.forceToLauncherConsumer(), v))); mHomeIntent, mISystemUiProxy, mMainThreadExecutor,
mEventQueue.deferInit(); mBackgroundThreadChoreographer, downHitTarget));
} else {
mEventQueue = new MotionEventQueue(
mMainThreadChoreographer, getCurrentTouchConsumer(downHitTarget, false, null));
} }
} }
private TouchConsumer getCurrentTouchConsumer( private MotionEventQueue getLauncherEventQueue() {
@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(); Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback();
if (launcher == null) { if (launcher == null) {
return mNoOpTouchConsumer; return mNoOpEventQueue;
} }
View target = launcher.getDragLayer(); View target = launcher.getDragLayer();
return new LauncherTouchConsumer(launcher, target); return new MotionEventQueue(mMainThreadChoreographer,
new LauncherTouchConsumer(launcher, target));
} }
private static class LauncherTouchConsumer implements TouchConsumer { private static class LauncherTouchConsumer implements TouchConsumer {
@@ -317,12 +310,13 @@ public class TouchInteractionService extends Service {
if (TouchConsumer.isInteractionQuick(interactionType)) { if (TouchConsumer.isInteractionQuick(interactionType)) {
Runnable action = () -> { Runnable action = () -> {
Runnable onComplete = null; Runnable onComplete = null;
if (interactionType == INTERACTION_QUICK_SWITCH) { if (interactionType == INTERACTION_QUICK_SCRUB) {
mQuickScrubController.onQuickScrubStart(true);
} else if (interactionType == INTERACTION_QUICK_SWITCH) {
onComplete = mQuickScrubController::onQuickSwitch; onComplete = mQuickScrubController::onQuickSwitch;
} }
LauncherState fromState = mLauncher.getStateManager().getState(); mLauncher.getStateManager().goToState(OVERVIEW, true, 0,
mLauncher.getStateManager().goToState(FAST_OVERVIEW, true, onComplete); QUICK_SWITCH_START_DURATION, onComplete);
mQuickScrubController.onQuickScrubStart(fromState == NORMAL);
}; };
if (mLauncher.getWorkspace().runOnOverlayHidden(action)) { if (mLauncher.getWorkspace().runOnOverlayHidden(action)) {
@@ -15,12 +15,9 @@
*/ */
package com.android.quickstep; package com.android.quickstep;
import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.anim.Interpolators.LINEAR; 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.QuickScrubController.QUICK_SWITCH_START_DURATION;
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL; 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_SCRUB;
@@ -35,17 +32,16 @@ import android.animation.ObjectAnimator;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context; import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit; import android.graphics.Matrix.ScaleToFit;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF; import android.graphics.RectF;
import android.metrics.LogMaker;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.SystemClock;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import android.support.annotation.WorkerThread; import android.support.annotation.WorkerThread;
import android.util.Log; import android.util.Log;
@@ -71,12 +67,9 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.ViewOnDrawExecutor; import com.android.launcher3.util.ViewOnDrawExecutor;
import com.android.quickstep.TouchConsumer.InteractionType; 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.model.ThumbnailData;
import com.android.systemui.shared.recents.utilities.RectFEvaluator; import com.android.systemui.shared.recents.utilities.RectFEvaluator;
import com.android.systemui.shared.system.InputConsumerController; 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.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TransactionCompat; import com.android.systemui.shared.system.TransactionCompat;
@@ -84,40 +77,6 @@ import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.StringJoiner; 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) @TargetApi(Build.VERSION_CODES.O)
public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName(); private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
@@ -230,17 +189,11 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper(); private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper();
private Matrix mTmpMatrix = new Matrix(); private Matrix mTmpMatrix = new Matrix();
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
private final MetricsLogger mMetricsLogger = new MetricsLogger();
WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs) { WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context) {
mContext = context; mContext = context;
mRunningTaskId = runningTaskInfo.id; mRunningTaskId = runningTaskInfo.id;
mTouchTimeMs = touchTimeMs; mInputConsumer.registerInputConsumer();
// Register the input consumer on the UI thread, to ensure that it runs after any pending
// unregister calls
mMainExecutor.execute(mInputConsumer::registerInputConsumer);
initStateCallbacks(); initStateCallbacks();
} }
@@ -370,8 +323,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
// For the duration of the gesture, lock the screen orientation to ensure that we do not // For the duration of the gesture, lock the screen orientation to ensure that we do not
// rotate mid-quickscrub // rotate mid-quickscrub
mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK); mLauncher.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
mRecentsView = mLauncher.getOverviewPanel(); mRecentsView = mLauncher.getOverviewPanel();
mQuickScrubController = mRecentsView.getQuickScrubController(); mQuickScrubController = mRecentsView.getQuickScrubController();
mLauncherLayoutListener = new LauncherLayoutListener(mLauncher); mLauncherLayoutListener = new LauncherLayoutListener(mLauncher);
@@ -464,26 +416,11 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
if (mLauncherDrawnCallback != null) { if (mLauncherDrawnCallback != null) {
mLauncherDrawnCallback.run(); mLauncherDrawnCallback.run();
} }
mLauncherFrameDrawnTime = SystemClock.uptimeMillis();
} }
private void initializeLauncherAnimationController() { private void initializeLauncherAnimationController() {
mLauncherLayoutListener.setHandler(this); mLauncherLayoutListener.setHandler(this);
onLauncherLayoutChanged(); 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) { public void updateInteractionType(@InteractionType int interactionType) {
@@ -505,8 +442,6 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
} }
private void onQuickInteractionStart() { private void onQuickInteractionStart() {
mLauncher.getStateManager().goToState(FAST_OVERVIEW,
mWasLauncherAlreadyVisible || mGestureStarted);
mQuickScrubController.onQuickScrubStart(false); mQuickScrubController.onQuickScrubStart(false);
} }
@@ -574,13 +509,8 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) { for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
if (app.mode == MODE_CLOSING) { if (app.mode == MODE_CLOSING) {
transaction.setMatrix(app.leash, mTmpMatrix) transaction.setMatrix(app.leash, mTmpMatrix)
.setWindowCrop(app.leash, mClipRect); .setWindowCrop(app.leash, mClipRect)
.show(app.leash);
if (app.isNotInRecents) {
transaction.setAlpha(app.leash, 1 - shift);
}
transaction.show(app.leash);
} }
} }
transaction.apply(); transaction.apply();
@@ -595,8 +525,9 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
mLauncherTransitionController.setPlayFraction(shift); mLauncherTransitionController.setPlayFraction(shift);
// Make sure the window follows the first task if it moves, e.g. during quick scrub. // Make sure the window follows the first task if it moves, e.g. during quick scrub.
View firstTask = mRecentsView.getPageAt(0); int firstTaskIndex = mRecentsView.getFirstTaskIndex();
int scrollForFirstTask = mRecentsView.getScrollForPage(0); View firstTask = mRecentsView.getPageAt(firstTaskIndex);
int scrollForFirstTask = mRecentsView.getScrollForPage(firstTaskIndex);
int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX()); int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX());
if (offsetFromFirstTask != 0) { if (offsetFromFirstTask != 0) {
synchronized (mTargetRect) { synchronized (mTargetRect) {
@@ -727,14 +658,13 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
/** Animates to the given progress, where 0 is the current app and 1 is overview. */ /** Animates to the given progress, where 0 is the current app and 1 is overview. */
private void animateToProgress(float progress, long duration) { private void animateToProgress(float progress, long duration) {
mIsGoingToHome = Float.compare(progress, 1) == 0;
ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration); ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
anim.setInterpolator(Interpolators.SCROLL); anim.setInterpolator(Interpolators.SCROLL);
anim.addListener(new AnimationSuccessListener() { anim.addListener(new AnimationSuccessListener() {
@Override @Override
public void onAnimationSuccess(Animator animator) { public void onAnimationSuccess(Animator animator) {
setStateOnUiThread(mIsGoingToHome ? setStateOnUiThread((Float.compare(mCurrentShift.value, 0) == 0)
STATE_SCALED_CONTROLLER_RECENTS : STATE_SCALED_CONTROLLER_APP); ? STATE_SCALED_CONTROLLER_APP : STATE_SCALED_CONTROLLER_RECENTS);
} }
}); });
anim.start(); anim.start();
@@ -755,7 +685,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
} }
private void invalidateHandler() { private void invalidateHandler() {
mCurrentShift.finishAnimation(); mCurrentShift.cancelAnimation();
if (mGestureEndCallback != null) { if (mGestureEndCallback != null) {
mGestureEndCallback.run(); mGestureEndCallback.run();
@@ -771,8 +701,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
mLauncherLayoutListener.close(false); mLauncherLayoutListener.close(false);
// Restore the requested orientation to the user preference after the gesture has ended // Restore the requested orientation to the user preference after the gesture has ended
mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_NONE); mLauncher.updateRequestedOrientation();
mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, false /* animate */); mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, false /* animate */);
} }
@@ -1,134 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.views;
import static com.android.launcher3.LauncherState.NORMAL;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
/**
* {@link RecentsView} used in Launcher activity
*/
public class LauncherRecentsView extends RecentsView<Launcher> implements Insettable {
private Bitmap mScrim;
private Paint mFadePaint;
private Shader mFadeShader;
private Matrix mFadeMatrix;
private boolean mScrimOnLeft;
public LauncherRecentsView(Context context) {
this(context, null);
}
public LauncherRecentsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LauncherRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
DeviceProfile dp = mActivity.getDeviceProfile();
Rect padding = getPadding(dp, getContext());
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
lp.bottomMargin = padding.bottom;
setLayoutParams(lp);
setPadding(padding.left, padding.top, padding.right, 0);
if (dp.isVerticalBarLayout()) {
boolean wasScrimOnLeft = mScrimOnLeft;
mScrimOnLeft = dp.isSeascape();
if (mScrim == null || wasScrimOnLeft != mScrimOnLeft) {
Drawable scrim = getContext().getDrawable(mScrimOnLeft
? R.drawable.recents_horizontal_scrim_left
: R.drawable.recents_horizontal_scrim_right);
if (scrim instanceof BitmapDrawable) {
mScrim = ((BitmapDrawable) scrim).getBitmap();
mFadePaint = new Paint();
mFadePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
mFadeShader = new BitmapShader(mScrim, TileMode.CLAMP, TileMode.REPEAT);
mFadeMatrix = new Matrix();
} else {
mScrim = null;
}
}
} else {
mScrim = null;
mFadePaint = null;
mFadeShader = null;
mFadeMatrix = null;
}
}
@Override
public void draw(Canvas canvas) {
if (mScrim == null) {
super.draw(canvas);
return;
}
final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
int length = mScrim.getWidth();
int height = getHeight();
int saveCount = canvas.getSaveCount();
int scrimLeft;
if (mScrimOnLeft) {
scrimLeft = getScrollX();
} else {
scrimLeft = getScrollX() + getWidth() - length;
}
canvas.saveLayer(scrimLeft, 0, scrimLeft + length, height, null, flags);
super.draw(canvas);
mFadeMatrix.setTranslate(scrimLeft, 0);
mFadeShader.setLocalMatrix(mFadeMatrix);
mFadePaint.setShader(mFadeShader);
canvas.drawRect(scrimLeft, 0, scrimLeft + length, height, mFadePaint);
canvas.restoreToCount(saveCount);
}
@Override
protected void onAllTasksRemoved() {
mActivity.getStateManager().goToState(NORMAL);
}
}
@@ -15,5 +15,5 @@
--> -->
<com.android.launcher3.graphics.ShadowDrawable <com.android.launcher3.graphics.ShadowDrawable
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_setting" android:src="@drawable/ic_info_no_shadow"
android:elevation="@dimen/drop_target_shadow_elevation" /> android:elevation="@dimen/drop_target_shadow_elevation" />
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project <!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -13,7 +13,8 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <shape xmlns:android="http://schemas.android.com/apk/res/android"
<solid android:color="?attr/popupColorPrimary" /> android:shape="rectangle">
<corners android:radius="2dp" /> <solid android:color="?android:attr/colorAccent" />
<size android:height="1dp" />
</shape> </shape>
+2 -3
View File
@@ -17,10 +17,9 @@ Copyright (C) 2016 The Android Open Source Project
android:width="@dimen/options_menu_icon_size" android:width="@dimen/options_menu_icon_size"
android:height="@dimen/options_menu_icon_size" android:height="@dimen/options_menu_icon_size"
android:viewportWidth="48.0" android:viewportWidth="48.0"
android:viewportHeight="48.0" android:viewportHeight="48.0">
android:tint="?android:attr/textColorPrimary" >
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="?android:attr/textColorPrimary"
android:pathData="M42.8,28.4l-3.88-2.9c0.06-0.5,0.08-1,0.08-1.52s-0.02-1.02-0.08-1.52l3.88-2.86c0.84-0.62,1.04-1.88, android:pathData="M42.8,28.4l-3.88-2.9c0.06-0.5,0.08-1,0.08-1.52s-0.02-1.02-0.08-1.52l3.88-2.86c0.84-0.62,1.04-1.88,
0.48-2.82l-3.2-5.52c-0.56-0.96-1.76-1.4-2.72-1l-4.28,1.82c-0.96-0.74-2.02-1.36-3.14-1.84l-0.54-4.4C29.28,4.8,28.28,4, 0.48-2.82l-3.2-5.52c-0.56-0.96-1.76-1.4-2.72-1l-4.28,1.82c-0.96-0.74-2.02-1.36-3.14-1.84l-0.54-4.4C29.28,4.8,28.28,4,
27.18,4h-6.36c-1.1,0-2.1,0.8-2.22,1.84l-0.52,4.38c-1.14,0.48-2.2,1.1-3.16,1.84l-4.28-1.82c-0.96-0.4-2.16,0.04-2.72, 27.18,4h-6.36c-1.1,0-2.1,0.8-2.22,1.84l-0.52,4.38c-1.14,0.48-2.2,1.1-3.16,1.84l-4.28-1.82c-0.96-0.4-2.16,0.04-2.72,
+9 -2
View File
@@ -29,13 +29,20 @@
<include layout="@layout/all_apps_rv_layout" /> <include layout="@layout/all_apps_rv_layout" />
<include layout="@layout/all_apps_fast_scroller" />
<include layout="@layout/all_apps_floating_header" /> <include layout="@layout/all_apps_floating_header" />
<!-- Note: we are reusing/repurposing a system attribute for search layout, because of a <!-- Note: we are reusing/repurposing a system attribute for search layout, because of a
platform bug, which prevents using custom attributes in <include> tag --> platform bug, which prevents using custom attributes in <include> tag -->
<include <include
android:id="@id/search_container_all_apps" android:id="@id/search_container_all_apps"
layout="@layout/search_container_all_apps"/> layout="?android:attr/keyboardLayout"/>
<include layout="@layout/all_apps_fast_scroller" /> <View
android:id="@+id/nav_bar_bg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:background="?attr/allAppsNavBarScrimColor" />
</com.android.launcher3.allapps.AllAppsContainerView> </com.android.launcher3.allapps.AllAppsContainerView>
+2 -1
View File
@@ -22,4 +22,5 @@
android:layout_below="@id/search_container_all_apps" android:layout_below="@id/search_container_all_apps"
android:clipToPadding="false" android:clipToPadding="false"
android:descendantFocusability="afterDescendants" android:descendantFocusability="afterDescendants"
android:focusable="true" /> android:focusable="true"
android:overScrollMode="never" />
+1
View File
@@ -35,6 +35,7 @@
android:textColor="?android:attr/textColorPrimary" android:textColor="?android:attr/textColorPrimary"
android:fontFamily="sans-serif" android:fontFamily="sans-serif"
launcher:layoutHorizontal="true" launcher:layoutHorizontal="true"
launcher:deferShadowGeneration="true"
launcher:iconDisplay="shortcut_popup" launcher:iconDisplay="shortcut_popup"
launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size" /> launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size" />
+11 -1
View File
@@ -32,8 +32,18 @@
android:gravity="center" android:gravity="center"
android:text="@string/remove_drop_target_label" /> android:text="@string/remove_drop_target_label" />
<!-- App Info -->
<com.android.launcher3.InfoDropTarget
android:id="@+id/info_target_text"
style="@style/DropTargetButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="@string/app_info_drop_target_label" />
<!-- Uninstall target --> <!-- Uninstall target -->
<com.android.launcher3.SecondaryDropTarget <com.android.launcher3.UninstallDropTarget
android:id="@+id/uninstall_target_text" android:id="@+id/uninstall_target_text"
style="@style/DropTargetButton" style="@style/DropTargetButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
+5
View File
@@ -44,6 +44,11 @@
layout="@layout/overview_panel" layout="@layout/overview_panel"
android:visibility="gone" /> android:visibility="gone" />
<com.android.launcher3.views.AllAppsScrim
android:id="@+id/all_apps_scrim"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- DO NOT CHANGE THE ID --> <!-- DO NOT CHANGE THE ID -->
<include <include
android:id="@+id/hotseat" android:id="@+id/hotseat"
+57 -3
View File
@@ -14,7 +14,61 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<Space <com.android.launcher3.uioverrides.OverviewPanel
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp" android:theme="@style/HomeScreenElementTheme"
android:layout_height="0dp" /> android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:gravity="top"
android:orientation="horizontal">
<TextView
android:id="@+id/wallpaper_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawablePadding="4dp"
android:drawableTop="@drawable/ic_wallpaper"
android:drawableTint="?attr/workspaceTextColor"
android:fontFamily="sans-serif-condensed"
android:gravity="center_horizontal"
android:stateListAnimator="@animator/overview_button_anim"
android:text="@string/wallpaper_button_text"
android:textAllCaps="true"
android:textColor="?attr/workspaceTextColor"
android:textSize="12sp" />
<TextView
android:id="@+id/widget_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawablePadding="4dp"
android:drawableTop="@drawable/ic_widget"
android:drawableTint="?attr/workspaceTextColor"
android:fontFamily="sans-serif-condensed"
android:gravity="center_horizontal"
android:stateListAnimator="@animator/overview_button_anim"
android:text="@string/widget_button_text"
android:textAllCaps="true"
android:textColor="?attr/workspaceTextColor"
android:textSize="12sp" />
<TextView
android:id="@+id/settings_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawablePadding="4dp"
android:drawableTop="@drawable/ic_setting"
android:drawableTint="?attr/workspaceTextColor"
android:fontFamily="sans-serif-condensed"
android:gravity="center_horizontal"
android:stateListAnimator="@animator/overview_button_anim"
android:text="@string/settings_button_text"
android:textAllCaps="true"
android:textColor="?attr/workspaceTextColor"
android:textSize="12sp" />
</com.android.launcher3.uioverrides.OverviewPanel>
+50 -20
View File
@@ -17,23 +17,53 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@id/search_container_all_apps" android:id="@id/search_container_all_apps"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/all_apps_search_bar_field_height" android:layout_height="@dimen/all_apps_search_bar_height"
android:layout_centerHorizontal="true" android:layout_gravity="center|top"
android:layout_gravity="top|center_horizontal" android:layout_marginBottom="-8dp"
android:layout_marginTop="8dp" android:gravity="center|bottom"
android:background="@drawable/bg_all_apps_searchbox" android:paddingLeft="@dimen/dynamic_grid_edge_margin"
android:elevation="1dp" android:paddingRight="@dimen/dynamic_grid_edge_margin"
android:focusableInTouchMode="true" android:saveEnabled="false" >
android:gravity="center"
android:hint="@string/all_apps_search_bar_hint" <!--
android:imeOptions="actionSearch|flagNoExtractUi" Note: The following relation should always be true so that the shadows are aligned properly
android:inputType="text|textNoSuggestions|textCapWords" search_box_input.layout_marginBottom
android:maxLines="1" == search_divider.layout_marginBottom
android:padding="8dp" == - (search_container.layout_marginBottom)
android:saveEnabled="false" >= 5dp
android:scrollHorizontally="true" -->
android:singleLine="true" <com.android.launcher3.ExtendedEditText
android:textColor="?android:attr/textColorSecondary" android:id="@+id/search_box_input"
android:textColorHint="@drawable/all_apps_search_hint" android:layout_width="match_parent"
android:textSize="16sp" android:layout_height="@dimen/all_apps_search_bar_field_height"
android:translationY="24dp" /> android:layout_gravity="bottom"
android:layout_marginBottom="8dp"
android:background="@android:color/transparent"
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:saveEnabled="false"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="?android:attr/textColorSecondary"
android:textColorHint="@drawable/all_apps_search_hint"
android:textSize="16sp" />
<!-- This needs to be a container with a view, to simulate a scrolling effect for the header.
We translate the header down, and its content up by the same amount, so that it gets
clipped by the parent, making it look like the divider was scrolled out of the view. -->
<FrameLayout
android:id="@+id/search_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom"
android:layout_marginBottom="8dp" >
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@drawable/all_apps_search_divider"/>
</FrameLayout>
</com.android.launcher3.allapps.search.AppsSearchContainerLayout>
+1
View File
@@ -34,6 +34,7 @@
android:fontFamily="sans-serif" android:fontFamily="sans-serif"
launcher:iconDisplay="shortcut_popup" launcher:iconDisplay="shortcut_popup"
launcher:layoutHorizontal="true" launcher:layoutHorizontal="true"
launcher:deferShadowGeneration="true"
android:focusable="false" /> android:focusable="false" />
<View <View
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?><!-- <?xml version="1.0" encoding="utf-8"?>
Copyright (C) 2018 The Android Open Source Project <!-- Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -13,17 +13,11 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<com.android.quickstep.RecentsRootView
<com.android.launcher3.graphics.GradientView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:id="@+id/gradient_bg"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
launcher:layout_ignoreInsets="true" />
<com.android.quickstep.FallbackRecentsView
xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@style/HomeScreenElementTheme"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false" />
</com.android.quickstep.RecentsRootView>
+17 -5
View File
@@ -20,6 +20,11 @@
android:orientation="vertical" android:orientation="vertical"
android:theme="?attr/widgetsTheme" > android:theme="?attr/widgetsTheme" >
<com.android.launcher3.graphics.GradientView
android:id="@+id/gradient_bg"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.android.launcher3.views.TopRoundedCornerView <com.android.launcher3.views.TopRoundedCornerView
android:id="@+id/container" android:id="@+id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -31,22 +36,29 @@
android:id="@+id/widgets_list_view" android:id="@+id/widgets_list_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" /> android:clipToPadding="false"
/>
<!-- Fast scroller popup --> <!-- Fast scroller popup -->
<TextView <TextView
android:id="@+id/fast_scroller_popup" android:id="@+id/fast_scroller_popup"
style="@style/FastScrollerPopup" style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true" android:layout_gravity="top|end"
android:layout_alignParentTop="true"
android:layout_marginEnd="@dimen/fastscroll_popup_margin" /> android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
<com.android.launcher3.views.RecyclerViewFastScroller <com.android.launcher3.views.RecyclerViewFastScroller
android:id="@+id/fast_scroller" android:id="@+id/fast_scroller"
android:layout_width="@dimen/fastscroll_width" android:layout_width="@dimen/fastscroll_width"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_alignParentEnd="true" android:layout_gravity="end"
android:layout_alignParentTop="true"
android:layout_marginEnd="@dimen/fastscroll_end_margin" /> android:layout_marginEnd="@dimen/fastscroll_end_margin" />
<View
android:id="@+id/nav_bar_bg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="bottom"
android:background="?attr/allAppsNavBarScrimColor"
android:focusable="false" />
</com.android.launcher3.views.TopRoundedCornerView> </com.android.launcher3.views.TopRoundedCornerView>
</com.android.launcher3.widget.WidgetsFullSheet> </com.android.launcher3.widget.WidgetsFullSheet>
+1
View File
@@ -42,6 +42,7 @@
android:textColor="?android:attr/textColorPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" android:textSize="16sp"
android:textAlignment="viewStart" android:textAlignment="viewStart"
launcher:deferShadowGeneration="true"
launcher:iconDisplay="widget_section" launcher:iconDisplay="widget_section"
launcher:iconSizeOverride="@dimen/widget_section_icon_size" launcher:iconSizeOverride="@dimen/widget_section_icon_size"
launcher:layoutHorizontal="true" /> launcher:layoutHorizontal="true" />
-1
View File
@@ -17,7 +17,6 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:focusable="true"
android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_bottom_padding" android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_bottom_padding"
android:paddingLeft="@dimen/dynamic_grid_cell_padding_x" android:paddingLeft="@dimen/dynamic_grid_cell_padding_x"
android:paddingRight="@dimen/dynamic_grid_cell_padding_x" android:paddingRight="@dimen/dynamic_grid_cell_padding_x"
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Werk"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Werk"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Werkprofiel"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Werkprofiel"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Kry werkprogramme hier"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Kry werkprogramme hier"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Elke werkprogram het \'n oranje kenteken en word deur jou organisasie veilig gehou. Skuif programme na jou Tuisskerm vir makliker toegang."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Bestuur deur jou organisasie"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Bestuur deur jou organisasie"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Kennisgewings en programme is af"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Kennisgewings en programme is af"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"ሥራ"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"ሥራ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"የሥራ መገለጫ"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"የሥራ መገለጫ"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"የስራ መተግበሪያዎችን እዚህ ያግኙ"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"የስራ መተግበሪያዎችን እዚህ ያግኙ"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"እያንዳንዱ የሥራ መተግበሪያ ብርቱካናማ ባጅ አለው እና በእርስዎ ድርጅት በኩል ደህንነቱ ተጠብቋል። ለቀለለ መዳረሻ መተግበሪያዎችን ወደ የእርስዎ መነሻ ማያ ገጽ ያንቀሳቅሱ።"</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"በእርስዎ ድርጅት የሚተዳደር"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"በእርስዎ ድርጅት የሚተዳደር"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"ማሳወቂያዎች እና መተግበሪያዎች ጠፍተዋል"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"ማሳወቂያዎች እና መተግበሪያዎች ጠፍተዋል"</string>
</resources> </resources>
+1 -2
View File
@@ -141,8 +141,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"للعمل"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"للعمل"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"الملف الشخصي للعمل"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"الملف الشخصي للعمل"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"البحث عن تطبيقات العمل هنا"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"البحث عن تطبيقات العمل هنا"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"يحتوي كل تطبيق للعمل على شارة برتقالية اللون ويظل تحت حماية مؤسستك. يمكنك نقل التطبيقات إلى شاشتك الرئيسية لتسهيل الوصول."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"ملف شخصي للعمل تديره مؤسستك"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"ملف شخصي للعمل تديره مؤسستك"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"الإشعارات والتطبيقات متوقفة."</string> <string name="work_mode_off_label" msgid="3194894777601421047">"الإشعارات والتطبيقات متوقفة."</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"İş"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"İş"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"İş profili"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"İş profili"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Burada iş tətbiqləri axtarın"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Burada iş tətbiqləri axtarın"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Təşkilatınız tərəfindən idarə olunur"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Təşkilatınız tərəfindən idarə olunur"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Bildiriş və tətbiqlər deaktivdir"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Bildiriş və tətbiqlər deaktivdir"</string>
</resources> </resources>
+1 -2
View File
@@ -138,8 +138,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil za Work"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil za Work"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Pronađite poslovne aplikacije ovde"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Pronađite poslovne aplikacije ovde"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Ovim upravlja organizacija"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Ovim upravlja organizacija"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Obaveštenja i aplikacije su isključeni"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Obaveštenja i aplikacije su isključeni"</string>
</resources> </resources>
+1 -2
View File
@@ -139,8 +139,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Праца"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Праца"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Працоўны профіль"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Працоўны профіль"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Знайдзіце працоўныя праграмы тут"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Знайдзіце працоўныя праграмы тут"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Кожная працоўная праграма мае аранжавы значок і знаходзіцца пад аховай вашай арганізацыі. Для больш простага доступу перамясціце праграмы на свой Галоўны экран."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Пад кіраваннем вашай арганізацыі"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Пад кіраваннем вашай арганізацыі"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Апавяшчэнні і праграмы выключаны"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Апавяшчэнні і праграмы выключаны"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Служебни"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Служебни"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Служебен потребителски профил"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Служебен потребителски профил"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Тук можете да намерите служебните приложения"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Тук можете да намерите служебните приложения"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Всяко служебно приложение има оранжева значка и организацията ви се грижи за сигурността му. За по-лесен достъп преместете приложенията на началния си екран."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Управлява се от организацията ви"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Управлява се от организацията ви"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Известията и приложенията са изключени"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Известията и приложенията са изключени"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"অফিস"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"অফিস"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"অফিসের প্রোফাইল"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"অফিসের প্রোফাইল"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"এখানে কাজের অ্যাপ্সগুলি খুঁজুন"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"এখানে কাজের অ্যাপ্সগুলি খুঁজুন"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"প্রতিটি কাজের অ্যাপে একটি করে কমলা ব্যাজ রয়েছে এবং অ্যাপগুলি আপনার প্রতিষ্ঠানের দ্বারা সুরক্ষিত। সহজে অ্যাক্সেস করার জন্য অ্যাপগুলি হোম স্ক্রিনে রাখুন।"</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"আপনার প্রতিষ্ঠানের দ্বারা পরিচালিত"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"আপনার প্রতিষ্ঠানের দ্বারা পরিচালিত"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"বিজ্ঞপ্তি এবং অ্যাপ বন্ধ আছে"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"বিজ্ঞপ্তি এবং অ্যাপ বন্ধ আছে"</string>
</resources> </resources>
+3 -4
View File
@@ -41,7 +41,7 @@
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Pretraži više aplikacija"</string> <string name="all_apps_search_market_message" msgid="1366263386197059176">"Pretraži više aplikacija"</string>
<string name="notifications_header" msgid="1404149926117359025">"Obavještenja"</string> <string name="notifications_header" msgid="1404149926117359025">"Obavještenja"</string>
<string name="out_of_space" msgid="4691004494942118364">"Na ovom početnom ekranu nema više prostora."</string> <string name="out_of_space" msgid="4691004494942118364">"Na ovom početnom ekranu nema više prostora."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora u ladici Omiljeno"</string> <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora u ladici Favoriti"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Spisak aplikacija"</string> <string name="all_apps_button_label" msgid="8130441508702294465">"Spisak aplikacija"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Početna"</string> <string name="all_apps_home_button_label" msgid="252062713717058851">"Početna"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string> <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
@@ -112,7 +112,7 @@
<string name="action_move" msgid="4339390619886385032">"Premjesti stavku"</string> <string name="action_move" msgid="4339390619886385032">"Premjesti stavku"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"Pomjeri stavku u red <xliff:g id="NUMBER_0">%1$s</xliff:g> kolonu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string> <string name="move_to_empty_cell" msgid="2833711483015685619">"Pomjeri stavku u red <xliff:g id="NUMBER_0">%1$s</xliff:g> kolonu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
<string name="move_to_position" msgid="6750008980455459790">"Pomjeri stavku na poziciju <xliff:g id="NUMBER">%1$s</xliff:g>"</string> <string name="move_to_position" msgid="6750008980455459790">"Pomjeri stavku na poziciju <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
<string name="move_to_hotseat_position" msgid="6295412897075147808">"Pomjeri stavku na poziciju <xliff:g id="NUMBER">%1$s</xliff:g> među omiljenim"</string> <string name="move_to_hotseat_position" msgid="6295412897075147808">"Pomjeri stavku na poziciju <xliff:g id="NUMBER">%1$s</xliff:g> među favoritima"</string>
<string name="item_moved" msgid="4606538322571412879">"Stavka je premještena"</string> <string name="item_moved" msgid="4606538322571412879">"Stavka je premještena"</string>
<string name="add_to_folder" msgid="9040534766770853243">"Dodaj u folder: <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="add_to_folder" msgid="9040534766770853243">"Dodaj u folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="add_to_folder_with_app" msgid="4534929978967147231">"Dodaj u folder sa aplikacijom <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="add_to_folder_with_app" msgid="4534929978967147231">"Dodaj u folder sa aplikacijom <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -138,8 +138,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Radni profil"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Radni profil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Pronađite poslovne aplikacije ovdje"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Pronađite poslovne aplikacije ovdje"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Svaka poslovna aplikacija ima narandžastu značku i osigurava je vaša organizacija. Premjestite aplikacije na Početni ekran, radi lakšeg pristupa."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Upravlja vaša organizacija"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Upravlja vaša organizacija"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifikacije i aplikacije su isključene"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Notifikacije i aplikacije su isključene"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Feina"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Feina"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil professional"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil professional"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Cerca aplicacions per a la feina aquí"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Cerca aplicacions per a la feina aquí"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Gestionat per la teva organització"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Gestionat per la teva organització"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Les notificacions i les aplicacions estan desactivades"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Les notificacions i les aplicacions estan desactivades"</string>
</resources> </resources>
+1 -2
View File
@@ -139,8 +139,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Pracovní"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Pracovní"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Pracovní profil"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Pracovní profil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Zde naleznete pracovní aplikace"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Zde naleznete pracovní aplikace"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Každý pracovní profil má oranžový odznak a je zabezpečen vaší organizací. Aplikace si můžete pro jednoduchost přesunout na plochu."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Spravováno vaší organizací"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Spravováno vaší organizací"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Oznámení a aplikace jsou vypnuty"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Oznámení a aplikace jsou vypnuty"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Arbejde"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Arbejde"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbejdsprofil"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbejdsprofil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find arbejdsapps her"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find arbejdsapps her"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Administreret af din organisation"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Administreret af din organisation"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Underretninger og apps er slået fra"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Underretninger og apps er slået fra"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Geschäftlich"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Geschäftlich"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbeitsprofil"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbeitsprofil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hier findest du Apps für die Arbeit"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hier findest du Apps für die Arbeit"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Wird von deiner Organisation verwaltet"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Wird von deiner Organisation verwaltet"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Benachrichtigungen und Apps sind deaktiviert"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Benachrichtigungen und Apps sind deaktiviert"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Εργασίας"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Εργασίας"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Προφίλ εργασίας"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Προφίλ εργασίας"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Βρείτε όλες τις εφαρμογές εργασίας εδώ"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Βρείτε όλες τις εφαρμογές εργασίας εδώ"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Κάθε εφαρμογή εργασίας φέρει ένα πορτοκαλί σήμα και διατηρείται ασφαλής από τον οργανισμό σας. Μετακινήστε τις εφαρμογές εργασίας στην Αρχική οθόνη, για να έχετε πιο εύκολη πρόσβαση."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Διαχειριζόμενο από τον οργανισμό σας"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Διαχειριζόμενο από τον οργανισμό σας"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Οι ειδοποιήσεις και οι εφαρμογές είναι απενεργοποιημένες"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Οι ειδοποιήσεις και οι εφαρμογές είναι απενεργοποιημένες"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Each work app has an orange badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Each work app has an orange badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Each work app has an orange badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Laborales"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Laborales"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Apps de trabajo"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Apps de trabajo"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Administrado por tu organización"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Administrado por tu organización"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Las notificaciones y las apps están desactivadas"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Las notificaciones y las apps están desactivadas"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Trabajo"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabajo"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Aplicaciones de trabajo"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Aplicaciones de trabajo"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Administrada por tu organización"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Administrada por tu organización"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Las notificaciones y las aplicaciones están desactivadas"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Las notificaciones y las aplicaciones están desactivadas"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Töö"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Töö"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Tööprofiil"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Tööprofiil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Töörakendused leiate siit"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Töörakendused leiate siit"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Igal töörakendusel on oranž märk ja teie organisatsioon tagab selle turvalisuse. Teisaldage rakendused avaekraanile, et neile oleks lihtsam juurde pääseda."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Haldab teie organisatsioon"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Haldab teie organisatsioon"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Märguanded ja rakendused on välja lülitatud"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Märguanded ja rakendused on välja lülitatud"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Lanekoak"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Lanekoak"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Laneko profila"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Laneko profila"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hemen dituzu laneko aplikazioak"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hemen dituzu laneko aplikazioak"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Laneko aplikazio bakoitzak bereizgarri laranja bat dauka eta erakundeak babesten du. Aplikazioak errazago atzitzeko, eraman itzazu hasierako pantailara."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Erakundeak kudeatzen du"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Erakundeak kudeatzen du"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Jakinarazpenak eta aplikazioak desaktibatuta daude"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Jakinarazpenak eta aplikazioak desaktibatuta daude"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"محل کار"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"محل کار"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"نمایه کاری"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"نمایه کاری"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"اینجا برنامه‌های کاری را پیدا کنید"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"اینجا برنامه‌های کاری را پیدا کنید"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"همه برنامه‌های کاری نشان نارنجی‌رنگی دارند و توسط سازمان شما امن نگه داشته می‌شود. برنامه‌های کاری را برای دسترسی آسان‌تر به صفحه اصلی انتقال دهید."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"توسط سازمانتان مدیریت می‌شود"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"توسط سازمانتان مدیریت می‌شود"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"اعلان‌ها و برنامه‌ها خاموش هستند"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"اعلان‌ها و برنامه‌ها خاموش هستند"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Työsovellukset"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Työsovellukset"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Työprofiili"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Työprofiili"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Etsi työsovelluksia tästä"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Etsi työsovelluksia tästä"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Kaikissa työsovelluksissa on oranssi merkki ja ne ovat organisaatiosi suojaamia. Voit siirtää työsovelluksia aloitusnäytölle käytön helpottamiseksi."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Organisaatiosi hallinnoima"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Organisaatiosi hallinnoima"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Ilmoitukset ja sovellukset ovat poissa käytöstä"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Ilmoitukset ja sovellukset ovat poissa käytöstä"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Travail"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Travail"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil professionnel"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil professionnel"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Trouvez ici des applications professionnelles"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Trouvez ici des applications professionnelles"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Géré par votre organisation"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Géré par votre organisation"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Les notifications et les applications sont désactivées"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Les notifications et les applications sont désactivées"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Professionnelles"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Professionnelles"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil professionnel"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil professionnel"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Retrouvez ici vos applications professionnelles"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Retrouvez ici vos applications professionnelles"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Géré par votre organisation"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Géré par votre organisation"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Les notifications et les applications sont désactivées"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Les notifications et les applications sont désactivées"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Traballo"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Traballo"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de traballo"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de traballo"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Buscar aplicacións do traballo aquí"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Buscar aplicacións do traballo aquí"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Perfil xestionado pola túa organización"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Perfil xestionado pola túa organización"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"As notificacións e as aplicacións están desactivadas"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"As notificacións e as aplicacións están desactivadas"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"કાર્યાલયની ઍપ"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"કાર્યાલયની ઍપ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"કાર્યાલયની પ્રોફાઇલ"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"કાર્યાલયની પ્રોફાઇલ"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"કાર્ય ઍપને અહીંથી મેળવો"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"કાર્ય ઍપને અહીંથી મેળવો"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"દરેક કાર્ય ઍપ પાસે એક નારંગી બૅજ હોય છે અને તમારી સંસ્થા દ્વારા તેને સુરક્ષિત રાખવામાં આવે છે. વધુ સરળ ઍક્સેસ માટે ઍપને તમારી હોમ સ્ક્રીન પર ખસેડો."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"તમારી સંસ્થા દ્વારા મેનેજ કરેલ"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"તમારી સંસ્થા દ્વારા મેનેજ કરેલ"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"નોટિફિકેશન અને ઍપ બંધ છે"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"નોટિફિકેશન અને ઍપ બંધ છે"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"काम से जुड़े ऐप"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"काम से जुड़े ऐप"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफ़ाइल"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफ़ाइल"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"काम से जुड़े सभी ऐप्लिकेशन यहां पाएं"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"काम से जुड़े सभी ऐप्लिकेशन यहां पाएं"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"काम से जुड़े हर ऐप्लिकेशन पर एक नारंगी रंग का बैज (निशान) होता है जिसकी सुरक्षा आपका संगठन करता है. आसानी से इस्तेमाल करने के लिए ऐप्लिकेशन को अपनी होम स्क्रीन पर ले जाएं."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"आपका संगठन प्रबंधित कर रहा है"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"आपका संगठन प्रबंधित कर रहा है"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"सूचनाएं और ऐप्लिकेशन बंद हैं"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"सूचनाएं और ऐप्लिकेशन बंद हैं"</string>
</resources> </resources>
+1 -2
View File
@@ -138,8 +138,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Posao"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Posao"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Radni profil"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Radni profil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Ovdje možete pronaći radne aplikacije"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Ovdje možete pronaći radne aplikacije"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Svaka radna aplikacija ima narančastu značku i štiti je vaša organizacija. Premjestite aplikacije na početni zaslon radi lakšeg pristupa."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Pod upravljanjem vaše organizacije"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Pod upravljanjem vaše organizacije"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Obavijesti i aplikacije isključeni su"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Obavijesti i aplikacije isključeni su"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Munkahelyi"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Munkahelyi"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Munkaprofil"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Munkaprofil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Itt kereshet munkahelyi alkalmazásokat"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Itt kereshet munkahelyi alkalmazásokat"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Az Ön szervezete kezeli"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Az Ön szervezete kezeli"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Az értesítések és az alkalmazások ki vannak kapcsolva"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Az értesítések és az alkalmazások ki vannak kapcsolva"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Աշխատանքային"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Աշխատանքային"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Աշխատանքային պրոֆիլ"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Աշխատանքային պրոֆիլ"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Գտեք աշխատանքային հավելվածներ այստեղ"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Գտեք աշխատանքային հավելվածներ այստեղ"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Աշխատանքային հավելվածները նշված են նարնջագույն նշանով, նման հավելվածների անվտանգությունը ապահովում է ձեր կազմակերպությունը։ Հարմարության համար աշխատանքային հավելվածները կարող եք տեղափոխել հիմնական էկրան։"</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Կառավարվում է ձեր կազմակերպության կողմից"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Կառավարվում է ձեր կազմակերպության կողմից"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Ծանուցումներն ու հավելվածներն անջատված են"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Ծանուցումներն ու հավելվածներն անջատված են"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Kantor"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Kantor"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Temukan aplikasi kerja di sini"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Temukan aplikasi kerja di sini"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Setiap aplikasi kerja memiliki badge oranye dan dibuat tetap aman oleh organisasi. Pindahkan aplikasi ke Layar utama untuk memudahkan akses."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Dikelola oleh organisasi"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Dikelola oleh organisasi"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Notifikasi dan aplikasi nonaktif"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Notifikasi dan aplikasi nonaktif"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Vinna"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Vinna"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Vinnusnið"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Vinnusnið"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hér finnurðu vinnuforrit"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hér finnurðu vinnuforrit"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Ö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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Stjórnað af fyrirtækinu þínu"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Stjórnað af fyrirtækinu þínu"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Slökkt er á tilkynningum og forritum"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Slökkt er á tilkynningum og forritum"</string>
</resources> </resources>
+1 -2
View File
@@ -137,8 +137,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Lavoro"</string> <string name="all_apps_work_tab" msgid="4884822796154055118">"Lavoro"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profilo di lavoro"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profilo di lavoro"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Qui puoi trovare le tue app di lavoro"</string> <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Qui puoi trovare le tue app di lavoro"</string>
<!-- no translation found for bottom_work_tab_user_education_body (2818107472360579152) --> <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"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."</string>
<skip />
<string name="work_mode_on_label" msgid="4781128097185272916">"Gestito dalla tua organizzazione"</string> <string name="work_mode_on_label" msgid="4781128097185272916">"Gestito dalla tua organizzazione"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"Le notifiche e le app non sono attive"</string> <string name="work_mode_off_label" msgid="3194894777601421047">"Le notifiche e le app non sono attive"</string>
</resources> </resources>

Some files were not shown because too many files have changed in this diff Show More