Merge "Highlight the tab for the first time" into ub-launcher3-master
diff --git a/build.gradle b/build.gradle
index 61c05e5..0030b8b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,12 +13,12 @@
apply plugin: 'com.google.protobuf'
android {
- compileSdkVersion 27
- buildToolsVersion '27.0.0'
+ compileSdkVersion 28
+ buildToolsVersion '28.0.0'
defaultConfig {
minSdkVersion 21
- targetSdkVersion 27
+ targetSdkVersion 28
versionCode 1
versionName "1.0"
@@ -102,7 +102,7 @@
jcenter()
}
-final String SUPPORT_LIBS_VERSION = '27.0.0-SNAPSHOT'
+final String SUPPORT_LIBS_VERSION = '28.0.0-SNAPSHOT'
dependencies {
compile "com.android.support:support-v4:${SUPPORT_LIBS_VERSION}"
compile "com.android.support:support-dynamic-animation:${SUPPORT_LIBS_VERSION}"
diff --git a/go/res/values-fa/strings.xml b/go/res/values-fa/strings.xml
index 8bc5256..f1584d9 100644
--- a/go/res/values-fa/strings.xml
+++ b/go/res/values-fa/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="long_press_widget_to_add" msgid="4001616142797446267">"برای انتخاب یک میانبر، لمس کنید و نگهدارید."</string>
- <string name="long_accessible_way_to_add" msgid="2725225828389948328">"برای انتخاب یک میانبر، دو ضربه سریع بزنید و نگهدارید یا از اقدامهای سفارشی استفاده کنید."</string>
+ <string name="long_accessible_way_to_add" msgid="2725225828389948328">"برای انتخاب میانبر، دو ضربه سریع بزنید و نگه دارید یا از کنشهای سفارشی استفاده کنید."</string>
<string name="widget_button_text" msgid="4221900832360456858">"میانبرها"</string>
<string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"میانبرهای <xliff:g id="NAME">%1$s</xliff:g>"</string>
</resources>
diff --git a/go/res/xml/device_profiles.xml b/go/res/xml/device_profiles.xml
index 487c026..16d7e13 100644
--- a/go/res/xml/device_profiles.xml
+++ b/go/res/xml/device_profiles.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-<profiles xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+<profiles xmlns:launcher="http://schemas.android.com/apk/res-auto" >
<profile
launcher:name="Go Device"
diff --git a/proguard.flags b/proguard.flags
index 987fb6f..b8cade5 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -97,6 +97,11 @@
# support jar.
-keep class android.support.v7.widget.RecyclerView { *; }
+# LauncherAppTransitionManager
+-keep class com.android.launcher3.LauncherAppTransitionManagerImpl {
+ public <init>(...);
+}
+
-keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** {
*;
}
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 08c740c4..02b4379 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
+ <uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index b3025ff..420ecef 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/drawable-hdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-hdpi/recents_horizontal_scrim_left.png
new file mode 100644
index 0000000..d4f995d
--- /dev/null
+++ b/quickstep/res/drawable-hdpi/recents_horizontal_scrim_left.png
Binary files differ
diff --git a/quickstep/res/drawable-hdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-hdpi/recents_horizontal_scrim_right.png
new file mode 100644
index 0000000..9013c1a
--- /dev/null
+++ b/quickstep/res/drawable-hdpi/recents_horizontal_scrim_right.png
Binary files differ
diff --git a/quickstep/res/drawable-mdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-mdpi/recents_horizontal_scrim_left.png
new file mode 100644
index 0000000..6e924ec
--- /dev/null
+++ b/quickstep/res/drawable-mdpi/recents_horizontal_scrim_left.png
Binary files differ
diff --git a/quickstep/res/drawable-mdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-mdpi/recents_horizontal_scrim_right.png
new file mode 100644
index 0000000..33d0edd
--- /dev/null
+++ b/quickstep/res/drawable-mdpi/recents_horizontal_scrim_right.png
Binary files differ
diff --git a/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_left.png
new file mode 100644
index 0000000..20c85e6
--- /dev/null
+++ b/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_left.png
Binary files differ
diff --git a/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_right.png
new file mode 100644
index 0000000..58a1ca0
--- /dev/null
+++ b/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_right.png
Binary files differ
diff --git a/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_left.png
new file mode 100644
index 0000000..9d3dc31
--- /dev/null
+++ b/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_left.png
Binary files differ
diff --git a/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_right.png
new file mode 100644
index 0000000..7fb248b
--- /dev/null
+++ b/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_right.png
Binary files differ
diff --git a/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_left.png
new file mode 100644
index 0000000..49ec7aa
--- /dev/null
+++ b/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_left.png
Binary files differ
diff --git a/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_right.png
new file mode 100644
index 0000000..a8922e2
--- /dev/null
+++ b/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_right.png
Binary files differ
diff --git a/quickstep/res/layout/longpress_options_menu.xml b/quickstep/res/layout/longpress_options_menu.xml
new file mode 100644
index 0000000..9cf0fcf
--- /dev/null
+++ b/quickstep/res/layout/longpress_options_menu.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.uioverrides.OptionsPopupView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="96dp"
+ android:background="?attr/popupColorPrimary"
+ android:elevation="@dimen/deep_shortcuts_elevation"
+ android:orientation="horizontal"
+ launcher:layout_ignoreInsets="true">
+
+ <FrameLayout
+ android:id="@+id/wallpaper_button"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:drawablePadding="4dp"
+ android:drawableTint="?android:attr/textColorPrimary"
+ android:drawableTop="@drawable/ic_wallpaper"
+ android:fontFamily="sans-serif-condensed"
+ android:gravity="center"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/wallpaper_button_text"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="12sp"/>
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/widget_button"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:drawablePadding="4dp"
+ android:drawableTint="?android:attr/textColorPrimary"
+ android:drawableTop="@drawable/ic_widget"
+ android:fontFamily="sans-serif-condensed"
+ android:gravity="center"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/widget_button_text"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="12sp"/>
+
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/settings_button"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:drawablePadding="4dp"
+ android:drawableTint="?android:attr/textColorPrimary"
+ android:drawableTop="@drawable/ic_setting"
+ android:fontFamily="sans-serif-condensed"
+ android:gravity="center"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/settings_button_text"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="12sp"/>
+
+ </FrameLayout>
+
+</com.android.launcher3.uioverrides.OptionsPopupView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 839d934..91b6aa3 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,23 +13,20 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.quickstep.TaskView
- xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.quickstep.TaskView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:elevation="4dp">
<com.android.quickstep.TaskThumbnailView
android:id="@+id/snapshot"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginTop="@dimen/task_thumbnail_top_margin"
- android:scaleType="matrix"
- android:background="@drawable/task_thumbnail_background"
- android:elevation="4dp" />
+ android:layout_marginTop="@dimen/task_thumbnail_top_margin" />
+
<ImageView
android:id="@+id/icon"
android:layout_width="@dimen/task_thumbnail_icon_size"
android:layout_height="@dimen/task_thumbnail_icon_size"
- android:layout_gravity="top|center_horizontal"
- android:elevation="5dp"/>
+ android:layout_gravity="top|center_horizontal" />
</com.android.quickstep.TaskView>
\ No newline at end of file
diff --git a/quickstep/res/drawable/task_thumbnail_background.xml b/quickstep/res/values/config.xml
similarity index 68%
copy from quickstep/res/drawable/task_thumbnail_background.xml
copy to quickstep/res/values/config.xml
index f1f48ac..94211c6 100644
--- a/quickstep/res/drawable/task_thumbnail_background.xml
+++ b/quickstep/res/values/config.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- 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
+ 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,
@@ -13,6 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
- <corners android:radius="2dp" />
-</shape>
+<resources>
+ <string name="task_overlay_factory_class" translatable="false"></string>
+
+</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 222a3f4..d8504f1 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -16,15 +16,25 @@
<resources>
+ <dimen name="options_menu_icon_size">24dp</dimen>
+
<dimen name="task_thumbnail_top_margin">24dp</dimen>
<dimen name="task_thumbnail_icon_size">48dp</dimen>
<dimen name="task_menu_background_radius">12dp</dimen>
+ <dimen name="task_corner_radius">2dp</dimen>
+ <dimen name="task_fade_length">20dp</dimen>
+ <dimen name="recents_page_spacing">10dp</dimen>
+
<dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
<dimen name="quickstep_fling_min_velocity">250dp</dimen>
- <dimen name="workspace_overview_offset_x">-30dp</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 -->
+ <dimen name="content_trans_y">25dp</dimen>
+ <dimen name="workspace_trans_y">80dp</dimen>
</resources>
diff --git a/res/layout/predictions_view.xml b/quickstep/res/values/override.xml
similarity index 69%
rename from res/layout/predictions_view.xml
rename to quickstep/res/values/override.xml
index 280290c..ba99d81 100644
--- a/res/layout/predictions_view.xml
+++ b/quickstep/res/values/override.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- 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.
@@ -13,7 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.launcher3.allapps.PredictionRowView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
\ No newline at end of file
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_transition_manager_class" translatable="false">com.android.launcher3.LauncherAppTransitionManagerImpl</string>
+</resources>
+
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
new file mode 100644
index 0000000..489e55b
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3;
+
+import android.animation.AnimatorSet;
+import android.os.Handler;
+
+import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+
+import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
+
+public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
+
+ AnimatorSet mAnimator;
+ private Launcher mLauncher;
+
+ LauncherAnimationRunner(Launcher launcher) {
+ mLauncher = launcher;
+ }
+
+ @Override
+ public void onAnimationCancelled() {
+ postAtFrontOfQueueAsynchronously(mLauncher.getWindow().getDecorView().getHandler(), () -> {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
new file mode 100644
index 0000000..31c195d
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
+import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber;
+import static com.android.systemui.shared.recents.utilities.Utilities.getSurface;
+import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+
+import com.android.launcher3.InsettableFrameLayout.LayoutParams;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.systemui.shared.system.ActivityCompat;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
+import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
+import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.TransactionCompat;
+import com.android.systemui.shared.system.WindowManagerWrapper;
+
+/**
+ * Manages the opening and closing app transitions from Launcher.
+ */
+public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManager {
+
+ private static final String TAG = "LauncherTransition";
+ private static final int REFRESH_RATE_MS = 16;
+
+ private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
+ "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
+
+ private static final int LAUNCHER_RESUME_START_DELAY = 150;
+ 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.
+ private static final float ALL_APPS_PROGRESS_START = 1.3059858f;
+ private static final float ALL_APPS_PROGRESS_SLIDE_END = 0.99581414f;
+
+ private final DragLayer mDragLayer;
+ private final Launcher mLauncher;
+ private final DeviceProfile mDeviceProfile;
+
+ private final float mContentTransY;
+ private final float mWorkspaceTransY;
+
+ private ImageView mFloatingView;
+ private boolean mIsRtl;
+
+ private Animator mCurrentAnimator;
+
+ public LauncherAppTransitionManagerImpl(Context context) {
+ mLauncher = Launcher.getLauncher(context);
+ mDragLayer = mLauncher.getDragLayer();
+ mDeviceProfile = mLauncher.getDeviceProfile();
+
+ mIsRtl = Utilities.isRtl(mLauncher.getResources());
+
+ Resources res = mLauncher.getResources();
+ mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
+ mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y);
+ }
+
+ private void setCurrentAnimator(Animator animator) {
+ if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
+ mCurrentAnimator.cancel();
+ }
+ mCurrentAnimator = animator;
+ }
+
+ /**
+ * @return A Bundle with remote animations that controls how the window of the opening
+ * targets are displayed.
+ */
+ @Override
+ public Bundle getActivityLaunchOptions(Launcher launcher, View v) {
+ if (hasControlRemoteAppTransitionPermission()) {
+ try {
+ RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) {
+ @Override
+ public void onAnimationStart(RemoteAnimationTargetCompat[] targets,
+ Runnable finishedCallback) {
+ // Post at front of queue ignoring sync barriers to make sure it gets
+ // processed before the next frame.
+ postAtFrontOfQueueAsynchronously(v.getHandler(), () -> {
+ mAnimator = new AnimatorSet();
+ setCurrentAnimator(mAnimator);
+ mAnimator.play(getLauncherAnimators(v));
+ mAnimator.play(getWindowAnimators(v, targets));
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Reset launcher to normal state
+ v.setVisibility(View.VISIBLE);
+ ((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView);
+
+ mDragLayer.setAlpha(1f);
+ mDragLayer.setTranslationY(0f);
+
+ View appsView = mLauncher.getAppsView();
+ appsView.setAlpha(1f);
+ appsView.setTranslationY(0f);
+
+ finishedCallback.run();
+ }
+ });
+ mAnimator.start();
+ // Because t=0 has the app icon in its original spot, we can skip the
+ // first frame and have the same movement one frame earlier.
+ mAnimator.setCurrentPlayTime(REFRESH_RATE_MS);
+ });
+ }
+ };
+
+ return ActivityOptionsCompat.makeRemoteAnimation(
+ new RemoteAnimationAdapterCompat(runner, 500, 380)).toBundle();
+ } catch (NoClassDefFoundError e) {
+ // Gracefully fall back to default launch options if the user's platform doesn't
+ // have the latest changes.
+ }
+ }
+ return getDefaultActivityLaunchOptions(launcher, v);
+ }
+
+ /**
+ * @return Animators that control the movements of the Launcher and icon of the opening target.
+ */
+ private AnimatorSet getLauncherAnimators(View v) {
+ AnimatorSet launcherAnimators = new AnimatorSet();
+ launcherAnimators.play(getLauncherContentAnimator(false /* show */));
+ launcherAnimators.play(getIconAnimator(v));
+ return launcherAnimators;
+ }
+
+ /**
+ * Content is everything on screen except the background and the floating view (if any).
+ *
+ * @param show If true: Animate the content so that it moves upwards and fades in.
+ * Else: Animate the content so that it moves downwards and fades out.
+ */
+ private AnimatorSet getLauncherContentAnimator(boolean show) {
+ AnimatorSet launcherAnimator = new AnimatorSet();
+
+ float[] alphas = show
+ ? new float[] {0, 1}
+ : new float[] {1, 0};
+ float[] trans = show
+ ? new float[] {mContentTransY, 0,}
+ : new float[] {0, mContentTransY};
+
+ if (mLauncher.isInState(LauncherState.ALL_APPS) && !mDeviceProfile.isVerticalBarLayout()) {
+ // All Apps in portrait mode is full screen, so we only animate AllAppsContainerView.
+ View appsView = mLauncher.getAppsView();
+ appsView.setAlpha(alphas[0]);
+ appsView.setTranslationY(trans[0]);
+
+ ObjectAnimator alpha = ObjectAnimator.ofFloat(appsView, View.ALPHA, alphas);
+ alpha.setDuration(217);
+ alpha.setInterpolator(Interpolators.LINEAR);
+ ObjectAnimator transY = ObjectAnimator.ofFloat(appsView, View.TRANSLATION_Y, trans);
+ transY.setInterpolator(Interpolators.AGGRESSIVE_EASE);
+ transY.setDuration(350);
+
+ launcherAnimator.play(alpha);
+ launcherAnimator.play(transY);
+ } else {
+ mDragLayer.setAlpha(alphas[0]);
+ mDragLayer.setTranslationY(trans[0]);
+
+ ObjectAnimator dragLayerAlpha = ObjectAnimator.ofFloat(mDragLayer, View.ALPHA, alphas);
+ dragLayerAlpha.setDuration(217);
+ dragLayerAlpha.setInterpolator(Interpolators.LINEAR);
+ ObjectAnimator dragLayerTransY = ObjectAnimator.ofFloat(mDragLayer, View.TRANSLATION_Y,
+ trans);
+ dragLayerTransY.setInterpolator(Interpolators.AGGRESSIVE_EASE);
+ dragLayerTransY.setDuration(350);
+
+ launcherAnimator.play(dragLayerAlpha);
+ launcherAnimator.play(dragLayerTransY);
+ }
+ return launcherAnimator;
+ }
+
+ /**
+ * @return Animator that controls the icon used to launch the target.
+ */
+ private AnimatorSet getIconAnimator(View v) {
+ boolean isBubbleTextView = v instanceof BubbleTextView;
+ mFloatingView = new ImageView(mLauncher);
+ if (isBubbleTextView) {
+ // Create a copy of the app icon
+ Bitmap iconBitmap = ((FastBitmapDrawable) ((BubbleTextView) v).getIcon()).getBitmap();
+ mFloatingView.setImageDrawable(new FastBitmapDrawable(iconBitmap));
+ }
+
+ // Position the floating view exactly on top of the original
+ Rect rect = new Rect();
+ mDragLayer.getDescendantRectRelativeToSelf(v, rect);
+ int viewLocationStart = mIsRtl
+ ? mDeviceProfile.widthPx - rect.right
+ : rect.left;
+ int viewLocationTop = rect.top;
+
+ if (isBubbleTextView) {
+ ((BubbleTextView) v).getIconBounds(rect);
+ }
+ LayoutParams lp = new LayoutParams(rect.width(), rect.height());
+ lp.ignoreInsets = true;
+ lp.setMarginStart(viewLocationStart + rect.left);
+ lp.topMargin = viewLocationTop + rect.top;
+ mFloatingView.setLayoutParams(lp);
+
+ // Swap the two views in place.
+ ((ViewGroup) mDragLayer.getParent()).addView(mFloatingView);
+ v.setVisibility(View.INVISIBLE);
+
+ AnimatorSet appIconAnimatorSet = new AnimatorSet();
+ // Animate the app icon to the center
+ float centerX = mDeviceProfile.widthPx / 2;
+ float centerY = mDeviceProfile.heightPx / 2;
+
+ float xPosition = mIsRtl
+ ? mDeviceProfile.widthPx - lp.getMarginStart() - rect.width()
+ : lp.getMarginStart();
+ float dX = centerX - xPosition - (lp.width / 2);
+ float dY = centerY - lp.topMargin - (lp.height / 2);
+
+ ObjectAnimator x = ObjectAnimator.ofFloat(mFloatingView, View.TRANSLATION_X, 0f, dX);
+ ObjectAnimator y = ObjectAnimator.ofFloat(mFloatingView, View.TRANSLATION_Y, 0f, dY);
+
+ // Adjust the duration to change the "curve" of the app icon to the center.
+ boolean isBelowCenterY = lp.topMargin < centerY;
+ x.setDuration(isBelowCenterY ? 500 : 233);
+ y.setDuration(isBelowCenterY ? 233 : 500);
+ appIconAnimatorSet.play(x);
+ appIconAnimatorSet.play(y);
+
+ // Scale the app icon to take up the entire screen. This simplifies the math when
+ // animating the app window position / scale.
+ float maxScaleX = mDeviceProfile.widthPx / (float) rect.width();
+ float maxScaleY = mDeviceProfile.heightPx / (float) rect.height();
+ float scale = Math.max(maxScaleX, maxScaleY);
+ ObjectAnimator sX = ObjectAnimator.ofFloat(mFloatingView, View.SCALE_X, 1f, scale);
+ ObjectAnimator sY = ObjectAnimator.ofFloat(mFloatingView, View.SCALE_Y, 1f, scale);
+ sX.setDuration(500);
+ sY.setDuration(500);
+ appIconAnimatorSet.play(sX);
+ appIconAnimatorSet.play(sY);
+
+ // Fade out the app icon.
+ ObjectAnimator alpha = ObjectAnimator.ofFloat(mFloatingView, View.ALPHA, 1f, 0f);
+ alpha.setStartDelay(17);
+ alpha.setDuration(33);
+ appIconAnimatorSet.play(alpha);
+
+ for (Animator a : appIconAnimatorSet.getChildAnimations()) {
+ a.setInterpolator(Interpolators.AGGRESSIVE_EASE);
+ }
+ return appIconAnimatorSet;
+ }
+
+ /**
+ * @return Animator that controls the window of the opening targets.
+ */
+ private ValueAnimator getWindowAnimators(View v, RemoteAnimationTargetCompat[] targets) {
+ Rect bounds = new Rect();
+ if (v instanceof BubbleTextView) {
+ ((BubbleTextView) v).getIconBounds(bounds);
+ } else {
+ mDragLayer.getDescendantRectRelativeToSelf(v, bounds);
+ }
+ int[] floatingViewBounds = new int[2];
+
+ Rect crop = new Rect();
+ Matrix matrix = new Matrix();
+
+ ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
+ appAnimator.setDuration(500);
+ appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ boolean isFirstFrame = true;
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final Surface surface = getSurface(mFloatingView);
+ final long frameNumber = surface != null ? getNextFrameNumber(surface) : -1;
+ if (frameNumber == -1) {
+ // Booo, not cool! Our surface got destroyed, so no reason to animate anything.
+ Log.w(TAG, "Failed to animate, surface got destroyed.");
+ return;
+ }
+ final float percent = animation.getAnimatedFraction();
+ final float easePercent = Interpolators.AGGRESSIVE_EASE.getInterpolation(percent);
+
+ // Calculate app icon size.
+ float iconWidth = bounds.width() * mFloatingView.getScaleX();
+ float iconHeight = bounds.height() * mFloatingView.getScaleY();
+
+ // Scale the app window to match the icon size.
+ float scaleX = iconWidth / mDeviceProfile.widthPx;
+ float scaleY = iconHeight / mDeviceProfile.heightPx;
+ float scale = Math.min(1f, Math.min(scaleX, scaleY));
+ matrix.setScale(scale, scale);
+
+ // Position the scaled window on top of the icon
+ int deviceWidth = mDeviceProfile.widthPx;
+ int deviceHeight = mDeviceProfile.heightPx;
+ float scaledWindowWidth = deviceWidth * scale;
+ float scaledWindowHeight = deviceHeight * scale;
+
+ float offsetX = (scaledWindowWidth - iconWidth) / 2;
+ float offsetY = (scaledWindowHeight - iconHeight) / 2;
+ mFloatingView.getLocationInWindow(floatingViewBounds);
+ float transX0 = floatingViewBounds[0] - offsetX;
+ float transY0 = floatingViewBounds[1] - offsetY;
+ matrix.postTranslate(transX0, transY0);
+
+ // Fade in the app window.
+ float alphaDelay = 0;
+ float alphaDuration = 50;
+ float alpha = getValue(0f, 1f, alphaDelay, alphaDuration,
+ appAnimator.getDuration() * percent, Interpolators.AGGRESSIVE_EASE);
+
+ // Animate the window crop so that it starts off as a square, and then reveals
+ // horizontally.
+ float cropHeight = deviceHeight * easePercent + deviceWidth * (1 - easePercent);
+ float initialTop = (deviceHeight - deviceWidth) / 2f;
+ crop.left = 0;
+ crop.top = (int) (initialTop * (1 - easePercent));
+ crop.right = deviceWidth;
+ crop.bottom = (int) (crop.top + cropHeight);
+
+ TransactionCompat t = new TransactionCompat();
+ for (RemoteAnimationTargetCompat target : targets) {
+ if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) {
+ t.setAlpha(target.leash, alpha);
+
+ // TODO: This isn't correct at the beginning of the animation, but better
+ // than nothing.
+ matrix.postTranslate(target.position.x, target.position.y);
+ t.setMatrix(target.leash, matrix);
+ t.setWindowCrop(target.leash, crop);
+ t.deferTransactionUntil(target.leash, surface, getNextFrameNumber(surface));
+ }
+ if (isFirstFrame) {
+ t.show(target.leash);
+ }
+ }
+ t.apply();
+
+ matrix.reset();
+ isFirstFrame = false;
+ }
+ });
+ return appAnimator;
+ }
+
+ /**
+ * Registers remote animations used when closing apps to home screen.
+ */
+ @Override
+ public void registerRemoteAnimations() {
+ if (hasControlRemoteAppTransitionPermission()) {
+ try {
+ RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
+ definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN,
+ new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(),
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+
+// TODO: App controlled transition for unlock to home TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER
+
+ new ActivityCompat(mLauncher).registerRemoteAnimations(definition);
+ } catch (NoClassDefFoundError e) {
+ // Gracefully fall back if the user's platform doesn't have the latest changes
+ }
+ }
+ }
+
+ /**
+ * @return Runner that plays when user goes to Launcher
+ * ie. pressing home, swiping up from nav bar.
+ */
+ private RemoteAnimationRunnerCompat getWallpaperOpenRunner() {
+ return new LauncherAnimationRunner(mLauncher) {
+ @Override
+ public void onAnimationStart(RemoteAnimationTargetCompat[] targets,
+ Runnable finishedCallback) {
+ Handler handler = mLauncher.getWindow().getDecorView().getHandler();
+ postAtFrontOfQueueAsynchronously(handler, () -> {
+ if (Utilities.getPrefs(mLauncher).getBoolean("pref_use_screenshot_animation",
+ true) && mLauncher.isInState(LauncherState.OVERVIEW)) {
+ // We use a separate transition for Overview mode.
+ setCurrentAnimator(null);
+ finishedCallback.run();
+ return;
+ }
+
+ mAnimator = new AnimatorSet();
+ setCurrentAnimator(mAnimator);
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finishedCallback.run();
+ }
+ });
+ mAnimator.play(getClosingWindowAnimators(targets));
+ mAnimator.play(getLauncherResumeAnimation());
+ mAnimator.start();
+ });
+ }
+ };
+ }
+
+ /**
+ * Animator that controls the transformations of the windows the targets that are closing.
+ */
+ private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] targets) {
+ Matrix matrix = new Matrix();
+ float height = mLauncher.getDeviceProfile().heightPx;
+ float width = mLauncher.getDeviceProfile().widthPx;
+ float endX = Utilities.isRtl(mLauncher.getResources()) ? -width : width;
+
+ ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
+ closingAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
+
+ closingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ boolean isFirstFrame = true;
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float percent = animation.getAnimatedFraction();
+ float currentPlayTime = percent * closingAnimator.getDuration();
+
+ float scale = getValue(1f, 0.8f, 0, 267, currentPlayTime,
+ Interpolators.AGGRESSIVE_EASE);
+ matrix.setScale(scale, scale);
+
+ float dX = getValue(0, endX, 0, 350, currentPlayTime,
+ Interpolators.AGGRESSIVE_EASE_IN_OUT);
+ float dY = (height - height * scale) / 2f;
+
+ TransactionCompat t = new TransactionCompat();
+ for (RemoteAnimationTargetCompat app : targets) {
+ if (app.mode == RemoteAnimationTargetCompat.MODE_CLOSING) {
+ t.setAlpha(app.leash, 1f - percent);
+ matrix.postTranslate(dX, dY);
+ matrix.postTranslate(app.position.x, app.position.y);
+ t.setMatrix(app.leash, matrix);
+ }
+ // TODO: Layer should be set only once, but there is possibly a race condition
+ // where WindowManager is also calling setLayer.
+ int layer = app.mode == RemoteAnimationTargetCompat.MODE_CLOSING
+ ? Integer.MAX_VALUE
+ : app.prefixOrderIndex;
+ t.setLayer(app.leash, layer);
+ if (isFirstFrame) {
+ t.show(app.leash);
+ }
+ }
+ t.apply();
+
+ matrix.reset();
+ isFirstFrame = false;
+ }
+ });
+ return closingAnimator;
+ }
+
+ /**
+ * @return Animator that modifies Launcher as a result from {@link #getWallpaperOpenRunner}.
+ */
+ private AnimatorSet getLauncherResumeAnimation() {
+ if (mLauncher.isInState(LauncherState.ALL_APPS)
+ || mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ AnimatorSet contentAnimator = getLauncherContentAnimator(true /* show */);
+ contentAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY);
+ return contentAnimator;
+ } else {
+ AnimatorSet workspaceAnimator = new AnimatorSet();
+ mLauncher.getWorkspace().setTranslationY(mWorkspaceTransY);
+ mLauncher.getWorkspace().setAlpha(0f);
+ workspaceAnimator.play(ObjectAnimator.ofFloat(mLauncher.getWorkspace(),
+ View.TRANSLATION_Y, mWorkspaceTransY, 0));
+ workspaceAnimator.play(ObjectAnimator.ofFloat(mLauncher.getWorkspace(), View.ALPHA,
+ 0, 1f));
+ workspaceAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY);
+ workspaceAnimator.setDuration(333);
+ workspaceAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+
+ // Animate the shelf in two parts: slide in, and overeshoot.
+ AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
+ // The shelf will start offscreen
+ final float startY = ALL_APPS_PROGRESS_START;
+ // And will end slightly pulled up, so that there is something to overshoot back to 1f.
+ final float slideEnd = ALL_APPS_PROGRESS_SLIDE_END;
+
+ allAppsController.setProgress(startY);
+
+ Animator allAppsSlideIn =
+ ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS, startY, slideEnd);
+ allAppsSlideIn.setStartDelay(LAUNCHER_RESUME_START_DELAY);
+ allAppsSlideIn.setDuration(317);
+ allAppsSlideIn.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+
+ Animator allAppsOvershoot =
+ ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS, slideEnd, 1f);
+ allAppsOvershoot.setDuration(153);
+ allAppsOvershoot.setInterpolator(Interpolators.OVERSHOOT_0);
+
+ AnimatorSet resumeLauncherAnimation = new AnimatorSet();
+ resumeLauncherAnimation.play(workspaceAnimator);
+ resumeLauncherAnimation.playSequentially(allAppsSlideIn, allAppsOvershoot);
+ return resumeLauncherAnimation;
+ }
+ }
+
+ private boolean hasControlRemoteAppTransitionPermission() {
+ return mLauncher.checkSelfPermission(CONTROL_REMOTE_APP_TRANSITION_PERMISSION)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * Helper method that allows us to get interpolated values for embedded
+ * animations with a delay and/or different duration.
+ */
+ private static float getValue(float start, float end, float delay, float duration,
+ float currentPlayTime, Interpolator i) {
+ float time = Math.max(0, currentPlayTime - delay);
+ float newPercent = Math.min(1f, time / duration);
+ newPercent = i.getInterpolation(newPercent);
+ return end * newPercent + start * (1 - newPercent);
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index 6395473..426fe35 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -83,7 +83,7 @@
@Override
public float getHoseatAlpha(Launcher launcher) {
- return launcher.getDeviceProfile().isVerticalBarLayout() ? 0 : 1;
+ return 0;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
index 356a144..fa09f23 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
@@ -26,6 +26,7 @@
import android.graphics.Rect;
import android.view.MotionEvent;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.dragndrop.DragLayer;
@@ -56,11 +57,7 @@
@Override
protected boolean isTransitionFlipped() {
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- Rect insets = mLauncher.getDragLayer().getInsets();
- return insets.left > insets.right;
- }
- return false;
+ return mLauncher.getDeviceProfile().isSeascape();
}
@Override
@@ -82,9 +79,10 @@
RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, sTempRect);
DragLayer dl = launcher.getDragLayer();
Rect insets = dl.getInsets();
+ DeviceProfile dp = launcher.getDeviceProfile();
- if (launcher.getDeviceProfile().isVerticalBarLayout()) {
- if (insets.left > insets.right) {
+ if (dp.isVerticalBarLayout()) {
+ if (dp.isSeascape()) {
return insets.left + sTempRect.left;
} else {
return dl.getWidth() - sTempRect.right + insets.right;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/IgnoreTouchesInQuickScrub.java b/quickstep/src/com/android/launcher3/uioverrides/IgnoreTouchesInQuickScrub.java
new file mode 100644
index 0000000..2d5eb5a
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/IgnoreTouchesInQuickScrub.java
@@ -0,0 +1,41 @@
+/*
+ * 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 android.view.MotionEvent;
+
+import com.android.launcher3.util.TouchController;
+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();
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java b/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java
new file mode 100644
index 0000000..c089d06
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java
@@ -0,0 +1,276 @@
+/*
+ * 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 android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Outline;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.widget.Toast;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.RevealOutlineAnimation;
+import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.graphics.GradientView;
+import com.android.launcher3.widget.WidgetsFullSheet;
+
+/**
+ * Popup shown on long pressing an empty space in launcher
+ */
+public class OptionsPopupView extends AbstractFloatingView implements OnClickListener {
+
+ private final float mOutlineRadius;
+ private final Launcher mLauncher;
+ private final PointF mTouchPoint = new PointF();
+
+ private final GradientView mGradientView;
+
+ protected Animator mOpenCloseAnimator;
+
+ public OptionsPopupView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public OptionsPopupView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius);
+ setClipToOutline(true);
+ setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius);
+ }
+ });
+
+ mLauncher = Launcher.getLauncher(context);
+
+ mGradientView = (GradientView) mLauncher.getLayoutInflater().inflate(
+ R.layout.widgets_bottom_sheet_scrim, mLauncher.getDragLayer(), false);
+ mGradientView.setProgress(1, false);
+ mGradientView.setAlpha(0);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ findViewById(R.id.wallpaper_button).setOnClickListener(this);
+ findViewById(R.id.widget_button).setOnClickListener(this);
+ findViewById(R.id.settings_button).setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view.getId() == R.id.wallpaper_button) {
+ mLauncher.onClickWallpaperPicker(null);
+ close(true);
+ } else if (view.getId() == R.id.widget_button) {
+ if (mLauncher.getPackageManager().isSafeMode()) {
+ Toast.makeText(mLauncher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
+ } else {
+ WidgetsFullSheet.show(mLauncher, true /* animated */);
+ close(true);
+ }
+ } else if (view.getId() == R.id.settings_button) {
+ mLauncher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
+ .setPackage(mLauncher.getPackageName())
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ close(true);
+ }
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() != MotionEvent.ACTION_DOWN) {
+ return false;
+ }
+ if (mLauncher.getDragLayer().isEventOverView(this, ev)) {
+ return false;
+ }
+ close(true);
+ return true;
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ if (animate) {
+ animateClose();
+ } else {
+ closeComplete();
+ }
+ }
+
+ protected void animateClose() {
+ if (!mIsOpen) {
+ return;
+ }
+ mIsOpen = false;
+
+ final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
+ closeAnim.setDuration(getResources().getInteger(R.integer.config_popupOpenCloseDuration));
+
+ // Rectangular reveal (reversed).
+ final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
+ .createRevealAnimator(this, true);
+ closeAnim.play(revealAnim);
+
+ Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0);
+ fadeOut.setInterpolator(Interpolators.DEACCEL);
+ closeAnim.play(fadeOut);
+
+ Animator gradientAlpha = ObjectAnimator.ofFloat(mGradientView, ALPHA, 0);
+ gradientAlpha.setInterpolator(Interpolators.DEACCEL);
+ closeAnim.play(gradientAlpha);
+
+ closeAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mOpenCloseAnimator = null;
+ closeComplete();
+ }
+ });
+ if (mOpenCloseAnimator != null) {
+ mOpenCloseAnimator.cancel();
+ }
+ mOpenCloseAnimator = closeAnim;
+ closeAnim.start();
+ }
+
+ /**
+ * Closes the popup without animation.
+ */
+ private void closeComplete() {
+ if (mOpenCloseAnimator != null) {
+ mOpenCloseAnimator.cancel();
+ mOpenCloseAnimator = null;
+ }
+ mIsOpen = false;
+ mLauncher.getDragLayer().removeView(this);
+ mLauncher.getDragLayer().removeView(mGradientView);
+ }
+
+ @Override
+ public void logActionCommand(int command) {
+ // TODO:
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_OPTIONS_POPUP) != 0;
+ }
+
+ private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
+ DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
+ Rect startRect = new Rect();
+ startRect.offset((int) (mTouchPoint.x - lp.x), (int) (mTouchPoint.y - lp.y));
+
+ Rect endRect = new Rect(0, 0, lp.width, lp.height);
+ if (getOutlineProvider() instanceof RevealOutlineAnimation) {
+ ((RevealOutlineAnimation) getOutlineProvider()).getOutline(endRect);
+ }
+
+ return new RoundedRectRevealOutlineProvider
+ (mOutlineRadius, mOutlineRadius, startRect, endRect);
+ }
+
+ private void animateOpen() {
+ mIsOpen = true;
+ final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
+ openAnim.setDuration(getResources().getInteger(R.integer.config_popupOpenCloseDuration));
+
+ final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
+ .createRevealAnimator(this, false);
+ openAnim.play(revealAnim);
+
+ Animator gradientAlpha = ObjectAnimator.ofFloat(mGradientView, ALPHA, 1);
+ gradientAlpha.setInterpolator(Interpolators.ACCEL);
+ openAnim.play(gradientAlpha);
+
+ mOpenCloseAnimator = openAnim;
+
+ openAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mOpenCloseAnimator = null;
+ }
+ });
+ openAnim.start();
+ }
+
+ public static void show(Launcher launcher, float x, float y) {
+ DragLayer dl = launcher.getDragLayer();
+ OptionsPopupView view = (OptionsPopupView) launcher.getLayoutInflater()
+ .inflate(R.layout.longpress_options_menu, dl, false);
+ DragLayer.LayoutParams lp = (DragLayer.LayoutParams) view.getLayoutParams();
+
+ int maxWidth = dl.getWidth();
+ int maxHeight = dl.getHeight();
+ if (x <= 0 || y <= 0 || x >= maxWidth || y >= maxHeight) {
+ x = maxWidth / 2;
+ y = maxHeight / 2;
+ }
+ view.mTouchPoint.set(x, y);
+
+ int height = lp.height;
+
+ // Find a good width;
+ int childCount = view.getChildCount();
+ int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+ int widthSpec = MeasureSpec.makeMeasureSpec(maxWidth / childCount, MeasureSpec.AT_MOST);
+ int maxChildWidth = 0;
+
+ for (int i = 0; i < childCount; i ++) {
+ View child = ((ViewGroup) view.getChildAt(i)).getChildAt(0);
+ child.measure(widthSpec, heightSpec);
+ maxChildWidth = Math.max(maxChildWidth, child.getMeasuredWidth());
+ }
+ Rect insets = dl.getInsets();
+ int margin = (int) (2 * view.getElevation());
+
+ int width = Math.min(maxWidth - insets.left - insets.right - 2 * margin,
+ maxChildWidth * childCount);
+ lp.width = width;
+
+ // Position is towards the finger
+ lp.customPosition = true;
+ lp.x = Utilities.boundToRange((int) (x - width / 2), insets.left + margin,
+ maxWidth - insets.right - width - margin);
+ lp.y = Utilities.boundToRange((int) (y - height / 2), insets.top + margin,
+ maxHeight - insets.bottom - height - margin);
+
+ launcher.getDragLayer().addView(view.mGradientView);
+ launcher.getDragLayer().addView(view);
+ view.animateOpen();
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index d2057cf..68f6eed 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -100,12 +100,12 @@
float scale = pageRect.height() / childHeight;
Rect insets = launcher.getDragLayer().getInsets();
- float halfHeight = ws.getHeight() / 2;
+ float halfHeight = ws.getExpectedHeight() / 2;
float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
float translationY = pageRect.top - childTop;
// Align the workspace horizontally centered with the task rect
- float halfWidth = ws.getWidth() / 2;
+ float halfWidth = ws.getExpectedWidth() / 2;
float childCenter = halfWidth -
scale * (halfWidth - ws.getPaddingLeft() - insets.left - childWidth / 2);
float translationX = pageRect.exactCenterX() - childCenter;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index e848688..b4f40c2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -16,35 +16,39 @@
package com.android.launcher3.uioverrides;
-import android.content.Intent;
+import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.PointF;
+import android.os.Bundle;
+import android.view.View;
import android.view.View.AccessibilityDelegate;
-import android.widget.PopupMenu;
-import android.widget.Toast;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.BitmapRenderer;
import com.android.launcher3.util.TouchController;
-import com.android.launcher3.widget.WidgetsFullSheet;
import com.android.quickstep.RecentsView;
import com.android.systemui.shared.recents.view.RecentsTransition;
public class UiFactory {
+ private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
+ "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
+
public static final boolean USE_HARDWARE_BITMAP = false; // FeatureFlags.IS_DOGFOOD_BUILD;
public static TouchController[] createTouchControllers(Launcher launcher) {
if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) {
- return new TouchController[]{
+ return new TouchController[] {
+ new IgnoreTouchesInQuickScrub(),
new EdgeSwipeController(launcher),
new TwoStepSwipeController(launcher),
new OverviewSwipeController(launcher)};
} else {
- return new TouchController[]{
+ return new TouchController[] {
+ new IgnoreTouchesInQuickScrub(),
new TwoStepSwipeController(launcher),
new OverviewSwipeController(launcher)};
}
@@ -60,31 +64,8 @@
new RecentsViewStateController(launcher)};
}
- public static void onWorkspaceLongPress(Launcher launcher) {
- PopupMenu menu = new PopupMenu(launcher.getApplicationContext(),
- launcher.getWorkspace().getPageIndicator());
-
- menu.getMenu().add(R.string.wallpaper_button_text).setOnMenuItemClickListener((i) -> {
- launcher.onClickWallpaperPicker(null);
- return true;
- });
- menu.getMenu().add(R.string.widget_button_text).setOnMenuItemClickListener((i) -> {
- if (launcher.getPackageManager().isSafeMode()) {
- Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
- } else {
- WidgetsFullSheet.show(launcher, true /* animated */);
- }
- return true;
- });
- if (launcher.hasSettings()) {
- menu.getMenu().add(R.string.settings_button_text).setOnMenuItemClickListener((i) -> {
- launcher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
- .setPackage(launcher.getPackageName())
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
- return true;
- });
- }
- menu.show();
+ public static void onWorkspaceLongPress(Launcher launcher, PointF touchPoint) {
+ OptionsPopupView.show(launcher, touchPoint.x, touchPoint.y);
}
public static Bitmap createFromRenderer(int width, int height, boolean forceSoftwareRenderer,
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
index 92a09dd..8533502 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
@@ -76,7 +76,7 @@
mTranslateXPage0 = scale[1];
mTranslateXPage1 = OverviewState
.getScaleAndTranslationForPageRect(mLauncher,
- getResources().getDimension(R.dimen.workspace_overview_offset_x),
+ getResources().getDimension(R.dimen.workspace_overview_offset_x) / scale[0],
mTempRect)[1];
mExtraScrollShift = 0;
diff --git a/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
new file mode 100644
index 0000000..aa210b8
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.support.annotation.WorkerThread;
+
+import com.android.launcher3.states.InternalStateHandler;
+import com.android.quickstep.TouchInteractionService.InteractionType;
+
+public abstract class BaseSwipeInteractionHandler extends InternalStateHandler {
+
+ protected Runnable mGestureEndCallback;
+
+ public void setGestureEndCallback(Runnable gestureEndCallback) {
+ mGestureEndCallback = gestureEndCallback;
+ }
+
+ public void reset() {}
+
+ @WorkerThread
+ public abstract void onGestureStarted();
+
+ @WorkerThread
+ public abstract void onGestureEnded(float endVelocity);
+
+ public abstract void updateInteractionType(@InteractionType int interactionType);
+
+ public abstract void onQuickScrubEnd();
+
+ public abstract void onQuickScrubProgress(float progress);
+
+ @WorkerThread
+ public abstract void updateDisplacement(float displacement);
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
new file mode 100644
index 0000000..2854342
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.graphics.Rect;
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+
+/**
+ * Floating view which shows the task snapshot allowing it to be dragged and placed.
+ */
+public class LauncherLayoutListener extends AbstractFloatingView implements Insettable {
+
+ private final Launcher mLauncher;
+ private final WindowTransformSwipeHandler mHandler;
+
+ public LauncherLayoutListener(Launcher launcher, WindowTransformSwipeHandler handler) {
+ super(launcher, null);
+ mLauncher = launcher;
+ mHandler = handler;
+ setVisibility(INVISIBLE);
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ requestLayout();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ mHandler.onLauncherLayoutChanged();
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ return false;
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ // We dont suupport animate.
+ mLauncher.getDragLayer().removeView(this);
+ mHandler.layoutListenerClosed();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(1, 1);
+ }
+
+ @Override
+ public void logActionCommand(int command) {
+ // We should probably log the weather
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_QUICKSTEP_PREVIEW) != 0;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java
index e3c3a1b..fae9b66 100644
--- a/quickstep/src/com/android/quickstep/MotionEventQueue.java
+++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java
@@ -18,6 +18,8 @@
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_MOVE;
+import android.annotation.TargetApi;
+import android.os.Build;
import android.view.Choreographer;
import android.view.MotionEvent;
@@ -29,25 +31,64 @@
/**
* Helper class for batching input events
*/
-public class MotionEventQueue implements Runnable {
+@TargetApi(Build.VERSION_CODES.O)
+public class MotionEventQueue {
+
+ private final EventArray mEmptyArray = new EventArray();
+ private final Object mExecutionLock = new Object();
// We use two arrays and swap the current index when one array is being consumed
private final EventArray[] mArrays = new EventArray[] {new EventArray(), new EventArray()};
private int mCurrentIndex = 0;
- private final Choreographer mChoreographer;
- private final Consumer<MotionEvent> mConsumer;
+ private final Runnable mMainFrameCallback = this::frameCallbackForMainChoreographer;
+ private final Runnable mInterimFrameCallback = this::frameCallbackForInterimChoreographer;
+
+ private final Choreographer mMainChoreographer;
+
+ private Consumer<MotionEvent> mConsumer;
+
+ private Choreographer mInterimChoreographer;
+ private Choreographer mCurrentChoreographer;
+
+ private Runnable mCurrentRunnable;
public MotionEventQueue(Choreographer choreographer, Consumer<MotionEvent> consumer) {
- mChoreographer = choreographer;
+ mMainChoreographer = choreographer;
mConsumer = consumer;
+
+ mCurrentChoreographer = mMainChoreographer;
+ mCurrentRunnable = mMainFrameCallback;
+ }
+
+ public void setConsumer(Consumer<MotionEvent> consumer) {
+ synchronized (mExecutionLock) {
+ mConsumer = consumer;
+ }
+ }
+
+ public void setInterimChoreographer(Choreographer choreographer) {
+ synchronized (mExecutionLock) {
+ synchronized (mArrays) {
+ mInterimChoreographer = choreographer;
+ if (choreographer == null) {
+ mCurrentChoreographer = mMainChoreographer;
+ mCurrentRunnable = mMainFrameCallback;
+ } else {
+ mCurrentChoreographer = mInterimChoreographer;
+ mCurrentRunnable = mInterimFrameCallback;
+ }
+
+ ChoreographerCompat.postInputFrame(mCurrentChoreographer, mCurrentRunnable);
+ }
+ }
}
public void queue(MotionEvent event) {
synchronized (mArrays) {
EventArray array = mArrays[mCurrentIndex];
if (array.isEmpty()) {
- ChoreographerCompat.postInputFrame(mChoreographer, this);
+ ChoreographerCompat.postInputFrame(mCurrentChoreographer, mCurrentRunnable);
}
int eventAction = event.getAction();
@@ -61,21 +102,33 @@
}
}
- @Override
- public void run() {
- EventArray array = swapAndGetCurrentArray();
- int size = array.size();
- for (int i = 0; i < size; i++) {
- MotionEvent event = array.get(i);
- mConsumer.accept(event);
- event.recycle();
- }
- array.clear();
- array.lastEventAction = ACTION_CANCEL;
+ private void frameCallbackForMainChoreographer() {
+ runFor(mMainChoreographer);
}
- private EventArray swapAndGetCurrentArray() {
+ private void frameCallbackForInterimChoreographer() {
+ runFor(mInterimChoreographer);
+ }
+
+ private void runFor(Choreographer caller) {
+ synchronized (mExecutionLock) {
+ EventArray array = swapAndGetCurrentArray(caller);
+ int size = array.size();
+ for (int i = 0; i < size; i++) {
+ MotionEvent event = array.get(i);
+ mConsumer.accept(event);
+ event.recycle();
+ }
+ array.clear();
+ array.lastEventAction = ACTION_CANCEL;
+ }
+ }
+
+ private EventArray swapAndGetCurrentArray(Choreographer caller) {
synchronized (mArrays) {
+ if (caller != mCurrentChoreographer) {
+ return mEmptyArray;
+ }
EventArray current = mArrays[mCurrentIndex];
mCurrentIndex = mCurrentIndex ^ 1;
return current;
diff --git a/quickstep/src/com/android/quickstep/MultiStateCallback.java b/quickstep/src/com/android/quickstep/MultiStateCallback.java
index cca2729..7a74176 100644
--- a/quickstep/src/com/android/quickstep/MultiStateCallback.java
+++ b/quickstep/src/com/android/quickstep/MultiStateCallback.java
@@ -55,4 +55,8 @@
public void addCallback(int stateMask, Runnable callback) {
mCallbacks.put(stateMask, callback);
}
+
+ public int getState() {
+ return mState;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 168c1fe..e2abd59 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -15,6 +15,11 @@
*/
package com.android.quickstep;
+import static com.android.quickstep.TouchInteractionService.INTERACTION_NORMAL;
+import static com.android.quickstep.TouchInteractionService.INTERACTION_QUICK_SCRUB;
+import static com.android.quickstep.TouchInteractionService.INTERACTION_QUICK_SWITCH;
+import static com.android.quickstep.TouchInteractionService.isInteractionQuick;
+
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.RectEvaluator;
@@ -27,7 +32,6 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Build;
-import android.os.Handler;
import android.os.UserHandle;
import android.support.annotation.UiThread;
import android.view.View;
@@ -37,16 +41,17 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
+import com.android.launcher3.Launcher.OnResumeCallback;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.states.InternalStateHandler;
-import com.android.launcher3.uioverrides.RecentsViewStateController;
+import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.views.AllAppsScrim;
+import com.android.quickstep.TouchInteractionService.InteractionType;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -54,14 +59,14 @@
import com.android.systemui.shared.system.WindowManagerWrapper;
@TargetApi(Build.VERSION_CODES.O)
-public class NavBarSwipeInteractionHandler extends InternalStateHandler {
+public class NavBarSwipeInteractionHandler extends BaseSwipeInteractionHandler implements
+ OnResumeCallback {
private static final int STATE_LAUNCHER_READY = 1 << 0;
private static final int STATE_ACTIVITY_MULTIPLIER_COMPLETE = 1 << 4;
private static final int STATE_SCALED_SNAPSHOT_RECENTS = 1 << 5;
private static final int STATE_SCALED_SNAPSHOT_APP = 1 << 6;
- private static final long RECENTS_VIEW_VISIBILITY_DURATION = 150;
private static final long MAX_SWIPE_DURATION = 200;
private static final long MIN_SWIPE_DURATION = 80;
private static final int QUICK_SWITCH_SNAP_DURATION = 120;
@@ -87,7 +92,7 @@
// animated to 1, so allow for a smooth transition.
private final AnimatedFloat mActivityMultiplier = new AnimatedFloat(this::updateFinalShift);
- private final Task mRunningTask;
+ private final int mRunningTaskId;
private final Context mContext;
private final MultiStateCallback mStateCallback;
@@ -95,28 +100,25 @@
private Launcher mLauncher;
private SnapshotDragView mDragView;
private RecentsView mRecentsView;
- private RecentsViewStateController mStateController;
private QuickScrubController mQuickScrubController;
private Hotseat mHotseat;
- private AllAppsScrim mAllAppsScrim;
+
+ private boolean mWasLauncherAlreadyVisible;
private boolean mLauncherReady;
private boolean mTouchEndHandled;
private float mCurrentDisplacement;
- private @TouchInteractionService.InteractionType int mInteractionType;
+
+ private @InteractionType int mInteractionType;
private boolean mStartedQuickScrubFromHome;
private Bitmap mTaskSnapshot;
NavBarSwipeInteractionHandler(RunningTaskInfo runningTaskInfo, Context context,
- @TouchInteractionService.InteractionType int interactionType) {
- // TODO: We need a better way for this
- TaskKey taskKey = new TaskKey(runningTaskInfo.id, 0, null, UserHandle.myUserId(), 0);
- mRunningTask = new Task(taskKey, null, null, "", "", Color.BLACK, Color.BLACK,
- true, false, false, false, null, 0, null, false);
-
+ @InteractionType int interactionType) {
mContext = context;
mInteractionType = interactionType;
+ mRunningTaskId = runningTaskInfo.id;
WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
@@ -182,13 +184,13 @@
}
@Override
- protected void init(Launcher launcher, boolean alreadyOnHome) {
+ protected boolean init(Launcher launcher, boolean alreadyOnHome) {
+ launcher.setOnResumeCallback(this);
mLauncher = launcher;
mRecentsView = launcher.getOverviewPanel();
- mRecentsView.showTask(mRunningTask);
- mStateController = mRecentsView.getStateController();
+ mRecentsView.showTask(mRunningTaskId);
mHotseat = mLauncher.getHotseat();
- mAllAppsScrim = mLauncher.findViewById(R.id.all_apps_scrim);
+ mWasLauncherAlreadyVisible = alreadyOnHome;
AbstractFloatingView.closeAllOpenViews(mLauncher, alreadyOnHome);
mLauncher.getStateManager().goToState(LauncherState.OVERVIEW, alreadyOnHome);
@@ -198,17 +200,8 @@
mDragView.setPivotX(0);
mDragView.setPivotY(0);
- boolean interactionIsQuick
- = mInteractionType == TouchInteractionService.INTERACTION_QUICK_SCRUB
- || mInteractionType == TouchInteractionService.INTERACTION_QUICK_SWITCH;
- mStartedQuickScrubFromHome = alreadyOnHome && interactionIsQuick;
- if (interactionIsQuick) {
- mQuickScrubController = mRecentsView.getQuickScrubController();
- mQuickScrubController.onQuickScrubStart(mStartedQuickScrubFromHome);
- animateToProgress(1f, MAX_SWIPE_DURATION);
- if (mStartedQuickScrubFromHome) {
- mDragView.setVisibility(View.INVISIBLE);
- }
+ if (isInteractionQuick(mInteractionType)) {
+ updateUiForQuickScrub();
}
// Optimization
@@ -217,6 +210,34 @@
mLauncher.getAppsView().setVisibility(View.GONE);
}
TraceHelper.partitionSection("TouchInt", "Launcher on new intent");
+ return false;
+ }
+
+ public void updateInteractionType(@InteractionType int interactionType) {
+ Preconditions.assertUIThread();
+ if (mInteractionType != INTERACTION_NORMAL) {
+ throw new IllegalArgumentException(
+ "Can't change interaction type from " + mInteractionType);
+ }
+ if (!isInteractionQuick(interactionType)) {
+ throw new IllegalArgumentException(
+ "Can't change interaction type to " + interactionType);
+ }
+ mInteractionType = interactionType;
+
+ if (mLauncher != null) {
+ updateUiForQuickScrub();
+ }
+ }
+
+ private void updateUiForQuickScrub() {
+ mStartedQuickScrubFromHome = mWasLauncherAlreadyVisible;
+ mQuickScrubController = mRecentsView.getQuickScrubController();
+ mQuickScrubController.onQuickScrubStart(mStartedQuickScrubFromHome);
+ animateToProgress(1f, MAX_SWIPE_DURATION);
+ if (mStartedQuickScrubFromHome) {
+ mDragView.setVisibility(View.INVISIBLE);
+ }
}
@UiThread
@@ -242,11 +263,10 @@
}
float shift = mCurrentShift.value * mActivityMultiplier.value;
- int hotseatSize = getHotseatSize();
- float hotseatTranslation = (1 - shift) * hotseatSize;
- mHotseat.setTranslationY(hotseatTranslation);
- mAllAppsScrim.setTranslationY(hotseatTranslation);
+ AllAppsTransitionController controller = mLauncher.getAllAppsController();
+ float range = getHotseatSize() / controller.getShiftRange();
+ controller.setProgress(1 + (1 - shift) * range);
mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
@@ -266,8 +286,11 @@
? mHotseat.getWidth() : mHotseat.getHeight();
}
+ @Override
+ public void onGestureStarted() { }
+
@UiThread
- public void endTouch(float endVelocity) {
+ public void onGestureEnded(float endVelocity) {
if (mTouchEndHandled) {
return;
}
@@ -313,45 +336,51 @@
@UiThread
private void resumeLastTask() {
- // TODO: We need a better way for this
- TaskKey key = mRunningTask.key;
RecentsTaskLoadPlan loadPlan = RecentsModel.getInstance(mContext).getLastLoadPlan();
if (loadPlan != null) {
- Task task = loadPlan.getTaskStack().findTaskWithId(key.id);
+ Task task = loadPlan.getTaskStack().findTaskWithId(mRunningTaskId);
if (task != null) {
- key = task.key;
+ ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
+ ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(task.key, opts,
+ null, null);
}
}
+ }
- ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
- ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(key, opts, null, null);
+ public void reset() {
+ mCurrentShift.cancelAnimation();
+ if (mGestureEndCallback != null) {
+ mGestureEndCallback.run();
+ }
}
private void cleanupLauncher() {
+ reset();
+
// TODO: These should be done as part of ActivityOptions#OnAnimationStarted
- mHotseat.setTranslationY(0);
- mAllAppsScrim.setTranslationY(0);
+ mLauncher.getStateManager().reapplyState();
mLauncher.setOnResumeCallback(() -> mDragView.close(false));
}
private void onAnimationToLauncherComplete() {
+ reset();
+
mDragView.close(false);
View currentRecentsPage = mRecentsView.getPageAt(mRecentsView.getCurrentPage());
if (currentRecentsPage instanceof TaskView) {
((TaskView) currentRecentsPage).animateIconToScale(1f);
}
- if (mInteractionType == TouchInteractionService.INTERACTION_QUICK_SWITCH) {
+ if (mInteractionType == INTERACTION_QUICK_SWITCH) {
for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
- // TODO: Match the keys directly
- if (taskView.getTask().key.id != mRunningTask.key.id) {
+ if (taskView.getTask().key.id != mRunningTaskId) {
mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION);
taskView.postDelayed(() -> {taskView.launchTask(true);},
QUICK_SWITCH_SNAP_DURATION);
break;
}
}
- } else if (mInteractionType == TouchInteractionService.INTERACTION_QUICK_SCRUB) {
+ } else if (mInteractionType == INTERACTION_QUICK_SCRUB) {
if (mQuickScrubController != null) {
mQuickScrubController.snapToPageForCurrentQuickScrubSection();
}
@@ -361,12 +390,16 @@
public void onQuickScrubEnd() {
if (mQuickScrubController != null) {
mQuickScrubController.onQuickScrubEnd();
+ } else {
+ // TODO:
}
}
public void onQuickScrubProgress(float progress) {
if (mQuickScrubController != null) {
mQuickScrubController.onQuickScrubProgress(progress);
+ } else {
+ // TODO:
}
}
}
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index f4c2055..3e65ffe 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -55,7 +55,8 @@
public void onQuickScrubEnd() {
mAutoAdvanceAlarm.cancelAlarm();
- if (mRecentsView != null) {
+ if (mRecentsView == null) {
+ } else {
int page = mRecentsView.getNextPage();
// Settle on the page then launch it.
int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
new file mode 100644
index 0000000..7c98317
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+/**
+ * Wrapper around RecentsAnimationController to help with some synchronization
+ */
+public class RecentsAnimationWrapper {
+
+ public RecentsAnimationControllerCompat controller;
+ public RemoteAnimationTargetCompat[] targets;
+
+ private boolean mInputConsumerEnabled;
+
+ public synchronized void setController(
+ RecentsAnimationControllerCompat controller, RemoteAnimationTargetCompat[] targets) {
+ this.controller = controller;
+ this.targets = targets;
+
+ if (mInputConsumerEnabled) {
+ enableInputConsumer();
+ }
+ }
+
+ public void finish(boolean toHome) {
+ BackgroundExecutor.get().submit(() -> {
+ synchronized (this) {
+ if (controller != null) {
+ controller.setInputConsumerEnabled(false);
+ controller.finish(toHome);
+ }
+ }
+ });
+ }
+
+ public void enableInputConsumer() {
+ mInputConsumerEnabled = true;
+ if (mInputConsumerEnabled) {
+ BackgroundExecutor.get().submit(() -> {
+ synchronized (this) {
+ if (controller != null) {
+ controller.setInputConsumerEnabled(true);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 9c757bf..8e03f37 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -18,12 +18,25 @@
import android.animation.LayoutTransition;
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.view.LayoutInflater;
import android.view.View;
+import android.widget.FrameLayout;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
@@ -48,7 +61,7 @@
/**
* A list of recent tasks.
*/
-public class RecentsView extends PagedView {
+public class RecentsView extends PagedView implements Insettable {
private static final Rect sTempStableInsets = new Rect();
@@ -72,7 +85,7 @@
for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
final TaskView taskView = (TaskView) getChildAt(i);
if (taskView.getTask().key.id == taskId) {
- taskView.getThumbnail().setThumbnail(snapshot);
+ taskView.getThumbnail().setThumbnail(taskView.getTask(), snapshot);
return;
}
}
@@ -85,7 +98,14 @@
private final RecentsModel mModel;
private int mLoadPlanId = -1;
- private Task mFirstTask;
+ // Only valid until the launcher state changes to NORMAL
+ private int mRunningTaskId = -1;
+
+ private Bitmap mScrim;
+ private Paint mFadePaint;
+ private Shader mFadeShader;
+ private Matrix mFadeMatrix;
+ private boolean mScrimOnLeft;
public RecentsView(Context context) {
this(context, null);
@@ -99,8 +119,8 @@
super(context, attrs, defStyleAttr);
setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
enableFreeScroll(true);
- setClipChildren(true);
setupLayoutTransition();
+ setClipToOutline(true);
mLauncher = Launcher.getLauncher(context);
mQuickScrubController = new QuickScrubController(mLauncher);
@@ -109,6 +129,16 @@
mScrollState.isRtl = mIsRtl;
}
+ public void updateThumbnail(int taskId, ThumbnailData thumbnailData) {
+ for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
+ final TaskView taskView = (TaskView) getChildAt(i);
+ if (taskView.getTask().key.id == taskId) {
+ taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
+ return;
+ }
+ }
+ }
+
private void setupLayoutTransition() {
// We want to show layout transitions when pages are deleted, to close the gap.
mLayoutTransition = new LayoutTransition();
@@ -123,10 +153,6 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
-
- Rect padding =
- getPadding(Launcher.getLauncher(getContext()).getDeviceProfile(), getContext());
- setPadding(padding.left, padding.top, padding.right, padding.bottom);
mFirstTaskIndex = getPageCount();
}
@@ -148,6 +174,43 @@
updateTaskStackListenerState();
}
+ @Override
+ public void setInsets(Rect insets) {
+ mInsets.set(insets);
+ DeviceProfile dp = Launcher.getLauncher(getContext()).getDeviceProfile();
+ Rect padding = getPadding(dp, getContext());
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+ lp.bottomMargin = padding.bottom;
+ setLayoutParams(lp);
+
+ setPadding(padding.left, padding.top, padding.right, 0);
+
+ if (dp.isVerticalBarLayout()) {
+ boolean wasScrimOnLeft = mScrimOnLeft;
+ mScrimOnLeft = dp.isSeascape();
+
+ if (mScrim == null || wasScrimOnLeft != mScrimOnLeft) {
+ Drawable scrim = getContext().getDrawable(mScrimOnLeft
+ ? R.drawable.recents_horizontal_scrim_left
+ : R.drawable.recents_horizontal_scrim_right);
+ if (scrim instanceof BitmapDrawable) {
+ mScrim = ((BitmapDrawable) scrim).getBitmap();
+ mFadePaint = new Paint();
+ mFadePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+ mFadeShader = new BitmapShader(mScrim, TileMode.CLAMP, TileMode.REPEAT);
+ mFadeMatrix = new Matrix();
+ } else {
+ mScrim = null;
+ }
+ }
+ } else {
+ mScrim = null;
+ mFadePaint = null;
+ mFadeShader = null;
+ mFadeMatrix = null;
+ }
+ }
+
public int getFirstTaskIndex() {
return mFirstTaskIndex;
}
@@ -179,13 +242,6 @@
final ArrayList<Task> tasks = new ArrayList<>(stack.getTasks());
setLayoutTransition(null);
- if (mFirstTask != null) {
- // TODO: Handle this case here once we have a valid implementation for mFirstTask
- if (tasks.isEmpty() || !keysEquals(tasks.get(tasks.size() - 1), mFirstTask)) {
- // tasks.add(mFirstTask);
- }
- }
-
final int requiredChildCount = tasks.size() + mFirstTaskIndex;
for (int i = getChildCount(); i < requiredChildCount; i++) {
final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false);
@@ -234,10 +290,9 @@
if (profile.isVerticalBarLayout()) {
// Use the same padding on both sides for symmetry.
float availableWidth = taskWidth - 2 * Math.max(padding.left, padding.right);
- float availableHeight = profile.availableHeightPx - padding.top - padding.bottom
- - sTempStableInsets.top
- - profile.heightPx * (1 - OverviewState.getVerticalProgress(profile, context));
-
+ float availableHeight = profile.availableHeightPx - padding.top
+ - sTempStableInsets.top - Math.max(padding.bottom,
+ profile.heightPx * (1 - OverviewState.getVerticalProgress(profile, context)));
float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
overviewHeight = taskHeight * scaledRatio;
overviewWidth = taskWidth * scaledRatio;
@@ -306,11 +361,11 @@
if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
return;
}
- final int halfScreenWidth = getMeasuredWidth() / 2;
- final int screenCenter = halfScreenWidth + getScrollX();
- final int pageSpacing = mPageSpacing;
final int halfPageWidth = mScrollState.halfPageWidth = getNormalChildWidth() / 2;
mScrollState.lastScrollType = SCROLL_TYPE_NONE;
+ final int screenCenter = mInsets.left + getPaddingLeft() + getScrollX() + halfPageWidth;
+ final int halfScreenWidth = getMeasuredWidth() / 2;
+ final int pageSpacing = mPageSpacing;
final int pageCount = getPageCount();
for (int i = 0; i < pageCount; i++) {
@@ -333,7 +388,7 @@
}
public void reset() {
- mFirstTask = null;
+ mRunningTaskId = -1;
setCurrentPage(0);
}
@@ -346,11 +401,7 @@
*/
public void reloadIfNeeded() {
if (!mModel.isLoadPlanValid(mLoadPlanId)) {
- int taskId = -1;
- if (mFirstTask != null) {
- taskId = mFirstTask.key.id;
- }
- mLoadPlanId = mModel.loadTasks(taskId, this::applyLoadPlan);
+ mLoadPlanId = mModel.loadTasks(mRunningTaskId, this::applyLoadPlan);
}
}
@@ -362,43 +413,63 @@
* is called.
* Also scrolls the view to this task
*/
- public void showTask(Task task) {
+ public void showTask(int runningTaskId) {
boolean needsReload = false;
- boolean inflateFirstChild = true;
- if (getTaskCount() > 0) {
- TaskView tv = (TaskView) getChildAt(mFirstTaskIndex);
- inflateFirstChild = !keysEquals(tv.getTask(), task);
- }
- if (inflateFirstChild) {
+ if (getTaskCount() == 0) {
needsReload = true;
- setLayoutTransition(null);
// Add an empty view for now
+ setLayoutTransition(null);
final TaskView taskView = (TaskView) LayoutInflater.from(getContext())
.inflate(R.layout.task, this, false);
addView(taskView, mFirstTaskIndex);
- taskView.bind(task);
setLayoutTransition(mLayoutTransition);
}
if (!needsReload) {
needsReload = !mModel.isLoadPlanValid(mLoadPlanId);
}
if (needsReload) {
- mLoadPlanId = mModel.loadTasks(task.key.id, this::applyLoadPlan);
+ mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
}
- mFirstTask = task;
+ mRunningTaskId = runningTaskId;
setCurrentPage(mFirstTaskIndex);
- ((TaskView) getPageAt(mCurrentPage)).setIconScale(0);
- }
-
- private static boolean keysEquals(Task t1, Task t2) {
- // TODO: Match the keys directly
- return t1.key.id == t2.key.id;
+ if (mCurrentPage >= mFirstTaskIndex) {
+ ((TaskView) getPageAt(mCurrentPage)).setIconScale(0);
+ }
}
public QuickScrubController getQuickScrubController() {
return mQuickScrubController;
}
+ @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 {
/**
diff --git a/quickstep/src/com/android/quickstep/RemoteRunnable.java b/quickstep/src/com/android/quickstep/RemoteRunnable.java
new file mode 100644
index 0000000..ec7cad4
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RemoteRunnable.java
@@ -0,0 +1,33 @@
+/*
+ * 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.os.RemoteException;
+import android.util.Log;
+
+@FunctionalInterface
+public interface RemoteRunnable {
+
+ void run() throws RemoteException;
+
+ static void executeSafely(RemoteRunnable r) {
+ try {
+ r.run();
+ } catch (final RemoteException e) {
+ Log.e("RemoteRunnable", "Error calling remote method", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/TaskMenuView.java b/quickstep/src/com/android/quickstep/TaskMenuView.java
index bf75376..196a227 100644
--- a/quickstep/src/com/android/quickstep/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/TaskMenuView.java
@@ -35,6 +35,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer;
@@ -170,7 +171,8 @@
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
mLauncher.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
Rect insets = mLauncher.getDragLayer().getInsets();
- setX(sTempRect.left + (sTempRect.width() - getMeasuredWidth()) / 2 - insets.left);
+ int x = sTempRect.left + (sTempRect.width() - getMeasuredWidth()) / 2 - insets.left;
+ setX(Utilities.isRtl(getResources()) ? -x : x);
setY(sTempRect.top - mTaskIconAndName.getPaddingTop() - insets.top);
}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
new file mode 100644
index 0000000..c2fb7be
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -0,0 +1,55 @@
+/*
+ * 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.Matrix;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Preconditions;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+/**
+ * Factory class to create and add an overlays on the TaskView
+ */
+public class TaskOverlayFactory {
+
+ private static TaskOverlayFactory sInstance;
+
+ public static TaskOverlayFactory get(Context context) {
+ Preconditions.assertUIThread();
+ if (sInstance == null) {
+ sInstance = Utilities.getOverrideObject(TaskOverlayFactory.class,
+ context.getApplicationContext(), R.string.task_overlay_factory_class);
+ }
+ return sInstance;
+ }
+
+ public TaskOverlay createOverlay(View thumbnailView) {
+ return new TaskOverlay();
+ }
+
+ public static class TaskOverlay {
+
+ public void setTaskInfo(ThumbnailData thumbnail, Matrix matrix) { }
+
+ public void reset() { }
+
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
index 473681f..36a0601 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
@@ -22,35 +22,42 @@
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ComposeShader;
import android.graphics.LightingColorFilter;
+import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
import android.graphics.Shader;
import android.util.AttributeSet;
-import android.widget.FrameLayout;
+import android.view.View;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
/**
* A task in the Recents view.
*/
-public class TaskThumbnailView extends FrameLayout {
+public class TaskThumbnailView extends View {
+
+ private static final LightingColorFilter[] sDimFilterCache = new LightingColorFilter[256];
+
+ private final float mCornerRadius;
+ private final float mFadeLength;
+
+ private final TaskOverlay mOverlay;
+ private final Paint mPaint = new Paint();
+
+ private final Matrix mMatrix = new Matrix();
private ThumbnailData mThumbnailData;
-
- private Rect mThumbnailRect = new Rect();
- private float mThumbnailScale;
-
- private Matrix mMatrix = new Matrix();
- private Paint mDrawPaint = new Paint();
- protected Paint mBgFillPaint = new Paint();
protected BitmapShader mBitmapShader;
private float mDimAlpha = 1f;
- private LightingColorFilter mLightingColorFilter = new LightingColorFilter(Color.WHITE, 0);
public TaskThumbnailView(Context context) {
this(context, null);
@@ -62,32 +69,35 @@
public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- setWillNotDraw(false);
- setClipToOutline(true);
+ mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
+ mFadeLength = getResources().getDimension(R.dimen.task_fade_length);
+ mOverlay = TaskOverlayFactory.get(context).createOverlay(this);
+ }
+
+ public void bind() {
+ mOverlay.reset();
}
/**
* Updates this thumbnail.
*/
- public void setThumbnail(ThumbnailData thumbnailData) {
+ public void setThumbnail(Task task, ThumbnailData thumbnailData) {
+ mPaint.setColor(task == null ? Color.BLACK : task.colorBackground | 0xFF000000);
+
if (thumbnailData != null && thumbnailData.thumbnail != null) {
Bitmap bm = thumbnailData.thumbnail;
bm.prepareToDraw();
- mThumbnailScale = thumbnailData.scale;
mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
- mDrawPaint.setShader(mBitmapShader);
- mThumbnailRect.set(0, 0,
- bm.getWidth() - thumbnailData.insets.left - thumbnailData.insets.right,
- bm.getHeight() - thumbnailData.insets.top - thumbnailData.insets.bottom);
+ mPaint.setShader(mBitmapShader);
mThumbnailData = thumbnailData;
updateThumbnailMatrix();
- updateThumbnailPaintFilter();
} else {
mBitmapShader = null;
- mDrawPaint.setShader(null);
- mThumbnailRect.setEmpty();
mThumbnailData = null;
+ mPaint.setShader(null);
+ mOverlay.reset();
}
+ updateThumbnailPaintFilter();
}
/**
@@ -100,77 +110,78 @@
@Override
protected void onDraw(Canvas canvas) {
- int viewWidth = getMeasuredWidth();
- int viewHeight = getMeasuredHeight();
- int thumbnailWidth = Math.min(viewWidth,
- (int) (mThumbnailRect.width() * mThumbnailScale));
- int thumbnailHeight = Math.min(viewHeight,
- (int) (mThumbnailRect.height() * mThumbnailScale));
-
- if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) {
- // Draw the background, there will be some small overdraw with the thumbnail
- if (thumbnailWidth < viewWidth) {
- // Portrait thumbnail on a landscape task view
- canvas.drawRect(Math.max(0, thumbnailWidth), 0, viewWidth, viewHeight,
- mBgFillPaint);
- }
- if (thumbnailHeight < viewHeight) {
- // Landscape thumbnail on a portrait task view
- canvas.drawRect(0, Math.max(0, thumbnailHeight), viewWidth, viewHeight,
- mBgFillPaint);
- }
-
- // Draw the thumbnail
- canvas.drawRect(0, 0, thumbnailWidth, thumbnailHeight, mDrawPaint);
- } else {
- canvas.drawRect(0, 0, viewWidth, viewHeight, mBgFillPaint);
- }
+ canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
+ mCornerRadius, mCornerRadius, mPaint);
}
private void updateThumbnailPaintFilter() {
int mul = (int) (mDimAlpha * 255);
if (mBitmapShader != null) {
- mLightingColorFilter = new LightingColorFilter(Color.argb(255, mul, mul, mul), 0);
- mDrawPaint.setColorFilter(mLightingColorFilter);
- mDrawPaint.setColor(0xFFffffff);
- mBgFillPaint.setColorFilter(mLightingColorFilter);
+ mPaint.setColorFilter(getLightingColorFilter(mul));
} else {
- mDrawPaint.setColorFilter(null);
- mDrawPaint.setColor(Color.argb(255, mul, mul, mul));
+ mPaint.setColorFilter(null);
+ mPaint.setColor(Color.argb(255, mul, mul, mul));
}
invalidate();
}
private void updateThumbnailMatrix() {
- mThumbnailScale = 1f;
if (mBitmapShader != null && mThumbnailData != null) {
+ float scale = mThumbnailData.scale;
+ float thumbnailWidth = mThumbnailData.thumbnail.getWidth() -
+ (mThumbnailData.insets.left + mThumbnailData.insets.right) * scale;
+ float thumbnailHeight = mThumbnailData.thumbnail.getHeight() -
+ (mThumbnailData.insets.top + mThumbnailData.insets.bottom) * scale;
+ final float thumbnailScale;
+
if (getMeasuredWidth() == 0) {
// If we haven't measured , skip the thumbnail drawing and only draw the background
// color
- mThumbnailScale = 0f;
+ thumbnailScale = 0f;
} else {
- float invThumbnailScale = 1f / mThumbnailScale;
final Configuration configuration =
getContext().getApplicationContext().getResources().getConfiguration();
final DeviceProfile profile = Launcher.getLauncher(getContext()).getDeviceProfile();
if (configuration.orientation == mThumbnailData.orientation) {
// If we are in the same orientation as the screenshot, just scale it to the
// width of the task view
- mThumbnailScale = (float) getMeasuredWidth() / mThumbnailRect.width();
+ thumbnailScale = getMeasuredWidth() / thumbnailWidth;
} else if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
// Scale the landscape thumbnail up to app size, then scale that to the task
// view size to match other portrait screenshots
- mThumbnailScale = invThumbnailScale *
- ((float) getMeasuredWidth() / profile.widthPx);
+ thumbnailScale = ((float) getMeasuredWidth() / profile.widthPx);
} else {
// Otherwise, scale the screenshot to fit 1:1 in the current orientation
- mThumbnailScale = invThumbnailScale;
+ thumbnailScale = 1;
}
}
- mMatrix.setTranslate(-mThumbnailData.insets.left, -mThumbnailData.insets.top);
- mMatrix.postScale(mThumbnailScale, mThumbnailScale);
+ mMatrix.setTranslate(-mThumbnailData.insets.left * scale,
+ -mThumbnailData.insets.top * scale);
+ mMatrix.postScale(thumbnailScale, thumbnailScale);
mBitmapShader.setLocalMatrix(mMatrix);
+
+ float bitmapHeight = Math.max(thumbnailHeight * thumbnailScale, 0);
+ Shader shader = mBitmapShader;
+ if (bitmapHeight < getMeasuredHeight()) {
+ int color = mPaint.getColor();
+ LinearGradient fade = new LinearGradient(
+ 0, bitmapHeight - mFadeLength, 0, bitmapHeight,
+ color & 0x00FFFFFF, color, Shader.TileMode.CLAMP);
+ shader = new ComposeShader(fade, shader, Mode.DST_OVER);
+ }
+
+ float bitmapWidth = Math.max(thumbnailWidth * thumbnailScale, 0);
+ if (bitmapWidth < getMeasuredWidth()) {
+ int color = mPaint.getColor();
+ LinearGradient fade = new LinearGradient(
+ bitmapWidth - mFadeLength, 0, bitmapWidth, 0,
+ color & 0x00FFFFFF, color, Shader.TileMode.CLAMP);
+ shader = new ComposeShader(fade, shader, Mode.DST_OVER);
+ }
+ mPaint.setShader(shader);
}
+
+ mOverlay.setTaskInfo(mThumbnailData, mMatrix);
invalidate();
}
@@ -179,4 +190,17 @@
super.onSizeChanged(w, h, oldw, oldh);
updateThumbnailMatrix();
}
+
+ private static LightingColorFilter getLightingColorFilter(int dimColor) {
+ if (dimColor < 0) {
+ dimColor = 0;
+ } else if (dimColor > 255) {
+ dimColor = 255;
+ }
+ if (sDimFilterCache[dimColor] == null) {
+ sDimFilterCache[dimColor] =
+ new LightingColorFilter(Color.argb(255, dimColor, dimColor, dimColor), 0);
+ }
+ return sDimFilterCache[dimColor];
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index 5c15a76..46fcc72 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -16,19 +16,27 @@
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.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.app.ActivityOptions;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Outline;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Property;
+import android.view.View;
+import android.view.ViewOutlineProvider;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.launcher3.R;
import com.android.quickstep.RecentsView.PageCallbacks;
import com.android.quickstep.RecentsView.ScrollState;
+import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -40,9 +48,6 @@
import java.util.ArrayList;
import java.util.List;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
-
/**
* A task in the Recents view.
*/
@@ -90,9 +95,8 @@
public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- setOnClickListener((view) -> {
- launchTask(true /* animate */);
- });
+ setOnClickListener((view) -> launchTask(true /* animate */));
+ setOutlineProvider(new TaskOutlineProvider(getResources()));
}
@Override
@@ -110,6 +114,7 @@
mTask.removeCallback(this);
}
mTask = task;
+ mSnapshotView.bind();
task.addCallback(this);
}
@@ -155,14 +160,14 @@
@Override
public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
- mSnapshotView.setThumbnail(thumbnailData);
+ mSnapshotView.setThumbnail(task, thumbnailData);
mIconView.setImageDrawable(task.icon);
mIconView.setOnLongClickListener(icon -> TaskMenuView.showForTask(this));
}
@Override
public void onTaskDataUnloaded() {
- mSnapshotView.setThumbnail(null);
+ mSnapshotView.setThumbnail(null, null);
mIconView.setImageDrawable(null);
mIconView.setOnLongClickListener(null);
}
@@ -216,4 +221,22 @@
scrollState.prevPageExtraWidth = 0;
return SCROLL_TYPE_TASK;
}
+
+
+ private static final class TaskOutlineProvider extends ViewOutlineProvider {
+
+ private final int mMarginTop;
+ private final float mRadius;
+
+ TaskOutlineProvider(Resources res) {
+ mMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+ mRadius = res.getDimension(R.dimen.task_corner_radius);
+ }
+
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(0, mMarginTop, view.getWidth(),
+ view.getHeight(), mRadius);
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index c35ffee..0490832 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -23,6 +23,8 @@
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
+import static com.android.quickstep.RemoteRunnable.executeSafely;
+
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
@@ -37,8 +39,10 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.RemoteException;
import android.support.annotation.IntDef;
import android.util.Log;
import android.view.Choreographer;
@@ -52,11 +56,18 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.model.ModelPreload;
import com.android.launcher3.util.TraceHelper;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.AssistDataReceiver;
import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.systemui.shared.system.RecentsAnimationListener;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
import java.lang.annotation.Retention;
@@ -84,26 +95,32 @@
public static final int INTERACTION_QUICK_SWITCH = 1;
public static final int INTERACTION_QUICK_SCRUB = 2;
+ /**
+ * A background thread used for handling UI for another window.
+ */
+ private static HandlerThread sRemoteUiThread;
+
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
@Override
public void onMotionEvent(MotionEvent ev) {
- mEventQueue.queue(ev);
+ onBinderMotionEvent(ev);
}
@Override
- public void onBind(ISystemUiProxy iSystemUiProxy) throws RemoteException {
+ public void onBind(ISystemUiProxy iSystemUiProxy) {
mISystemUiProxy = iSystemUiProxy;
}
@Override
public void onQuickSwitch() {
- startTouchTracking(INTERACTION_QUICK_SWITCH);
+ updateTouchTracking(INTERACTION_QUICK_SWITCH);
}
@Override
public void onQuickScrubStart() {
- startTouchTracking(INTERACTION_QUICK_SCRUB);
+ updateTouchTracking(INTERACTION_QUICK_SCRUB);
+ sQuickScrubEnabled = true;
}
@Override
@@ -111,6 +128,7 @@
if (mInteractionHandler != null) {
mInteractionHandler.onQuickScrubEnd();
}
+ sQuickScrubEnabled = false;
}
@Override
@@ -126,36 +144,45 @@
private final Consumer<MotionEvent> mNoOpTouchConsumer = (ev) -> {};
private static boolean sConnected = false;
+ private static boolean sQuickScrubEnabled = false;
public static boolean isConnected() {
return sConnected;
}
+ public static boolean isQuickScrubEnabled() {
+ return sQuickScrubEnabled;
+ }
+
private ActivityManagerWrapper mAM;
private RunningTaskInfo mRunningTask;
private RecentsModel mRecentsModel;
private Intent mHomeIntent;
private ComponentName mLauncher;
private MotionEventQueue mEventQueue;
+ private MainThreadExecutor mMainThreadExecutor;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private int mActivePointerId = INVALID_POINTER_ID;
private VelocityTracker mVelocityTracker;
+ private boolean mTouchThresholdCrossed;
private int mTouchSlop;
private float mStartDisplacement;
- private NavBarSwipeInteractionHandler mInteractionHandler;
+ private BaseSwipeInteractionHandler mInteractionHandler;
private int mDisplayRotation;
private Rect mStableInsets = new Rect();
private ISystemUiProxy mISystemUiProxy;
- private Consumer<MotionEvent> mCurrentConsumer = mNoOpTouchConsumer;
+
+ private Choreographer mBackgroundThreadChoreographer;
@Override
public void onCreate() {
super.onCreate();
mAM = ActivityManagerWrapper.getInstance();
mRecentsModel = RecentsModel.getInstance(this);
+ mMainThreadExecutor = new MainThreadExecutor();
mHomeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
@@ -166,13 +193,17 @@
// Clear the packageName as system can fail to dedupe it b/64108432
mHomeIntent.setComponent(mLauncher).setPackage(null);
- mEventQueue = new MotionEventQueue(Choreographer.getInstance(), this::handleMotionEvent);
+ mEventQueue = new MotionEventQueue(Choreographer.getInstance(), mNoOpTouchConsumer);
sConnected = true;
+
+ new ModelPreload().start(this);
+ initBackgroundChoreographer();
}
@Override
public void onDestroy() {
sConnected = false;
+ sQuickScrubEnabled = false;
super.onDestroy();
}
@@ -182,19 +213,23 @@
return mMyBinder;
}
- private void handleMotionEvent(MotionEvent ev) {
+ private void onBinderMotionEvent(MotionEvent ev) {
if (ev.getActionMasked() == ACTION_DOWN) {
mRunningTask = mAM.getRunningTask();
if (mRunningTask == null) {
- mCurrentConsumer = mNoOpTouchConsumer;
+ mEventQueue.setConsumer(mNoOpTouchConsumer);
+ mEventQueue.setInterimChoreographer(null);
} else if (mRunningTask.topActivity.equals(mLauncher)) {
- mCurrentConsumer = getLauncherConsumer();
+ mEventQueue.setConsumer(getLauncherConsumer());
+ mEventQueue.setInterimChoreographer(null);
} else {
- mCurrentConsumer = mOtherActivityTouchConsumer;
+ mEventQueue.setConsumer(mOtherActivityTouchConsumer);
+ mEventQueue.setInterimChoreographer(
+ isUsingScreenShot() ? null : mBackgroundThreadChoreographer);
}
}
- mCurrentConsumer.accept(ev);
+ mEventQueue.queue(ev);
}
private void handleTouchDownOnOtherActivity(MotionEvent ev) {
@@ -208,6 +243,19 @@
mDownPos.set(ev.getX(), ev.getY());
mLastPos.set(mDownPos);
mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
+ mTouchThresholdCrossed = false;
+
+ // Clean up the old interaction handler
+ if (mInteractionHandler != null) {
+ final BaseSwipeInteractionHandler handler = mInteractionHandler;
+ mMainThreadExecutor.execute(handler::reset);
+ mInteractionHandler = null;
+ }
+
+ // Start the window animation on down to give more time for launcher to draw
+ if (!isUsingScreenShot()) {
+ startTouchTrackingForWindowAnimation();
+ }
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
@@ -215,10 +263,6 @@
mVelocityTracker.clear();
}
mVelocityTracker.addMovement(ev);
- if (mInteractionHandler != null) {
- mInteractionHandler.endTouch(0);
- mInteractionHandler = null;
- }
Display display = getSystemService(WindowManager.class).getDefaultDisplay();
mDisplayRotation = display.getRotation();
@@ -253,10 +297,22 @@
} else if (isNavBarOnLeft()) {
displacement = mDownPos.x - ev.getX(pointerIndex);
}
- if (mInteractionHandler == null) {
- if (Math.abs(displacement) >= mTouchSlop) {
+ if (!mTouchThresholdCrossed) {
+ mTouchThresholdCrossed = Math.abs(displacement) >= mTouchSlop;
+ if (mTouchThresholdCrossed) {
mStartDisplacement = Math.signum(displacement) * mTouchSlop;
- startTouchTracking(INTERACTION_NORMAL);
+
+ if (isUsingScreenShot()) {
+ startTouchTrackingForScreenshotAnimation();
+ }
+
+ // Notify the handler that the gesture has actually started
+ mInteractionHandler.onGestureStarted();
+
+ // Notify the system that we have started tracking the event
+ if (mISystemUiProxy != null) {
+ executeSafely(mISystemUiProxy::onRecentsAnimationStarted);
+ }
}
} else {
// Move
@@ -269,8 +325,8 @@
case ACTION_UP: {
TraceHelper.endSection("TouchInt");
- endInteraction();
- mCurrentConsumer = mNoOpTouchConsumer;
+ finishTouchTracking();
+ mEventQueue.setConsumer(mNoOpTouchConsumer);
break;
}
}
@@ -284,10 +340,17 @@
return mDisplayRotation == Surface.ROTATION_270 && mStableInsets.left > 0;
}
- private void startTouchTracking(@InteractionType int interactionType) {
+ private boolean isUsingScreenShot() {
+ return Utilities.getPrefs(this).getBoolean("pref_use_screenshot_animation", true);
+ }
+
+ /**
+ * Called when the gesture has started.
+ */
+ private void startTouchTrackingForScreenshotAnimation() {
// Create the shared handler
final NavBarSwipeInteractionHandler handler =
- new NavBarSwipeInteractionHandler(mRunningTask, this, interactionType);
+ new NavBarSwipeInteractionHandler(mRunningTask, this, INTERACTION_NORMAL);
TraceHelper.partitionSection("TouchInt", "Thershold crossed ");
@@ -300,29 +363,85 @@
Intent homeIntent = handler.addToIntent(new Intent(mHomeIntent));
startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, 0).toBundle());
TraceHelper.partitionSection("TouchInt", "Home started");
-
- /*
- ActivityManagerWrapper.getInstance().startRecentsActivity(null, options,
- ActivityOptions.makeCustomAnimation(this, 0, 0), UserHandle.myUserId(),
- null, null);
- */
});
// Preload the plan
mRecentsModel.loadTasks(mRunningTask.id, null);
mInteractionHandler = handler;
+ mInteractionHandler.setGestureEndCallback(() -> mInteractionHandler = null);
}
- private void endInteraction() {
- if (mInteractionHandler != null) {
+ private void startTouchTrackingForWindowAnimation() {
+ // Create the shared handler
+ final WindowTransformSwipeHandler handler =
+ new WindowTransformSwipeHandler(mRunningTask, this);
+ BackgroundExecutor.get().submit(() -> {
+ ActivityManagerWrapper.getInstance().startRecentsActivity(mHomeIntent,
+ new AssistDataReceiver() {
+ @Override
+ public void onHandleAssistData(Bundle bundle) {
+ // Pass to AIAI
+ }
+ },
+ new RecentsAnimationListener() {
+ public void onAnimationStart(
+ RecentsAnimationControllerCompat controller,
+ RemoteAnimationTargetCompat[] apps) {
+ if (mInteractionHandler == handler) {
+ handler.setRecentsAnimation(controller, apps);
+
+ } else {
+ controller.finish(false /* toHome */);
+ }
+ }
+
+ public void onAnimationCanceled() {
+ if (mInteractionHandler == handler) {
+ handler.setRecentsAnimation(null, null);
+ }
+ }
+ }, null, null);
+ });
+
+ // Preload the plan
+ mRecentsModel.loadTasks(mRunningTask.id, null);
+ mInteractionHandler = handler;
+ handler.setGestureEndCallback(() -> {
+ if (handler == mInteractionHandler) {
+ mInteractionHandler = null;
+ }
+ });
+ handler.setLauncherOnDrawCallback(() -> {
+ if (handler == mInteractionHandler) {
+ mEventQueue.setInterimChoreographer(null);
+ }
+ });
+ mMainThreadExecutor.execute(handler::initWhenReady);
+ }
+
+ private void updateTouchTracking(@InteractionType int interactionType) {
+ final BaseSwipeInteractionHandler handler = mInteractionHandler;
+ mMainThreadExecutor.execute(() -> handler.updateInteractionType(interactionType));
+ }
+
+ /**
+ * Called when the gesture has ended. Does not correlate to the completion of the interaction as
+ * the animation can still be running.
+ */
+ private void finishTouchTracking() {
+ if (mTouchThresholdCrossed) {
mVelocityTracker.computeCurrentVelocity(1000,
ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
float velocity = isNavBarOnRight() ? mVelocityTracker.getXVelocity(mActivePointerId)
: isNavBarOnLeft() ? -mVelocityTracker.getXVelocity(mActivePointerId)
: mVelocityTracker.getYVelocity(mActivePointerId);
- mInteractionHandler.endTouch(velocity);
- mInteractionHandler = null;
+ mInteractionHandler.onGestureEnded(velocity);
+ } else if (!isUsingScreenShot()) {
+ // Since we start touch tracking on DOWN, we may reach this state without actually
+ // starting the gesture. In that case, just cleanup immediately.
+ final BaseSwipeInteractionHandler handler = mInteractionHandler;
+ mMainThreadExecutor.execute(handler::reset);
}
mVelocityTracker.recycle();
mVelocityTracker = null;
@@ -393,7 +512,7 @@
case ACTION_POINTER_UP:
case ACTION_POINTER_DOWN:
if (!mTrackingStarted) {
- mCurrentConsumer = mNoOpTouchConsumer;
+ mEventQueue.setConsumer(mNoOpTouchConsumer);
}
break;
case ACTION_MOVE: {
@@ -417,7 +536,7 @@
}
if (action == ACTION_UP || action == ACTION_CANCEL) {
- mCurrentConsumer = mNoOpTouchConsumer;
+ mEventQueue.setConsumer(mNoOpTouchConsumer);
}
}
@@ -430,4 +549,18 @@
ev.setEdgeFlags(flags);
}
}
+
+ private void initBackgroundChoreographer() {
+ if (sRemoteUiThread == null) {
+ sRemoteUiThread = new HandlerThread("remote-ui");
+ sRemoteUiThread.start();
+ }
+ new Handler(sRemoteUiThread.getLooper()).post(() ->
+ mBackgroundThreadChoreographer = Choreographer.getInstance());
+ }
+
+ public static boolean isInteractionQuick(@InteractionType int interactionType) {
+ return interactionType == INTERACTION_QUICK_SCRUB ||
+ interactionType == INTERACTION_QUICK_SWITCH;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
new file mode 100644
index 0000000..1351973
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -0,0 +1,530 @@
+/*
+ * 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.launcher3.anim.Interpolators.LINEAR;
+import static com.android.quickstep.TouchInteractionService.INTERACTION_NORMAL;
+import static com.android.quickstep.TouchInteractionService.INTERACTION_QUICK_SCRUB;
+import static com.android.quickstep.TouchInteractionService.INTERACTION_QUICK_SWITCH;
+import static com.android.quickstep.TouchInteractionService.isInteractionQuick;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.RectEvaluator;
+import android.annotation.TargetApi;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Looper;
+import android.support.annotation.UiThread;
+import android.support.annotation.WorkerThread;
+import android.view.View;
+import android.view.ViewTreeObserver.OnDrawListener;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.TraceHelper;
+import com.android.quickstep.TouchInteractionService.InteractionType;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.TransactionCompat;
+import com.android.systemui.shared.system.WindowManagerWrapper;
+
+@TargetApi(Build.VERSION_CODES.O)
+public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
+
+ // Launcher UI related states
+ private static final int STATE_LAUNCHER_READY = 1 << 0;
+ private static final int STATE_LAUNCHER_DRAWN = 1 << 1;
+ private static final int STATE_ACTIVITY_MULTIPLIER_COMPLETE = 1 << 2;
+
+ // Internal initialization states
+ private static final int STATE_APP_CONTROLLER_RECEIVED = 1 << 3;
+
+ // Interaction finish states
+ private static final int STATE_SCALED_SNAPSHOT_RECENTS = 1 << 4;
+ private static final int STATE_SCALED_SNAPSHOT_APP = 1 << 5;
+
+ private static final int LAUNCHER_UI_STATES =
+ STATE_LAUNCHER_READY | STATE_LAUNCHER_DRAWN | STATE_ACTIVITY_MULTIPLIER_COMPLETE;
+
+ private static final long MAX_SWIPE_DURATION = 200;
+ private static final long MIN_SWIPE_DURATION = 80;
+ private static final int QUICK_SWITCH_SNAP_DURATION = 120;
+
+ private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
+
+ private final Rect mStableInsets = new Rect();
+ private final Rect mSourceRect = new Rect();
+ private final Rect mTargetRect = new Rect();
+ private final Rect mCurrentRect = new Rect();
+ private final Rect mClipRect = new Rect();
+ private final RectEvaluator mRectEvaluator = new RectEvaluator(mCurrentRect);
+ private DeviceProfile mDp;
+ private int mTransitionDragLength;
+
+ // Shift in the range of [0, 1].
+ // 0 => preview snapShot is completely visible, and hotseat is completely translated down
+ // 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
+ // visible.
+ private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
+
+ private final MainThreadExecutor mMainExecutor = new MainThreadExecutor();
+
+ private final Context mContext;
+ private final int mRunningTaskId;
+
+ private MultiStateCallback mStateCallback;
+ private boolean mControllerStateAnimation;
+ private AnimatorPlaybackController mLauncherTransitionController;
+
+ private Launcher mLauncher;
+ private LauncherLayoutListener mLauncherLayoutListener;
+ private RecentsView mRecentsView;
+ private QuickScrubController mQuickScrubController;
+
+ private Runnable mLauncherDrawnCallback;
+
+ private boolean mWasLauncherAlreadyVisible;
+
+ private float mCurrentDisplacement;
+
+ private @InteractionType int mInteractionType = INTERACTION_NORMAL;
+ private boolean mStartedQuickScrubFromHome;
+
+ private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper();
+ private Matrix mTmpMatrix = new Matrix();
+
+ WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context) {
+ mContext = context;
+ mRunningTaskId = runningTaskInfo.id;
+
+ WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
+
+ DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
+ // TODO: If in multi window mode, dp = dp.getMultiWindowProfile()
+ dp = dp.copy(mContext);
+ // TODO: Use different insets for multi-window mode
+ dp.updateInsets(mStableInsets);
+
+ initTransitionEndpoints(dp);
+ initStateCallbacks();
+ }
+
+ private void initStateCallbacks() {
+ mStateCallback = new MultiStateCallback();
+ mStateCallback.addCallback(STATE_SCALED_SNAPSHOT_APP | STATE_APP_CONTROLLER_RECEIVED,
+ this::resumeLastTask);
+ mStateCallback.addCallback(STATE_SCALED_SNAPSHOT_RECENTS
+ | STATE_ACTIVITY_MULTIPLIER_COMPLETE
+ | STATE_APP_CONTROLLER_RECEIVED,
+ this::switchToScreenshot);
+ mStateCallback.addCallback(STATE_SCALED_SNAPSHOT_RECENTS
+ | STATE_ACTIVITY_MULTIPLIER_COMPLETE,
+ this::animateFirstTaskIcon);
+
+ mStateCallback.addCallback(STATE_LAUNCHER_READY | STATE_SCALED_SNAPSHOT_APP,
+ this::reset);
+ mStateCallback.addCallback(STATE_LAUNCHER_READY | STATE_SCALED_SNAPSHOT_RECENTS,
+ this::reset);
+
+ mStateCallback.addCallback(STATE_LAUNCHER_READY | STATE_LAUNCHER_DRAWN,
+ mLauncherDrawnCallback);
+ }
+
+ private void setStateOnUiThread(int stateFlag) {
+ mMainExecutor.execute(() -> mStateCallback.setState(stateFlag));
+ }
+
+ public void setLauncherOnDrawCallback(Runnable callback) {
+ mLauncherDrawnCallback = callback;
+ mStateCallback.addCallback(STATE_LAUNCHER_READY | STATE_LAUNCHER_DRAWN,
+ mLauncherDrawnCallback);
+ }
+
+ private void initTransitionEndpoints(DeviceProfile dp) {
+ mDp = dp;
+ RecentsView.getPageRect(dp, mContext, mTargetRect);
+ mSourceRect.set(0, 0, dp.widthPx - mStableInsets.left - mStableInsets.right,
+ dp.heightPx - mStableInsets.top - mStableInsets.bottom);
+
+ mTransitionDragLength = dp.hotseatBarSizePx + (dp.isVerticalBarLayout()
+ ? (dp.hotseatBarSidePaddingPx + (dp.isSeascape() ? mStableInsets.left : mStableInsets.right))
+ : mStableInsets.bottom);
+ }
+
+ private long getFadeInDuration() {
+ if (mCurrentShift.getCurrentAnimation() != null) {
+ ObjectAnimator anim = mCurrentShift.getCurrentAnimation();
+ long theirDuration = anim.getDuration() - anim.getCurrentPlayTime();
+
+ // TODO: Find a better heuristic
+ return Math.min(MAX_SWIPE_DURATION, Math.max(theirDuration, MIN_SWIPE_DURATION));
+ } else {
+ return MAX_SWIPE_DURATION;
+ }
+ }
+
+ @Override
+ protected boolean init(final Launcher launcher, boolean alreadyOnHome) {
+ if (launcher == mLauncher) {
+ return true;
+ }
+ if (mLauncher != null) {
+ // The launcher may have been recreated as a result of device rotation.
+ int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES;
+ initStateCallbacks();
+ mStateCallback.setState(oldState);
+ }
+ mLauncher = launcher;
+
+ AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
+ mControllerStateAnimation = alreadyOnHome;
+ if (mControllerStateAnimation) {
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
+ mLauncherTransitionController = launcher.getStateManager()
+ .createAnimationToNewWorkspace(OVERVIEW, accuracy);
+ mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
+
+ mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_DRAWN);
+ } else {
+ TraceHelper.beginSection("WTS-init");
+ launcher.getStateManager().goToState(OVERVIEW, false);
+ TraceHelper.partitionSection("WTS-init", "State changed");
+
+ // TODO: Implement a better animation for fading in
+ View rootView = launcher.getRootView();
+ rootView.setAlpha(0);
+ rootView.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {
+
+ @Override
+ public void onDraw() {
+ TraceHelper.endSection("WTS-init", "Launcher frame is drawn");
+ rootView.post(() ->
+ rootView.getViewTreeObserver().removeOnDrawListener(this));
+ if (launcher != mLauncher) {
+ return;
+ }
+
+ if ((mStateCallback.getState() & STATE_LAUNCHER_DRAWN) == 0) {
+ mStateCallback.setState(STATE_LAUNCHER_DRAWN);
+ rootView.animate().alpha(1)
+ .setDuration(getFadeInDuration())
+ .withEndAction(() -> mStateCallback.setState(launcher == mLauncher
+ ? STATE_ACTIVITY_MULTIPLIER_COMPLETE : 0));
+ }
+ }
+ });
+ }
+
+ mRecentsView = mLauncher.getOverviewPanel();
+ mRecentsView.showTask(mRunningTaskId);
+ mWasLauncherAlreadyVisible = alreadyOnHome;
+ mLauncherLayoutListener = new LauncherLayoutListener(mLauncher, this);
+ mLauncher.getDragLayer().addView(mLauncherLayoutListener);
+
+ // Optimization
+ if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ // All-apps search box is visible in vertical bar layout.
+ mLauncher.getAppsView().setVisibility(View.GONE);
+ }
+
+ onLauncherLayoutChanged();
+ mStateCallback.setState(STATE_LAUNCHER_READY);
+ return true;
+ }
+
+ public void updateInteractionType(@InteractionType int interactionType) {
+ Preconditions.assertUIThread();
+ if (mInteractionType != INTERACTION_NORMAL) {
+ throw new IllegalArgumentException(
+ "Can't change interaction type from " + mInteractionType);
+ }
+ if (!isInteractionQuick(interactionType)) {
+ throw new IllegalArgumentException(
+ "Can't change interaction type to " + interactionType);
+ }
+ mInteractionType = interactionType;
+
+ if (mLauncher != null) {
+ updateUiForQuickScrub();
+ }
+ }
+
+ private void updateUiForQuickScrub() {
+ mStartedQuickScrubFromHome = mWasLauncherAlreadyVisible;
+ mQuickScrubController = mRecentsView.getQuickScrubController();
+ mQuickScrubController.onQuickScrubStart(mStartedQuickScrubFromHome);
+ animateToProgress(1f, MAX_SWIPE_DURATION);
+ if (mStartedQuickScrubFromHome) {
+ mLauncherLayoutListener.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ @WorkerThread
+ public void updateDisplacement(float displacement) {
+ mCurrentDisplacement = displacement;
+
+ float translation = Utilities.boundToRange(-mCurrentDisplacement, 0, mTransitionDragLength);
+ float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
+ mCurrentShift.updateValue(shift);
+ }
+
+ /**
+ * Called by {@link #mLauncherLayoutListener} when launcher layout changes
+ */
+ public void onLauncherLayoutChanged() {
+ Hotseat hotseat = mLauncher.getHotseat();
+
+ WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
+ initTransitionEndpoints(mLauncher.getDeviceProfile());
+
+ if (!mControllerStateAnimation) {
+ AnimatorSet anim = new AnimatorSet();
+ if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ mLauncher.getAllAppsController().setProgress(1);
+ ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(mLauncher.getAllAppsController(),
+ AllAppsTransitionController.ALL_APPS_PROGRESS,
+ 1, OVERVIEW.getVerticalProgress(mLauncher));
+ shiftAnim.setInterpolator(LINEAR);
+ anim.play(shiftAnim);
+
+ hotseat.setAlpha(0);
+ ObjectAnimator fadeAnim = ObjectAnimator.ofFloat(hotseat, View.ALPHA, 1);
+ fadeAnim.setInterpolator(LINEAR);
+ anim.play(fadeAnim);
+ } else {
+ hotseat.setTranslationY(mTransitionDragLength);
+ ObjectAnimator hotseatAnim = ObjectAnimator.ofFloat(hotseat, View.TRANSLATION_Y, 0);
+ hotseatAnim.setInterpolator(LINEAR);
+ anim.play(hotseatAnim);
+
+ View scrim = mLauncher.findViewById(R.id.all_apps_scrim);
+ scrim.setTranslationY(mTransitionDragLength);
+ ObjectAnimator scrimAnim = ObjectAnimator.ofFloat(scrim, View.TRANSLATION_Y, 0);
+ scrimAnim.setInterpolator(LINEAR);
+ anim.play(scrimAnim);
+ }
+
+ // TODO: Link this animation to state animation, so that it is cancelled
+ // automatically on state change
+ anim.setDuration(mTransitionDragLength * 2);
+ mLauncherTransitionController =
+ AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
+ mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
+ }
+ }
+
+ @WorkerThread
+ private void updateFinalShift() {
+ if (mStartedQuickScrubFromHome) {
+ return;
+ }
+
+ float shift = mCurrentShift.value;
+
+ synchronized (mRecentsAnimationWrapper) {
+ if (mRecentsAnimationWrapper.controller != null) {
+ mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
+ float scale = (float) mCurrentRect.width() / mSourceRect.width();
+
+ mClipRect.left = mSourceRect.left;
+ mClipRect.top = (int) (mStableInsets.top * shift);
+ mClipRect.bottom = (int) (mDp.heightPx - (mStableInsets.bottom * shift));
+ mClipRect.right = mSourceRect.right;
+
+ mTmpMatrix.setScale(scale, scale, 0, 0);
+ mTmpMatrix.postTranslate(mCurrentRect.left - mStableInsets.left * scale * shift,
+ mCurrentRect.top - mStableInsets.top * scale * shift);
+ TransactionCompat transaction = new TransactionCompat();
+ for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
+ if (app.mode == MODE_CLOSING) {
+ transaction.setMatrix(app.leash, mTmpMatrix)
+ .setWindowCrop(app.leash, mClipRect)
+ .show(app.leash);
+ }
+ }
+ transaction.apply();
+ }
+ }
+
+ if (mLauncherTransitionController != null) {
+ if (Looper.getMainLooper() == Looper.myLooper()) {
+ mLauncherTransitionController.setPlayFraction(shift);
+ } else {
+ // The fling operation completed even before the launcher was drawn
+ mMainExecutor.execute(() -> mLauncherTransitionController.setPlayFraction(shift));
+ }
+ }
+ }
+
+ public void setRecentsAnimation(RecentsAnimationControllerCompat controller,
+ RemoteAnimationTargetCompat[] apps) {
+ mRecentsAnimationWrapper.setController(controller, apps);
+ setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
+ }
+
+ public void onGestureStarted() { }
+
+ @WorkerThread
+ public void onGestureEnded(float endVelocity) {
+ Resources res = mContext.getResources();
+ float flingThreshold = res.getDimension(R.dimen.quickstep_fling_threshold_velocity);
+ boolean isFling = Math.abs(endVelocity) > flingThreshold;
+
+ long duration = MAX_SWIPE_DURATION;
+ final float endShift;
+ if (!isFling) {
+ endShift = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW ? 1 : 0;
+ } else {
+ endShift = endVelocity < 0 ? 1 : 0;
+ float minFlingVelocity = res.getDimension(R.dimen.quickstep_fling_min_velocity);
+ if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
+ float distanceToTravel = (endShift - mCurrentShift.value) * mTransitionDragLength;
+
+ // we want the page's snap velocity to approximately match the velocity at
+ // which the user flings, so we scale the duration by a value near to the
+ // derivative of the scroll interpolator at zero, ie. 5.
+ duration = 5 * Math.round(1000 * Math.abs(distanceToTravel / endVelocity));
+ }
+ }
+
+ animateToProgress(endShift, duration);
+ }
+
+ /** Animates to the given progress, where 0 is the current app and 1 is overview. */
+ private void animateToProgress(float progress, long duration) {
+ ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
+ anim.setInterpolator(Interpolators.SCROLL);
+ anim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ setStateOnUiThread((Float.compare(mCurrentShift.value, 0) == 0)
+ ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS);
+ }
+ });
+ anim.start();
+ }
+
+ @UiThread
+ private void resumeLastTask() {
+ mRecentsAnimationWrapper.finish(false /* toHome */);
+ }
+
+ public void reset() {
+ mCurrentShift.cancelAnimation();
+
+ if (mGestureEndCallback != null) {
+ mGestureEndCallback.run();
+ }
+
+ if (mLauncher != null) {
+ // TODO: These should be done as part of ActivityOptions#OnAnimationStarted
+ mLauncher.getStateManager().reapplyState();
+ mLauncher.setOnResumeCallback(() -> mLauncherLayoutListener.close(false));
+ mLauncherTransitionController.setPlayFraction(1);
+ }
+ clearReference();
+ }
+
+ public void layoutListenerClosed() {
+ if (mControllerStateAnimation) {
+ mLauncherTransitionController.setPlayFraction(1);
+ }
+ }
+
+ private void switchToScreenshot() {
+ mLauncherLayoutListener.close(false);
+ View currentRecentsPage = mRecentsView.getPageAt(mRecentsView.getCurrentPage());
+ if (currentRecentsPage instanceof TaskView) {
+ ((TaskView) currentRecentsPage).animateIconToScale(1f);
+ }
+ if (mInteractionType == INTERACTION_QUICK_SWITCH) {
+ for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
+ TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
+ // TODO: Match the keys directly
+ if (taskView.getTask().key.id != mRunningTaskId) {
+ mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION);
+ taskView.postDelayed(() -> {taskView.launchTask(true);},
+ QUICK_SWITCH_SNAP_DURATION);
+ break;
+ }
+ }
+ } else if (mInteractionType == INTERACTION_QUICK_SCRUB) {
+ if (mQuickScrubController != null) {
+ mQuickScrubController.snapToPageForCurrentQuickScrubSection();
+ }
+ } else {
+ synchronized (mRecentsAnimationWrapper) {
+ if (mRecentsAnimationWrapper.controller != null) {
+ TransactionCompat transaction = new TransactionCompat();
+ for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
+ if (app.mode == MODE_CLOSING) {
+ // Update the screenshot of the task
+ final ThumbnailData thumbnail =
+ mRecentsAnimationWrapper.controller.screenshotTask(app.taskId);
+ mRecentsView.updateThumbnail(app.taskId, thumbnail);
+ }
+ }
+ transaction.apply();
+ }
+ }
+ mRecentsAnimationWrapper.finish(true /* toHome */);
+ }
+ }
+
+ private void animateFirstTaskIcon() {
+ View currentRecentsPage = mRecentsView.getPageAt(mRecentsView.getCurrentPage());
+ if (currentRecentsPage instanceof TaskView) {
+ ((TaskView) currentRecentsPage).animateIconToScale(1f);
+ }
+ }
+
+ public void onQuickScrubEnd() {
+ if (mQuickScrubController != null) {
+ mQuickScrubController.onQuickScrubEnd();
+ } else {
+ // TODO:
+ }
+ }
+
+ public void onQuickScrubProgress(float progress) {
+ if (mQuickScrubController != null) {
+ mQuickScrubController.onQuickScrubProgress(progress);
+ } else {
+ // TODO:
+ }
+ }
+}
diff --git a/res/drawable/ic_setting.xml b/res/drawable/ic_setting.xml
index 1bab189..08eba25 100644
--- a/res/drawable/ic_setting.xml
+++ b/res/drawable/ic_setting.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="@dimen/options_menu_icon_size"
+ android:height="@dimen/options_menu_icon_size"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
diff --git a/res/drawable/ic_star_rating.xml b/res/drawable/ic_star_rating.xml
deleted file mode 100644
index 4e34fa3..0000000
--- a/res/drawable/ic_star_rating.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="12dp"
- android:height="12dp"
- android:viewportWidth="12"
- android:viewportHeight="12">
-
- <path
- android:fillColor="#FB8C00"
- android:fillType="evenOdd"
- android:strokeWidth="1"
- android:pathData="M 9.76511755 11.9348136 L 8.33665684 7.16088817 L 12.080006 4.41656311 L 7.49967039 4.41856896 L 6.03138903 0 L 4.57932894 4.41856896 L -1.34115008e-16 4.41656311 L 3.72612122 7.16088817 L 2.29967385 11.9348136 L 6.03138903 8.82574452 Z" />
-</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_wallpaper.xml b/res/drawable/ic_wallpaper.xml
index 9e9222f..0c5a125 100644
--- a/res/drawable/ic_wallpaper.xml
+++ b/res/drawable/ic_wallpaper.xml
@@ -14,8 +14,8 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="@dimen/options_menu_icon_size"
+ android:height="@dimen/options_menu_icon_size"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
diff --git a/res/drawable/ic_widget.xml b/res/drawable/ic_widget.xml
index de2980f..4bb23b3 100644
--- a/res/drawable/ic_widget.xml
+++ b/res/drawable/ic_widget.xml
@@ -14,12 +14,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="@dimen/options_menu_icon_size"
+ android:height="@dimen/options_menu_icon_size"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
- android:fillColor="#FFFFFFFF"
+ android:fillColor="?android:attr/textColorPrimary"
android:pathData="M26,28v12c0,1,0.8,2,2,2h12c1,0,2-1,2-2V28c0-1.2-1-2-2-2H28C26.8,26,26,26.8,26,28z M8,42h12c1.2,0,2-1,2-2V28
c0-1.2-0.8-2-2-2H8c-1,0-2,0.8-2,2v12C6,41,7,42,8,42z M6,8v12c0,1.2,1,2,2,2h12c1.2,0,2-0.8,2-2V8c0-1-0.8-2-2-2H8C7,6,6,7,6,8z
M32.6,4.6l-8,8c-0.8,0.8-0.8,2,0,2.8l8,8c0.8,0.8,2,0.8,2.8,0l8-8c0.8-0.8,0.8-2,0-2.8l-8-8C34.6,3.8,33.4,3.8,32.6,4.6z"/>
diff --git a/res/drawable/round_rect_primary.xml b/res/drawable/round_rect_primary.xml
index 2c47e06..9f8f4da 100644
--- a/res/drawable/round_rect_primary.xml
+++ b/res/drawable/round_rect_primary.xml
@@ -17,5 +17,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?android:attr/colorPrimary" />
- <corners android:radius="2dp" />
+ <corners android:radius="8dp" />
</shape>
diff --git a/quickstep/res/drawable/task_thumbnail_background.xml b/res/drawable/tooltip_frame.xml
similarity index 82%
rename from quickstep/res/drawable/task_thumbnail_background.xml
rename to res/drawable/tooltip_frame.xml
index f1f48ac..0319051 100644
--- a/quickstep/res/drawable/task_thumbnail_background.xml
+++ b/res/drawable/tooltip_frame.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!--
+ 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.
@@ -13,6 +14,8 @@
See the License for the specific language governing permissions and
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"
+ android:shape="rectangle">
+ <solid android:color="?android:attr/colorBackground" />
<corners android:radius="2dp" />
-</shape>
+</shape>
\ No newline at end of file
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
deleted file mode 100644
index 9bd3c67..0000000
--- a/res/layout-land/launcher.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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.
--->
-
-<!-- Full screen view projects under the status bar and contains the background -->
-<com.android.launcher3.LauncherRootView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:id="@+id/launcher"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fitsSystemWindows="true">
-
- <com.android.launcher3.dragndrop.DragLayer
- android:id="@+id/drag_layer"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:background="?attr/workspaceStatusBarScrim"
- android:importantForAccessibility="no"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <!-- The workspace contains 5 screens of cells -->
- <!-- DO NOT CHANGE THE ID -->
- <com.android.launcher3.Workspace
- android:theme="@style/HomeScreenElementTheme"
- android:id="@+id/workspace"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- launcher:pageIndicator="@id/page_indicator" />
-
- <com.android.launcher3.pageindicators.PageIndicatorLandscape
- android:id="@+id/page_indicator"
- android:theme="@style/HomeScreenElementTheme"
- android:layout_width="@dimen/dynamic_grid_min_page_indicator_size"
- android:layout_height="@dimen/dynamic_grid_min_page_indicator_size"
- android:layout_gravity="bottom|left"
- android:background="@drawable/all_apps_handle_landscape" />
-
- <include layout="@layout/overview_panel"
- android:id="@+id/overview_panel"
- android:visibility="gone" />
-
- <com.android.launcher3.views.AllAppsScrim
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/all_apps_scrim" />
-
- <!-- DO NOT CHANGE THE ID -->
- <include layout="@layout/hotseat"
- android:id="@+id/hotseat"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- <include
- android:id="@+id/drop_target_bar"
- layout="@layout/drop_target_bar_vert" />
-
- <include layout="@layout/all_apps"
- android:id="@+id/apps_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible" />
-
- </com.android.launcher3.dragndrop.DragLayer>
-
-</com.android.launcher3.LauncherRootView>
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
deleted file mode 100644
index b678398..0000000
--- a/res/layout-port/launcher.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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.
--->
-
-<!-- Full screen view projects under the status bar and contains the background -->
-<com.android.launcher3.LauncherRootView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
-
- android:id="@+id/launcher"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fitsSystemWindows="true">
-
- <com.android.launcher3.dragndrop.DragLayer
- android:id="@+id/drag_layer"
- android:clipChildren="false"
- android:importantForAccessibility="no"
- android:clipToPadding="false"
- android:background="?attr/workspaceStatusBarScrim"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <!-- The workspace contains 5 screens of cells -->
- <!-- DO NOT CHANGE THE ID -->
- <com.android.launcher3.Workspace
- android:theme="@style/HomeScreenElementTheme"
- android:id="@+id/workspace"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- launcher:pageIndicator="@+id/page_indicator">
- </com.android.launcher3.Workspace>
-
- <include layout="@layout/overview_panel"
- android:id="@+id/overview_panel"
- android:visibility="gone" />
-
- <com.android.launcher3.views.AllAppsScrim
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/all_apps_scrim" />
-
- <!-- DO NOT CHANGE THE ID -->
- <include layout="@layout/hotseat"
- android:id="@+id/hotseat"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- <!-- Keep these behind the workspace so that they are not visible when
- we go into AllApps -->
- <include layout="@layout/page_indicator"
- android:id="@+id/page_indicator" />
-
- <include
- android:id="@+id/drop_target_bar"
- layout="@layout/drop_target_bar_horz" />
-
- <include layout="@layout/all_apps"
- android:id="@+id/apps_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible" />
- </com.android.launcher3.dragndrop.DragLayer>
-
-</com.android.launcher3.LauncherRootView>
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 8cf32bd..2ce6b8c 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -31,48 +31,7 @@
<include layout="@layout/all_apps_fast_scroller" />
- <com.android.launcher3.allapps.FloatingHeaderView
- android:id="@+id/all_apps_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/all_apps_header_top_padding"
- android:clipToPadding="false"
- android:layout_below="@id/search_container_all_apps" >
-
- <include layout="@layout/predictions_view" android:id="@+id/header_content" />
-
- <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
- android:id="@+id/tabs"
- android:layout_width="match_parent"
- android:layout_height="@dimen/all_apps_header_tab_height"
- android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
- android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
- android:layout_below="@id/header_content"
- android:orientation="horizontal">
- <Button
- android:id="@+id/tab_personal"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:background="?android:attr/selectableItemBackground"
- android:fontFamily="sans-serif-medium"
- android:text="@string/all_apps_personal_tab"
- android:textAllCaps="true"
- android:textColor="@color/all_apps_tab_text"
- android:textSize="14sp"/>
- <Button
- android:id="@+id/tab_work"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:background="?android:attr/selectableItemBackground"
- android:fontFamily="sans-serif-medium"
- android:text="@string/all_apps_work_tab"
- android:textAllCaps="true"
- android:textColor="@color/all_apps_work_tab_text"
- android:textSize="14sp"/>
- </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
- </com.android.launcher3.allapps.FloatingHeaderView>
+ <include layout="@layout/all_apps_floating_header" />
<!-- Note: we are reusing/repurposing a system attribute for search layout, because of a
platform bug, which prevents using custom attributes in <include> tag -->
diff --git a/res/layout/all_apps_discovery_item.xml b/res/layout/all_apps_discovery_item.xml
deleted file mode 100644
index 728283f..0000000
--- a/res/layout/all_apps_discovery_item.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.launcher3.discovery.AppDiscoveryItemView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clickable="true"
- android:background="?android:selectableItemBackground">
-
- <ImageView
- android:id="@+id/image"
- android:layout_width="56dp"
- android:layout_height="56dp"
- android:padding="8dp"
- android:scaleType="fitCenter"
- android:focusable="false"
- android:importantForAccessibility="no"/>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_centerVertical="true"
- android:layout_toRightOf="@id/image">
-
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="?android:textColorSecondary"
- android:textSize="15sp"/>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/rating"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="?android:textColorSecondary"
- android:textSize="14sp"
- android:layout_gravity="center_vertical"
- android:includeFontPadding="false"/>
-
- <com.android.launcher3.discovery.RatingView
- android:id="@+id/rating_view"
- android:layout_width="70dp"
- android:layout_height="16dp"
- android:layout_marginLeft="5dp"
- android:layout_marginRight="5dp"
- android:layout_gravity="center_vertical"/>
-
- <TextView
- android:id="@+id/review_count"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dp"
- android:textColor="?android:textColorHint"
- android:textSize="14sp"
- android:layout_gravity="center_vertical"/>
-
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
-
- <TextView
- android:id="@+id/price"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="?android:textColorHint"
- android:textSize="14sp"
- android:layout_marginRight="12dp"
- android:textAllCaps="true"/>
- </LinearLayout>
- </LinearLayout>
-
- <ImageView
- android:importantForAccessibility="no"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:paddingLeft="@dimen/dynamic_grid_edge_margin"
- android:paddingRight="@dimen/dynamic_grid_edge_margin"
- android:src="@drawable/all_apps_divider"
- android:scaleType="fitXY"
- android:focusable="false" />
-</com.android.launcher3.discovery.AppDiscoveryItemView>
\ No newline at end of file
diff --git a/res/layout/all_apps_discovery_loading_divider.xml b/res/layout/all_apps_discovery_loading_divider.xml
deleted file mode 100644
index 005847c..0000000
--- a/res/layout/all_apps_discovery_loading_divider.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="6dp"
- android:paddingLeft="@dimen/dynamic_grid_edge_margin"
- android:paddingRight="@dimen/dynamic_grid_edge_margin">
-
- <ProgressBar
- android:id="@+id/loadingProgressBar"
- style="@android:style/Widget.Material.ProgressBar.Horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="6dp"
- android:maxHeight="6dp"
- android:indeterminate="true"
- android:layout_gravity="center"/>
-
- <View
- android:id="@+id/loadedDivider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="@drawable/all_apps_divider"
- android:layout_gravity="bottom"
- android:visibility="invisible"/>
-
-</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/all_apps_floating_header.xml b/res/layout/all_apps_floating_header.xml
new file mode 100644
index 0000000..166725d
--- /dev/null
+++ b/res/layout/all_apps_floating_header.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.allapps.FloatingHeaderView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/all_apps_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/search_container_all_apps"
+ android:clipToPadding="false"
+ android:paddingTop="@dimen/all_apps_header_top_padding"
+ android:orientation="vertical" >
+
+ <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/all_apps_header_tab_height"
+ android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
+ android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/tab_personal"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:fontFamily="sans-serif-medium"
+ android:text="@string/all_apps_personal_tab"
+ android:textAllCaps="true"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp" />
+
+ <Button
+ android:id="@+id/tab_work"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:fontFamily="sans-serif-medium"
+ android:text="@string/all_apps_work_tab"
+ android:textAllCaps="true"
+ android:textColor="@color/all_apps_work_tab_text"
+ android:textSize="14sp" />
+ </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
+</com.android.launcher3.allapps.FloatingHeaderView>
diff --git a/res/layout/drop_target_bar.xml b/res/layout/drop_target_bar.xml
new file mode 100644
index 0000000..d376bcf
--- /dev/null
+++ b/res/layout/drop_target_bar.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.DropTargetBar xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dynamic_grid_drop_target_size"
+ android:layout_gravity="center_horizontal|top"
+ android:focusable="false"
+ android:alpha="0"
+ android:theme="@style/HomeScreenElementTheme"
+ android:visibility="invisible">
+
+ <!-- Delete target -->
+ <com.android.launcher3.DeleteDropTarget
+ android:id="@+id/delete_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/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 -->
+ <com.android.launcher3.UninstallDropTarget
+ android:id="@+id/uninstall_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/uninstall_drop_target_label" />
+
+</com.android.launcher3.DropTargetBar>
\ No newline at end of file
diff --git a/res/layout/drop_target_bar_horz.xml b/res/layout/drop_target_bar_horz.xml
deleted file mode 100644
index ed18192..0000000
--- a/res/layout/drop_target_bar_horz.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.launcher3.DropTargetBar
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:theme="@style/HomeScreenElementTheme"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dynamic_grid_drop_target_size"
- android:visibility="invisible"
- android:layout_gravity="center_horizontal|top"
- android:focusable="false">
-
- <FrameLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1" >
-
- <!-- Delete target -->
-
- <com.android.launcher3.DeleteDropTarget
- launcher:hideParentOnDisable="true"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:id="@+id/delete_target_text"
- style="@style/DropTargetButton"
- android:text="@string/remove_drop_target_label" />
- </FrameLayout>
-
- <FrameLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1" >
-
- <!-- App Info -->
-
- <com.android.launcher3.InfoDropTarget
- launcher:hideParentOnDisable="true"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:id="@+id/info_target_text"
- style="@style/DropTargetButton"
- android:text="@string/app_info_drop_target_label" />
- </FrameLayout>
-
- <FrameLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1" >
-
- <!-- Uninstall target -->
-
- <com.android.launcher3.UninstallDropTarget
- launcher:hideParentOnDisable="true"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:id="@+id/uninstall_target_text"
- style="@style/DropTargetButton"
- android:text="@string/uninstall_drop_target_label" />
- </FrameLayout>
-
-</com.android.launcher3.DropTargetBar>
\ No newline at end of file
diff --git a/res/layout/drop_target_bar_vert.xml b/res/layout/drop_target_bar_vert.xml
deleted file mode 100644
index 2394d0d..0000000
--- a/res/layout/drop_target_bar_vert.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.launcher3.DropTargetBar
- android:theme="@style/HomeScreenElementTheme"
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/dynamic_grid_drop_target_size"
- android:orientation="vertical"
- android:layout_height="match_parent"
- android:layout_gravity="left"
- android:visibility="invisible"
- android:focusable="false"
- android:paddingTop="@dimen/vert_drop_target_vertical_gap" >
-
- <!-- Delete target -->
- <com.android.launcher3.DeleteDropTarget
- android:layout_width="match_parent"
- android:layout_height="@dimen/dynamic_grid_drop_target_size"
- android:gravity="center"
- android:paddingLeft="@dimen/vert_drop_target_horizontal_gap"
- android:paddingRight="@dimen/vert_drop_target_horizontal_gap"
- android:id="@+id/delete_target_text" />
-
- <!-- Uninstall target -->
- <com.android.launcher3.UninstallDropTarget
- android:layout_width="match_parent"
- android:layout_height="@dimen/dynamic_grid_drop_target_size"
- android:gravity="center"
- android:paddingLeft="@dimen/vert_drop_target_horizontal_gap"
- android:paddingRight="@dimen/vert_drop_target_horizontal_gap"
- android:id="@+id/uninstall_target_text"
- android:layout_marginTop="@dimen/vert_drop_target_vertical_gap"/>
-
- <Space
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
-
- <!-- App Info -->
- <com.android.launcher3.InfoDropTarget
- android:layout_width="match_parent"
- android:layout_height="@dimen/dynamic_grid_drop_target_size"
- android:gravity="center"
- android:paddingLeft="@dimen/vert_drop_target_horizontal_gap"
- android:paddingRight="@dimen/vert_drop_target_horizontal_gap"
- android:id="@+id/info_target_text"
- android:layout_marginBottom="64dp"/>
-
-</com.android.launcher3.DropTargetBar>
\ No newline at end of file
diff --git a/res/layout/drop_target_tool_tip.xml b/res/layout/drop_target_tool_tip.xml
new file mode 100644
index 0000000..a3efec4
--- /dev/null
+++ b/res/layout/drop_target_tool_tip.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/tooltip_frame"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:maxWidth="256dp"
+ android:paddingBottom="6.5dp"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:paddingTop="6.5dp"
+ android:textSize="14sp"
+ android:fontFamily="sans-serif"
+ android:textColor="?android:attr/colorForeground" />
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout/launcher.xml
similarity index 70%
rename from res/layout-sw720dp/launcher.xml
rename to res/layout/launcher.xml
index 7e6c659..314359b 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout/launcher.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2007 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.
@@ -13,62 +12,65 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<!-- Full screen view projects under the status bar and contains the background -->
<com.android.launcher3.LauncherRootView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:id="@+id/launcher"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="?attr/workspaceStatusBarScrim"
android:fitsSystemWindows="true">
<com.android.launcher3.dragndrop.DragLayer
android:id="@+id/drag_layer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
- android:importantForAccessibility="no"
- android:background="?attr/workspaceStatusBarScrim"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:importantForAccessibility="no">
<!-- The workspace contains 5 screens of cells -->
<!-- DO NOT CHANGE THE ID -->
<com.android.launcher3.Workspace
- android:theme="@style/HomeScreenElementTheme"
- android:layout_gravity="center"
android:id="@+id/workspace"
android:layout_width="match_parent"
android:layout_height="match_parent"
- launcher:pageIndicator="@id/page_indicator">
- </com.android.launcher3.Workspace>
+ android:layout_gravity="center"
+ android:theme="@style/HomeScreenElementTheme"
+ launcher:pageIndicator="@+id/page_indicator" />
- <include layout="@layout/overview_panel"
+ <include
android:id="@+id/overview_panel"
+ layout="@layout/overview_panel"
android:visibility="gone" />
<com.android.launcher3.views.AllAppsScrim
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/all_apps_scrim" />
-
- <!-- DO NOT CHANGE THE ID -->
- <include layout="@layout/hotseat"
- android:id="@+id/hotseat"
+ android:id="@+id/all_apps_scrim"
android:layout_width="match_parent"
android:layout_height="match_parent" />
+ <!-- DO NOT CHANGE THE ID -->
<include
- android:id="@+id/drop_target_bar"
- layout="@layout/drop_target_bar_horz" />
+ android:id="@+id/hotseat"
+ layout="@layout/hotseat"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
<!-- Keep these behind the workspace so that they are not visible when
- we go into AllApps -->
- <include layout="@layout/page_indicator"
- android:id="@+id/page_indicator" />
+ we go into AllApps -->
+ <com.android.launcher3.pageindicators.WorkspacePageIndicator
+ android:id="@+id/page_indicator"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dynamic_grid_min_page_indicator_size"
+ android:theme="@style/HomeScreenElementTheme" />
- <include layout="@layout/all_apps"
+ <include
+ android:id="@+id/drop_target_bar"
+ layout="@layout/drop_target_bar" />
+
+ <include
android:id="@+id/apps_view"
+ layout="@layout/all_apps"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
diff --git a/res/layout/page_indicator.xml b/res/layout/page_indicator.xml
deleted file mode 100644
index 7de0cde..0000000
--- a/res/layout/page_indicator.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.launcher3.pageindicators.PageIndicatorLine
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:theme="@style/HomeScreenElementTheme"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dynamic_grid_min_page_indicator_size" />
diff --git a/res/layout/system_shortcut_icon_only.xml b/res/layout/system_shortcut_icon_only.xml
index c59cb53..b8b5b8c 100644
--- a/res/layout/system_shortcut_icon_only.xml
+++ b/res/layout/system_shortcut_icon_only.xml
@@ -20,5 +20,6 @@
android:layout_height="@dimen/system_shortcut_header_icon_touch_size"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:tint="?android:attr/textColorHint"
+ android:tintMode="src_in"
android:padding="@dimen/system_shortcut_header_icon_padding"
android:theme="@style/PopupItem" />
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 09f0920..9d0158b 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Werk"</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_body" msgid="5834430249581360068">"Elke werkprogram het \'n oranje kenteken, wat beteken dat dit deur jou organisasie veilig gehou word. Werkprogramme kan na jou tuisskerm geskuif word vir makliker toegang."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 462c91d..56742d3 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -132,4 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"የግል"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"ሥራ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"የሥራ መገለጫ"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"የስራ መተግበሪያዎችን እዚህ ያግኙ"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"እያንዳንዱ የሥራ መተግበሪያ ብርቱካናማ ባጅ አለው እና በእርስዎ ድርጅት በኩል ደህንነቱ ተጠብቋል። ለቀለለ መዳረሻ መተግበሪያዎችን ወደ የእርስዎ መነሻ ማያ ገጽ ያንቀሳቅሱ።"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"በእርስዎ ድርጅት የሚተዳደር"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"ማሳወቂያዎች እና መተግበሪያዎች ጠፍተዋል"</string>
</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index eaf695f..17075ce 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"للعمل"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"الملف الشخصي للعمل"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"البحث عن تطبيقات العمل هنا"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"يحتوي كل تطبيق من تطبيقات العمل على شارة باللون البرتقالي، ويعني هذا أن مؤسستك تريد الحفاظ على أمان التطبيق. ويمكن نقل تطبيقات العمل إلى شاشتك الرئيسية للوصول إليها بسهولة."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"يحتوي كل تطبيق للعمل على شارة برتقالية اللون ويظل تحت حماية مؤسستك. يمكنك نقل التطبيقات إلى شاشتك الرئيسية لتسهيل الوصول."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"ملف شخصي للعمل تديره مؤسستك"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"الإشعارات والتطبيقات متوقفة."</string>
</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 7e9951b..1e42fe8 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"İş"</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_body" msgid="5834430249581360068">"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ülə bilər."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 72e7fc0..6fc1968 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</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_body" msgid="5834430249581360068">"Svaka poslovna aplikacija ima narandžastu značku, što znači da je štiti vaša organizacija. Poslovne aplikacije možete da premestite na početni ekran da biste im lakše pristupali."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 2bfb817..f9e73ca 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Праца"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Працоўны профіль"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Знайдзіце працоўныя праграмы тут"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Кожная працоўная праграма мае аранжавы значок, які азначае, што яна пад аховай арганізацыі. Працоўныя праграмы можна перамясціць на галоўны экран для больш простага доступу."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Кожная працоўная праграма мае аранжавы значок і знаходзіцца пад аховай вашай арганізацыі. Для больш простага доступу перамясціце праграмы на свой Галоўны экран."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Пад кіраваннем вашай арганізацыі"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Апавяшчэнні і праграмы выключаны"</string>
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 17bfcbc..86a79b3 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Служебни"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Служебен потребителски профил"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Тук можете да намерите служебните приложения"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Всяко служебно приложение има оранжева значка. Тя означава, че организацията ви се грижи за сигурността му. За по-лесен достъп до служебните приложения можете да ги преместите на началния екран."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Всяко служебно приложение има оранжева значка и организацията ви се грижи за сигурността му. За по-лесен достъп преместете приложенията на началния си екран."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Управлява се от организацията ви"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Известията и приложенията са изключени"</string>
</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 5e7d294..d7f61eb 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"অফিস"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"অফিসের প্রোফাইল"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"এখানে কাজের অ্যাপ্সগুলি খুঁজুন"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"প্রতিটি কাজের অ্যাপে একটি কমলা ব্যাজ রয়েছে যার মানে হল এটি আপনার সংস্থার দ্বারা সুরক্ষিত। সহজে অ্যাক্সেসের জন্য আপনার হোম স্ক্রিন থেকে কাজের অ্যাপগুলি সরানো যেতে পারে।"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"প্রতিটি কাজের অ্যাপে একটি করে কমলা ব্যাজ রয়েছে এবং অ্যাপগুলি আপনার প্রতিষ্ঠানের দ্বারা সুরক্ষিত। সহজে অ্যাক্সেস করার জন্য অ্যাপগুলি হোম স্ক্রিনে রাখুন।"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"আপনার প্রতিষ্ঠানের দ্বারা পরিচালিত"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"বিজ্ঞপ্তি এবং অ্যাপ বন্ধ আছে"</string>
</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index ff7dd97..fbbab0e 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</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_body" msgid="5834430249581360068">"Svaka poslovna aplikacija ima narandžastu značku, što znači da je vaša organizacija osigurava. Radi lakšeg pristupa, poslovne aplikacije mogu se premjestiti na vaš Početni ekran."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index b1a875c..793b1c7 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Feina"</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_body" msgid="5834430249581360068">"Totes les aplicacions per a la feina tenen una insígnia taronja que indica que estan protegides per la teva organització. Pots col·locar-les a la pantalla d\'inici per poder-hi accedir més fàcilment."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index c7bf896..0d73f82 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Pracovní"</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_body" msgid="5834430249581360068">"Každý pracovní profil má oranžový odznak, který označuje, že je profil zabezpečen vaší organizací. Pracovní aplikace si můžete pro jednoduchost přesunout na plochu."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 00fe5bc..27d615a 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Arbejde"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbejdsprofil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find arbejdsapps her"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Alle arbejdsapps har et orange badge, hvilket betyder, at de beskyttes af din organisation. Arbejdsapps kan flyttes til din startskærm, så du nemmere har adgang til dem."</string>
+ <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>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Administreret af din organisation"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Underretninger og apps er slået fra"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 35d57ff..8fec587 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -133,6 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Geschäftlich"</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_body" msgid="5834430249581360068">"Jede App für die Arbeit hat ein orangefarbenes Logo, um zu zeigen, dass sich deine Organisation um die Sicherheit der App kümmert. Diese Apps können auf deinen Startbildschirm verschoben werden, damit du leichter auf sie zugreifen kannst."</string>
- <string name="managed_by_your_organisation" msgid="3989423660315876998">"Wird von deiner Organisation verwaltet"</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 1ec2dda..a78b820 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Εργασίας"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Προφίλ εργασίας"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Βρείτε όλες τις εφαρμογές εργασίας εδώ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Κάθε εφαρμογή εργασίας φέρει ένα πορτοκαλί σήμα, το οποίο σημαίνει ότι διατηρείται ασφαλής από τον οργανισμό σας. Οι εφαρμογές εργασίας μπορούν να μετακινηθούν στην Αρχική οθόνη, για να έχετε πιο εύκολη πρόσβαση."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Κάθε εφαρμογή εργασίας φέρει ένα πορτοκαλί σήμα και διατηρείται ασφαλής από τον οργανισμό σας. Μετακινήστε τις εφαρμογές εργασίας στην Αρχική οθόνη, για να έχετε πιο εύκολη πρόσβαση."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Διαχειριζόμενο από τον οργανισμό σας"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Οι ειδοποιήσεις και οι εφαρμογές είναι απενεργοποιημένες"</string>
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 4430e84..11389d4 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -132,4 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
+ <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>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 4430e84..11389d4 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -132,4 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
+ <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>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 4430e84..11389d4 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -132,4 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
+ <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>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 41563d4..5a13087 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Laborales"</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_body" msgid="5834430249581360068">"Cada app de trabajo tiene una insignia naranja, que indica que la protege tu organización. Puedes mover las apps de trabajo a la pantalla principal para acceder a ellas con mayor facilidad."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 812acff..1f1e3b7 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -46,7 +46,7 @@
<string name="all_apps_home_button_label" msgid="252062713717058851">"Inicio"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Datos de aplicación"</string>
+ <string name="app_info_drop_target_label" msgid="692894985365717661">"Información de la aplicación"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación añada accesos directos sin intervención del usuario."</string>
@@ -132,4 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</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="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Aplicaciones de trabajo"</string>
+ <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>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Administrada por tu organización"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Las notificaciones y las aplicaciones están desactivadas"</string>
</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index a2b52ad..162da73 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Töö"</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_body" msgid="5834430249581360068">"Igal töörakendusel on oranž märk, mis tähendab, et teie organisatsioon tagab selle turvalisuse. Töörakendused saab teisaldada avaekraanile, et neile oleks lihtsam juurde pääseda."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 28ea856..3f137e4 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -132,4 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Pertsonalak"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Lanekoak"</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_body" msgid="1485375451542813426">"Laneko aplikazio bakoitzak bereizgarri laranja bat dauka eta erakundeak babesten du. Aplikazioak errazago atzitzeko, eraman itzazu hasierako pantailara."</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>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index c87d8d4..f4b000d 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"محل کار"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"نمایه کاری"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"اینجا برنامههای کاری را پیدا کنید"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"همه برنامههای کاری نشان نارنجیرنگی دارند؛ به این معنی که برنامه توسط سازمان شما امن نگه داشته میشود. برنامههای کاری میتوانند برای دسترسی آسانتر به صفحه اصلی شما منتقل شوند."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"همه برنامههای کاری نشان نارنجیرنگی دارند و توسط سازمان شما امن نگه داشته میشود. برنامههای کاری را برای دسترسی آسانتر به صفحه اصلی انتقال دهید."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"توسط سازمانتان مدیریت میشود"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"اعلانها و برنامهها خاموش هستند"</string>
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 1c5698b..6146ef9 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Työsovellukset"</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_body" msgid="5834430249581360068">"Jokaisessa työsovelluksessa on oranssi merkki osoittamassa, että sovellus on organisaatiosi suojaama. Voit siirtää työsovelluksia aloitusnäytölle käytön helpottamiseksi."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index c5b8455..43bcc5c 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Travail"</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_body" msgid="5834430249581360068">"Chaque application professionnelle comporte un badge orange, ce qui signifie qu\'elle est sécurisée par votre organisation. Les applications professionnelles peuvent être déplacées vers votre écran d\'accueil pour y accéder plus facilement."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 5491a10..8994ef4 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Professionnelles"</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_body" msgid="5834430249581360068">"Les applications professionnelles sont accompagnées d\'un badge orange, indiquant qu\'elles sont sécurisées par votre organisation. Vous pouvez les déplacer vers votre écran d\'accueil pour y accéder plus facilement."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index f971aa9..f7b433b 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"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_body" msgid="5834430249581360068">"As aplicacións do traballo teñen unha insignia laranxa, o que significa que están protexidas pola túa organización. Pódense trasladar á pantalla de inicio para acceder a elas de forma máis fácil."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index a3df2b7..c292826 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"કાર્યાલયની ઍપ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"કાર્યાલયની પ્રોફાઇલ"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"કાર્ય ઍપને અહીંથી મેળવો"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"દરેક કાર્ય ઍપ પાસે એક નારંગી બૅજ હોય છે, જેનો અર્થ એમ કે તમારી સંસ્થા દ્વારા તેને સુરક્ષિત રાખવામાં આવે છે. વધુ સરળ ઍક્સેસ માટે કાર્ય ઍપને તમારી હોમ સ્ક્રીન પર ખસેડી શકાય છે."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"દરેક કાર્ય ઍપ પાસે એક નારંગી બૅજ હોય છે અને તમારી સંસ્થા દ્વારા તેને સુરક્ષિત રાખવામાં આવે છે. વધુ સરળ ઍક્સેસ માટે ઍપને તમારી હોમ સ્ક્રીન પર ખસેડો."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"તમારી સંસ્થા દ્વારા મેનેજ કરેલ"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"નોટિફિકેશન અને ઍપ બંધ છે"</string>
</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 31dff6b..5282a93 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -133,6 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"काम से जुड़े ऐप"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफ़ाइल"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"काम से जुड़े सभी ऐप्लिकेशन यहां पाएं"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"काम से जुड़े हर ऐप्लिकेशन पर एक नारंगी बैज होता है. इसका मतलब यह है कि यह ऐप्लिकेशन आपके संगठन की ओर से सुरक्षित किया जाता है. आसानी से इस्तेमाल के लिए, काम से जुड़े ऐप्लिकेशन होम स्क्रीन पर ले जाए जा सकते हैं."</string>
- <string name="managed_by_your_organisation" msgid="3989423660315876998">"आपके संगठन की ओर से प्रबंधित किया गया"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"काम से जुड़े हर ऐप्लिकेशन पर एक नारंगी रंग का बैज (निशान) होता है जिसकी सुरक्षा आपका संगठन करता है. आसानी से इस्तेमाल करने के लिए ऐप्लिकेशन को अपनी होम स्क्रीन पर ले जाएं."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"आपका संगठन प्रबंधित कर रहा है"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"सूचनाएं और ऐप्लिकेशन बंद हैं"</string>
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 53288ea..42eb733 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Posao"</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_body" msgid="5834430249581360068">"Svaka radna aplikacija ima narančastu značku, što znači da ima zaštitu vaše organizacije. Radne aplikacije mogu se premjestiti na početni zaslon radi lakšeg pristupa."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index dc09950..db39449 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Munkahelyi"</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_body" msgid="5834430249581360068">"A munkahelyi alkalmazásokon narancs jelvény található, ami azt jelenti, hogy szervezete gondoskodik biztonságukról. A munkahelyi alkalmazásokat áthelyezheti a kezdőképernyőre a könnyebb hozzáférhetőség érdekében."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 52a69e3..611a038 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Աշխատանքային"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Աշխատանքային պրոֆիլ"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Գտեք աշխատանքային հավելվածներ այստեղ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Աշխատանքային հավելվածները նշված են նարնջագույն նշանակով, ինչը ցույց է տալիս, որ ձեր կազմակերպությունը պաշտպանված է։ Հարմարության համար աշխատանքային հավելվածները կարող եք տեղափոխել հիմնական էկրան։"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Աշխատանքային հավելվածները նշված են նարնջագույն նշանով, նման հավելվածների անվտանգությունը ապահովում է ձեր կազմակերպությունը։ Հարմարության համար աշխատանքային հավելվածները կարող եք տեղափոխել հիմնական էկրան։"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Կառավարվում է ձեր կազմակերպության կողմից"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Ծանուցումներն ու հավելվածներն անջատված են"</string>
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 5112223..ff49b49 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -60,9 +60,9 @@
<string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini adalah aplikasi sistem dan tidak dapat dicopot pemasangannya."</string>
<string name="folder_hint_text" msgid="6617836969016293992">"Folder Tanpa Nama"</string>
<string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> dinonaktifkan"</string>
- <string name="default_scroll_format" msgid="7475544710230993317">"Laman %1$d dari %2$d"</string>
+ <string name="default_scroll_format" msgid="7475544710230993317">"Halaman %1$d dari %2$d"</string>
<string name="workspace_scroll_format" msgid="8458889198184077399">"Layar utama %1$d dari %2$d"</string>
- <string name="workspace_new_page" msgid="257366611030256142">"Laman layar utama baru"</string>
+ <string name="workspace_new_page" msgid="257366611030256142">"Halaman layar utama baru"</string>
<string name="folder_opened" msgid="94695026776264709">"Folder dibuka, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
<string name="folder_tap_to_close" msgid="4625795376335528256">"Ketuk untuk menutup folder"</string>
<string name="folder_tap_to_rename" msgid="4017685068016979677">"Ketuk untuk menyimpan ganti nama"</string>
@@ -129,4 +129,11 @@
<string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pintasan dan <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notifikasi untuk <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
<string name="action_dismiss_notification" msgid="5909461085055959187">"Tutup"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"Notifikasi ditutup"</string>
+ <string name="all_apps_personal_tab" msgid="4190252696685155002">"Pribadi"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"Kantor"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Temukan aplikasi kerja di sini"</string>
+ <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>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Dikelola oleh organisasi"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Notifikasi dan aplikasi nonaktif"</string>
</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index bda651a..c3988f3 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Vinna"</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_body" msgid="5834430249581360068">"Öll vinnuforrit eru með appelsínugulu merki sem þýðir að fyrirtækið þitt tryggir öryggi þess. Hægt er að flytja vinnuforrit á heimaskjáinn fyrir auðveldari aðgang."</string>
+ <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>
+ <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>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 82f6949..174949e 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Lavoro"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profilo di lavoro"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Qui puoi trovare le tue app di lavoro"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Ogni app di lavoro è contrassegnata da un badge arancione, che indica che è protetta dalla tua organizzazione. Le app di lavoro possono essere spostate sulla schermata Home per accedervi più facilmente."</string>
+ <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>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Gestito dalla tua organizzazione"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Le notifiche e le app non sono attive"</string>
</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 44a872c..db156e1 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -133,6 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"עבודה"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"פרופיל עבודה"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ניתן למצוא כאן את אפליקציות העבודה"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"לכל אפליקציית עבודה יש תג כתום, וזה אומר שאבטחתה מטופלת בידי הארגון. ניתן להעביר אפליקציות עבודה אל מסך דף הבית כדי להקל את הגישה אליהן."</string>
- <string name="managed_by_your_organisation" msgid="3989423660315876998">"מנוהל בידי הארגון שלך"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"לכל אפליקציית עבודה יש תג כתום ואבטחתה מטופלת בידי הארגון. אפשר להעביר אפליקציות אל מסך דף הבית כדי להקל את הגישה אליהן."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"מנוהל בידי הארגון"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"הודעות ואפליקציות כבויות"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 50d8aed..527cb95 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"仕事用"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"仕事用プロファイル"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ここには仕事用アプリが表示されます"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"仕事用アプリにはオレンジのバッジが表示されています。これは、組織によってアプリが安全に保護されていることを示します。簡単にアクセスできるよう、仕事用アプリはホーム画面に移動できます。"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"仕事用アプリにはオレンジのバッジが表示され、組織によって安全に保護されています。仕事用アプリをホーム画面に移動すると、簡単にアクセスできます。"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"組織によって管理されています"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"通知とアプリは OFF です"</string>
</resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index ce85187..7e1752c 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"სამსახური"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"სამსახურის პროფილი"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"აქ თავმოყრილია სამსახურის აპები"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"სამსახურის აპები მონიშნულია სტაფილოსფერი ბეჯით, რაც ნიშნავს, რომ მათ უსაფრთხოებას უზრუნველყოფს თქვენი ორგანიზაცია. მარტივი წვდომისთვის შეგიძლიათ სამსახურის აპები მთავარი ეკრანზე გადაიტანოთ."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"სამსახურის აპები მონიშნულია სტაფილოსფერი ბეჯით, რაც ნიშნავს, რომ მათ უსაფრთხოებას თქვენი ორგანიზაცია უზრუნველყოფს. მარტივი წვდომისთვის, შეგიძლიათ სამსახურის აპები მთავარი ეკრანზე გადაიტანოთ."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"იმართება თქვენი ორგანიზაციის მიერ"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"შეტყობინებები და აპები გამორთულია"</string>
</resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 4ce0e95..ef92146 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Жұмыс"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Жұмыс профилі"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Жұмыс қолданбалары осы жерде берілген"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Әрбір жұмыс қолданбасында қызғылт сары танымбелгі бар. Ол оның қауіпсіздігі ұйым арқылы қамтамасыз етілетінін білдіреді. Жұмыс қолданбаларына оңай кіру үшін, оларды Негізгі экранға жылжытуға болады."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Әрбір жұмыс қолданбасында қызғылт сары танымбелгі бар. Ол оның қауіпсіздігі ұйым арқылы қамтамасыз етілетінін білдіреді. Жұмыс қолданбаларына оңай кіру үшін, оларды Негізгі экранға жылжытуға болады."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Ұйым арқылы басқарылады"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Хабарландырулар мен қолданбалар өшірулі"</string>
</resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 1f27cd5..e52e0b2 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"ការងារ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"កម្រងព័ត៌មានការងារ"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ស្វែងរកកម្មវិធីការងារនៅទីនេះ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"កម្មវិធីការងារនីមួយៗមានស្លាកសញ្ញាពណ៌ទឹកក្រូច ដែលមានន័យថាវាត្រូវបានរក្សាទុកយ៉ាងមានសុវត្ថិភាពដោយស្ថាប័នរបស់អ្នក។ កម្មវិធីការងារអាចត្រូវបានផ្លាស់ទីទៅកាន់អេក្រង់ដើមរបស់អ្នកសម្រាប់ការចូលប្រើដែលកាន់តែងាយស្រួលជាងមុន។"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"កម្មវិធីការងារនីមួយៗមានស្លាកពណ៌ទឹកក្រូច និងត្រូវបានរក្សាទុកយ៉ាងមានសុវត្ថិភាពដោយស្ថាប័នរបស់អ្នក។ សូមផ្លាស់ទីកម្មវិធីទៅកាន់អេក្រង់ដើមរបស់អ្នក ដើម្បីងាយស្រួលចូលប្រើជាងមុន។"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"គ្រប់គ្រងដោយស្ថាប័នរបស់អ្នក"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"ការជូនដំណឹង និងកម្មវិធីត្រូវបានបិទ"</string>
</resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 00f6dcf..4bb0d22 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"ಕೆಲಸ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಇಲ್ಲಿ ಹುಡುಕಿ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"ಕೆಲಸದ ಪ್ರತಿ ಅಪ್ಲಿಕೇಶನ್ ಕಿತ್ತಳೆ ಬ್ಯಾಡ್ಜ್ ಹೊಂದಿದೆ, ಅಂದರೆ ಇದು ನಿಮ್ಮ ಸಂಸ್ಥೆಯಿಂದ ಸುರಕ್ಷಿತವಾಗಿದೆ ಎಂದರ್ಥ. ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಸುಲಭ ಪ್ರವೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಮುಖಪುಟ ಪರದೆಗೆ ಸರಿಸಬಹುದು."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ಕೆಲಸದ ಪ್ರತಿ ಅಪ್ಲಿಕೇಶನ್ ಕಿತ್ತಳೆ ಬ್ಯಾಡ್ಜ್ ಹೊಂದಿದೆ ಮತ್ತು ನಿಮ್ಮ ಸಂಸ್ಥೆಯಿಂದ ಸುರಕ್ಷಿತವಾಗಿ ಇರಿಸಲಾಗುತ್ತದೆ. ಸುಲಭ ಪ್ರವೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಸರಿಸಿ."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗಿದೆ"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"ಅಧಿಸೂಚನೆಗಳು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್ಗಳು ಆಫ್ ಆಗಿವೆ"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 14df51d..a50a107 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"직장"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"직장 프로필"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"여기에서 업무용 앱 찾기"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"각 업무용 앱에는 주황색 배지가 있으며 이는 조직에서 안전하게 보호함을 의미합니다. 업무용 앱은 홈 화면으로 이동하여 더 간편하게 사용할 수 있습니다."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"각 업무용 앱에는 주황색 배지가 있으며 업무용 앱은 조직에서 안전하게 보호됩니다. 앱을 홈 화면으로 이동하여 더 간편하게 사용하세요."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"조직에서 관리"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"알림 및 앱 사용 중지됨"</string>
</resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 3765649..e2fde48 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Жумуш колдонмолору"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Жумуш профили"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Жумуш колдонмолорун бул жерден таап алыңыз"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Ар бир жумуш колдонмосунун кызгылт сары бейджиги бар, ал уюмуңуз тарабынан коопсуздалганын билдирет. Жумуш колдонмолоруна тез өтүү үчүн аларды Башкы экранга кошуп алсаңыз болот."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Ар бир жумуш колдонмосунун кызгылт сары бейджиги бар жана ал уюмуңуз тарабынан коопсуз сакталат. Колдонмолорго тез өтүү үчүн аларды Башкы экранга кошуп алыңыз."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Уюмуңуз тарабынан башкарылат"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Билдирүүлөр жана колдонмолор өчүрүлгөн"</string>
</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index b826c35..3099d1f 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"ວຽກ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ຊອກຫາແອັບວຽກຢູ່ບ່ອນນີ້"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"ແຕ່ລະແອັບວຽກຈະມີປ້າຍສີສົ້ມ, ເຊິ່ງໝາຍຄວາມວ່າມັນຈະຖືກຮັກສາຄວາມປອດໄພໂດຍອົງກອນຂອງທ່ານ. ແຕ່ລະແອັບຈະສາມາດຍ້າຍໄປໃສ່ໜ້າຈໍຫຼັກເພື່ອເຂົ້າເຖິງໄດ້ງ່າຍຂຶ້ນໄດ້."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ແຕ່ລະແອັບວຽກຈະມີປ້າຍສີສົ້ມ ແລະ ຖືກຈັດເກັບໄວ້ຢ່າງປອດໄພໂດຍອົງກອນຂອງທ່ານ. ທ່ານສາມາດຍ້າຍແອັບໄປໃສ່ໜ້າຈໍຫຼັກເພື່ອໃຫ້ເຂົ້າໃຊ້ງ່າຍຂຶ້ນໄດ້."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"ຈັດການໂດຍອົງກອນຂອງທ່ານ"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"ການແຈ້ງເຕືອນ ແລະ ແອັບຖືກປິດໄວ້"</string>
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 01fa0b1..5b2e951 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Darbo"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Darbo profilis"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Darbo programas rasite čia"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Kiekvienoje darbo programoje yra oranžinis ženklelis, o tai reiškia, kad ji saugi jūsų organizacijai. Darbo programas galima perkelti į pagrindinį ekraną, kad būtų lengviau pasiekti."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Kiekvienai darbo programai priskirtas oranžinis ženklelis, o tokių programų sauga rūpinasi jūsų organizacija. Perkelkite darbo programas į pagrindinį ekraną, kad galėtumėte lengviau jas pasiekti."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Tvarko jūsų organizacija"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Programos ir pranešimai išjungti"</string>
</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index a19e32f..eec27b1 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Darba lietotnes"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Darba profils"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Meklējiet darba lietotnes šeit"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Katrai darba lietotnei ir oranža emblēma — tas nozīmē, ka jūsu organizācija to aizsargā. Ērtākai piekļuvei darba lietotnes var pārvietot uz sākuma ekrānu."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Katrai darba lietotnei ir oranža emblēma, un jūsu organizācija aizsargā šīs lietotnes. Ērtākai piekļuvei pārvietojiet darba lietotnes uz sākuma ekrānu."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Pārvalda jūsu organizācija"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Paziņojumi un lietotnes ir izslēgtas"</string>
</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 0aaed62..53944cb 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -129,4 +129,11 @@
<string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> кратенки и <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> известувања за <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
<string name="action_dismiss_notification" msgid="5909461085055959187">"Отфрли"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"Известувањето е отфрлено"</string>
+ <string name="all_apps_personal_tab" msgid="4190252696685155002">"Лично"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"За работа"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"Работен профил"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Најдете апликации за работа тука"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Секоја апликација за работа има портокалова значка и е обезбедена од вашата организација. За полесен пристап, апликациите за работа преместете ги на почетниот екран."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Управувано од вашата организација"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Известувањата и апликациите се исклучени"</string>
</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 63f32bc..c247c4e 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"ജോലി"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ഔദ്യോഗിക ആപ്പുകൾ ഇവിടെ കണ്ടെത്തുക"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"എല്ലാ ഔദ്യോഗിക ആപ്പിനും ഓറഞ്ച് നിറത്തിലുള്ള ഒരു ബാഡ്ജ് ഉണ്ടാകും, നിങ്ങളുടെ ഓർഗനൈസേഷൻ അത് സുരക്ഷിതമാക്കി സൂക്ഷിക്കുന്നുണ്ട് എന്നാണ് അതിനർത്ഥം. എളുപ്പത്തിൽ ആക്സസ് ചെയ്യാനായി ഔദ്യോഗിക ആപ്പുകൾ ഹോം സ്ക്രീനിലേക്ക് നീക്കാം."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"എല്ലാ ഔദ്യോഗിക ആപ്പിനും ഓറഞ്ച് നിറത്തിലുള്ള ഒരു ബാഡ്ജ് ഉണ്ട്, നിങ്ങളുടെ സ്ഥാപനം അത് സുരക്ഷിതമായി സൂക്ഷിക്കുന്നു. എളുപ്പത്തിൽ ആക്സസ് ചെയ്യാൻ ആപ്പുകളെ ഹോം സ്ക്രീനിലേക്ക് നീക്കുക."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"നിങ്ങളുടെ സ്ഥാപനം നിയന്ത്രിക്കുന്നത്"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"അറിയിപ്പുകളും ആപ്പുകളും ഓഫാണ്"</string>
</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 43ef36b..1deef00 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Ажил"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Ажлын профайл"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Ажлын аппыг эндээс олно уу"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Ажлын апп тус бүр танай байгууллагаас аюулгүй хадгалж буйг илтгэх улбар шар тэмдэгтэй байна. Ажлын аппад илүү хялбараар хандахын тулд үүнийг Үндсэн Нүүрэнд зөөх боломжтой."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Ажлын апп тус бүр улбар шар тэмдэгтэй ба эдгээрийг танай байгууллагаас аюулгүй байлгадаг. Аппуудад хялбараар хандахын тулд тэдгээрийг Үндсэн Нүүрэнд зөөнө үү."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Танай байгууллагаас удирддаг"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Мэдэгдэл, апп унтраалттай байна"</string>
</resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 4708b7a..c11883d 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"कार्यालय"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफाइल"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"कामाची अॅप्स येथे मिळवा"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"कामाच्या प्रत्येक अॅपला एक ऑरेंज बॅज असतो, याचाच अर्थ तुमच्या संस्थेने ते सुरक्षित ठेवलेले आहे असा होतो. आणखी सोप्या अॅक्सेससाठी कामाची अॅप्स तुमच्या होमस्क्रीनवर हलवता येऊ शकतात."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"प्रत्येक कार्य अॅपमध्ये नारिंगी बॅज असतो आणि तो तुमच्या संस्थेकडून सुरक्षित ठेवला जातो. अधिक सहज अॅक्सेससाठी अॅप्स तुमच्या होम स्क्रीनवर हलवा."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"तुमच्या संस्थेकडून व्यवस्थापित"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"सूचना आणि अॅप्स बंद आहेत"</string>
</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index dbb4884..f88fe96 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Kerja"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Temui apl kerja di sini"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Setiap apl kerja mempunyai lencana oren yang bermaksud dipastikan selamat oleh organisasi anda. Apl kerja boleh dialihkan ke Skrin Utama anda untuk akses yang lebih mudah."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Setiap apl kerja terdapat lencana berwarna oren dan dilindungi oleh organisasi anda. Alihkan apl ke Skrin Utama untuk akses yang lebh mudah."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Diurus oleh organisasi anda"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Pemberitahuan dan apl dimatikan"</string>
</resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 9c0aca6..f44f28c 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"အလုပ်"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"အလုပ်ပရိုဖိုင်"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"အလုပ်အက်ပ်များကို ဤနေရာတွင်ရှာဖွေပါ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"အလုပ်အက်ပ် တစ်ခုစီတိုင်းတွင် သင့်အဖွဲ့အစည်းက လုံခြုံစိတ်ချရသည်ဟု ဆိုလိုသည့် လိမ္မော်ရောင်တံဆိပ်ပါရှိသည်။ ပိုမိုလွယ်ကူစွာ သုံးရန်အတွက် အလုပ်အက်ပ်များကို သင့်ပင်မစာမျက်နှာသို့ ရွှေ့နိုင်ပါသည်။"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"အလုပ်အက်ပ်တိုင်းတွင် လိမ္မော်ရောင်တံဆိပ် တစ်ခုစီရှိပြီး သင်၏ အဖွဲ့အစည်းက လုံခြုံအောင် ထားရှိပါသည်။ အသုံးပြုရ ပိုမိုလွယ်ကူစေရန် အက်ပ်များကို သင်၏ ပင်မမျက်နှာပြင်သို့ ရွှေ့ပါ။"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"သင်၏ အဖွဲ့အစည်းက စီမံခန့်ခွဲထားပါသည်"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"အကြောင်းကြားချက်များနှင့် အက်ပ်များကို ပိတ်ထားသည်"</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 5f2493d..ee374f8 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Jobb"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Jobbprofil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Finn jobbapper her"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Alle jobbapper har et oransje merke. Det betyr at de sikres av organisasjonen din. Jobbapper kan flyttes til startskjermen for å gjøre det enklere å finne dem."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Alle jobbapper har et oransje merke og sikres av organisasjonen din. Flytt apper til startskjermen for å gjøre det enklere å finne dem."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Administreres av organisasjonen din"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Varsler og apper er slått av"</string>
</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index e140eb3..8d6819a 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"कार्यसम्बन्धी"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफाइल"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"कार्यसम्बन्धी अनुप्रयोगहरू यहाँ प्राप्त गर्नुहोस्"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"कार्यसम्बन्धी प्रत्येक अनुप्रयोगमा एउटा सुन्तला रङको ब्याज छ, जसको अर्थ यसलाई तपाईंको संगठनद्वारा सुरक्षित राखिएको छ भन्ने हो। अझ सजिलो गरी पहुँच राख्नका लागि कार्यसम्बन्धी अनुप्रयोगहरूलाई तपाईंको गृहस्क्रिनमा सार्न सकिन्छ।"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"कार्यसम्बन्धी प्रत्येक अनुप्रयोगमा एउटा सुन्तला रङको ब्याज छ र यसलाई तपाईंको संगठनद्वारा सुरक्षित राखिएको छ । अझ सजिलो गरी पहुँच राख्नका लागि कार्यसम्बन्धी अनुप्रयोगहरूलाई तपाईंको गृहस्क्रिनमा सार्नुहोस्।"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"तपाईंको सङ्गठनले व्यवस्थापन गरेको"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"सूचना र अनुप्रयोगहरू निष्क्रिय छन्"</string>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 16a79ae..a9123bd 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -100,7 +100,7 @@
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> wordt gedownload, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> wacht op installatie"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-widgets"</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Toevoegen aan homepage"</string>
+ <string name="action_add_to_workspace" msgid="8902165848117513641">"Toevoegen aan startscherm"</string>
<string name="action_move_here" msgid="2170188780612570250">"Item hier naartoe verplaatsen"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item toegevoegd aan startscherm"</string>
<string name="item_removed" msgid="851119963877842327">"Item verwijderd"</string>
@@ -129,4 +129,11 @@
<string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> snelkoppelingen en <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> meldingen voor <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
<string name="action_dismiss_notification" msgid="5909461085055959187">"Sluiten"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"Melding gesloten"</string>
+ <string name="all_apps_personal_tab" msgid="4190252696685155002">"Privé"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"Werk"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"Werkprofiel"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Zoek hier naar werk-apps"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Elke werk-app heeft een oranje badge en wordt beveiligd door je organisatie. Verplaats apps naar je startscherm om gemakkelijker toegang te krijgen."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Beheerd door je organisatie"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Meldingen en apps zijn uitgeschakeld"</string>
</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 6672c20..602bc34 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"ਕਾਰਜ-ਸਥਾਨ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ਕਾਰਜ-ਸਥਾਨ ਐਪਾਂ ਇੱਥੇ ਲੱਭੋ"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"ਹਰੇਕ ਕਾਰਜ-ਸਥਾਨ ਐਪ ਦਾ ਇੱਕ ਸੰਤਰੀ ਬੈਜ ਹੈ, ਜਿਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਉਸਨੂੰ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਰੱਖਿਆ ਜਾਂਦਾ ਹੈ। ਕਾਰਜ-ਸਥਾਨ ਐਪਾਂ ਨੂੰ ਤੁਹਾਡੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਜਾਇਆ ਜਾ ਸਕਦਾ ਹੈ ਤਾਂ ਕਿ ਉਹਨਾਂ \'ਤੇ ਵਧੇਰੇ ਆਸਾਨੀ ਨਾਲ ਪਹੁੰਚ ਕੀਤੀ ਜਾ ਸਕੇ।"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ਹਰੇਕ ਕਾਰਜ-ਸਥਾਨ ਐਪ ਦਾ ਇੱਕ ਸੰਤਰੀ ਬੈਜ ਹੁੰਦਾ ਹੈ ਅਤੇ ਉਸਨੂੰ ਤੁਹਾਡੀ ਸੰਸਥਾ ਰਾਹੀਂ ਸੁਰੱਖਿਅਤ ਰੱਖਿਆ ਜਾਂਦਾ ਹੈ। ਵਧੇਰੇ ਆਸਾਨ ਪਹੁੰਚ ਲਈ ਐਪਾਂ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਜਾਓ।"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"ਸੂਚਨਾਵਾਂ ਅਤੇ ਐਪਾਂ ਬੰਦ ਹਨ"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 4431718..0db8d62 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Praca"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil do pracy"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Aplikacje do pracy"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Każda aplikacja do pracy ma pomarańczową plakietkę, która oznacza, że o jej bezpieczeństwo dba Twoja organizacja. Aplikacje do pracy można przenieść na ekran główny, by były łatwiej dostępne."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Każda aplikacja do pracy ma pomarańczową plakietkę, a o jej bezpieczeństwo dba Twoja organizacja. Aplikacje można przenieść na ekran główny, by były łatwiej dostępne."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Profil zarządzany przez Twoją organizację"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Powiadomienia i aplikacje są wyłączone"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 3e34e16..ca4a1c6 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -132,8 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Pessoal"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Trabalho"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabalho"</string>
- <!-- no translation found for bottom_work_tab_user_education_title (5785851780786322825) -->
- <skip />
- <!-- no translation found for bottom_work_tab_user_education_body (5834430249581360068) -->
- <skip />
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Encontrar as aplicações de trabalho aqui"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Cada aplicação de trabalho apresenta um emblema laranja, pelo que a sua entidade a mantém em segurança. Pode mover as aplicações para o ecrã principal para facilitar o acesso."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Gerido pela sua entidade"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"As notificações e as aplicações estão desativadas."</string>
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 07970f7..77cc50f 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -132,4 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Pessoais"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Comerciais"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabalho"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Localizar apps de trabalho aqui"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Cada app de trabalho tem um selo laranja e é mantido em segurança pela sua organização. Mova os apps para sua tela inicial para facilitar o acesso."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Gerenciados pela sua organização"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"As notificações e os apps estão desativados"</string>
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 00cea3c..7b2409c 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -132,4 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Personale"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Profesionale"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil de serviciu"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Găsiți aplicații de serviciu aici"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Fiecare aplicație de serviciu are o insignă portocalie și este păstrată în siguranță de organizația dvs. Mutați aplicațiile de serviciu pe ecranul de pornire pentru acces mai ușor."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Gestionat de organizația dvs."</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Notificările și aplicațiile sunt dezactivate"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index cb5b977..5242322 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Рабочие"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Рабочий профиль"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Приложения для работы"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Рабочие приложения отмечены оранжевым значком, который подтверждает, что ваша организация гарантирует их безопасность. Для удобства вы можете перенести эти приложения на главный экран."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Рабочие приложения отмечены оранжевым значком, который подтверждает, что ваша организация гарантирует их безопасность. Для удобства перенесите эти приложения на главный экран."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Управляется вашей организацией"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Уведомления и приложения отключены."</string>
</resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 16ee89f..31d26e4 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -132,4 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"පුද්ගලික"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"කාර්යාලය"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"කාර්යාල පැතිකඩ"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"මෙහි කාර්යාල යෙදුම් සොයා ගන්න"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"සෑම කාර්යාල යෙදුමකම තැඹිලි ලාංඡනයක් ඇත ඇති අතර එය ඔබේ සංවිධානය විසින් සුරක්ෂිතව තබා ගනී. වඩා පහසුවෙන් පිවිසීමට යෙදුම් ඔබගේ මුල් පිටු තිරය වෙත ගෙන යන්න."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"ඔබේ සංවිධානය විසින් කළමනාකරණය කරනු ලැබේ"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"දැනුම්දීම් සහ යෙදුම් ක්රියාවිරහිතයි"</string>
</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index ba84811..9567889 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -129,4 +129,11 @@
<string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Odkazy (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) a upozornenia (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) pre aplikáciu <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
<string name="action_dismiss_notification" msgid="5909461085055959187">"Zavrieť"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"Upozornenie bolo zavreté"</string>
+ <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobné"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"Pracovné"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"Pracovný profil"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Tu nájdete pracovné aplikácie"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Všetky pracovné aplikácie majú oranžový štítok a sú bezpečne uchovávané vašou organizáciou. Ak chcete mať k aplikáciám ľahší prístup, presuňte ich na plochu."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Spravované vašou organizáciou"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Upozornenia a aplikácie sú vypnuté"</string>
</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index c317c0e..ca59140 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -129,4 +129,11 @@
<string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Bližnjice (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) in obvestila (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) aplikacije <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
<string name="action_dismiss_notification" msgid="5909461085055959187">"Opusti"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"Obvestilo je bilo opuščeno"</string>
+ <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osebno"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"Služba"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"Delovni profil"</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Tukaj poiščite delovne aplikacije"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Vsaka delovna aplikacija ima oranžno značko. Za varnost teh aplikacij skrbi vaša organizacija. Za preprostejši dostop premaknite aplikacije na začetni zaslon."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Upravlja vaša organizacija"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Obvestila in aplikacije – izklopljeno"</string>
</resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index e49e4fb..7f4c3bc 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Punë"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profili i punës"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Gjej këtu aplikacionet e punës"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Secili aplikacion pune ka një distinktiv portokalli, që do të thotë se mbahet i sigurt nga organizata jote. Aplikacionet e punës mund të zhvendosen në ekranin tënd kryesor për qasje më të lehtë."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Secili aplikacion pune ka një distinktiv portokalli dhe mbahet i sigurt nga organizata jote. Zhvendosi aplikacionet e punës në ekranin tënd kryesor për qasje më të lehtë."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Menaxhohet nga organizata jote"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Njoftimet dhe aplikacionet janë joaktive"</string>
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index dfad866..6d757fd 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Пословне"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Профил за Work"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Пронађите пословне апликације овде"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Свака пословна апликација има наранџасту значку, што значи да је штити ваша организација. Пословне апликације можете да преместите на почетни екран да бисте им лакше приступали."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Свака пословна апликација има наранџасту значку и штити је ваша организација. Преместите апликације на почетни екран да бисте им лакше приступали."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Овим управља организација"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Обавештења и апликације су искључени"</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 107673b..b61ed69 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Arbete"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Jobbprofil"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Här hittar du jobbappar"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Alla jobbappar har ett orange märke som symboliserar att organisationen ser till att de är säkra. Du kan flytta apparna till startskärmen så att du kommer åt dem lättare."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Alla jobbappar har ett orange märke och organisationen ser till att de är skyddade. Flytta apparna till startskärmen så kommer du åt dem lättare."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Hanteras av organisationen"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Aviseringar och appar är inaktiverade"</string>
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 1d3cfb2..05864fa 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -135,5 +135,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Kazini"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Wasifu wa kazini"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Pata programu za kazi hapa"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Kila programu ya kazi ina beji ya rangi ya machungwa, ambayo inamaanisha kuwa imehifadhiwa salama na shirika lako. Programu za kazi zinaweza kuwekwa kwenye skrini yako ya mwanzo ili uzifikie kwa urahisi."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Kila programu ya kazi ina beji ya rangi ya machungwa na hulindwa na shirika lako. Hamishia programu kwenye skrini yako ya kwanza ili uzifikie kwa urahisi."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Inasimamiwa na shirika lako"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Vipenge vya arifa na programu vimezimwa"</string>
</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 8a723e7..aafb982 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"பணி"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"பணி விவரம்"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"பணி ஆப்ஸை இங்கு காணலாம்"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"ஒவ்வொரு பணிப் பயன்பாட்டிற்கும் ஆரஞ்சு நிற பேட்ஜ் இருக்கும், அதாவது உங்கள் நிறுவனத்தால் இது பாதுகாப்பாக வைக்கப்பட்டுள்ளது. எளிதான அணுகலுக்காக, பணி ஆப்ஸை உங்கள் முகப்புத் திரைக்கு நகர்த்திக்கொள்ளலாம்."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ஒவ்வொரு பணிப் பயன்பாடும் ஆரஞ்சு நிற பேட்ஜைக் கொண்டிருக்கும். இவை, உங்கள் நிறுவனத்தால் பாதுகாப்பாக வைக்கப்பட்டுள்ளன. இந்த ஆப்ஸை எளிதாக அணுக, முகப்புத் திரைக்கு நகர்த்திக்கொள்ளவும்."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"உங்கள் நிறுவனம் நிர்வகிக்கிறது"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"ஆப்ஸும் அறிவிப்புகளும் ஆஃப் செய்யப்பட்டுள்ளன"</string>
</resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 7d64ef3..83d32f2 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"కార్యాలయం"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"కార్యాలయ ప్రొఫైల్"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"కార్యాలయ యాప్లను ఇక్కడ కనుగొనండి"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"ప్రతి కార్యాలయ యాప్కు నారింజ బ్యాడ్జ్ ఉంది, అంటే ఇది మీ సంస్థ ద్వారా సురక్షితంగా ఉంచబడుతుంది. సులభ యాక్సెస్ కోసం కార్యాలయ యాప్లు, మీ హోమ్ స్క్రీన్కి తరలించబడవచ్చు."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ప్రతి కార్యాలయ యాప్కు నారింజ బ్యాడ్జ్ ఉంది మరియు మీ సంస్థ ద్వారా సురక్షితంగా ఉంచబడుతుంది. సులభ యాక్సెస్ కోసం యాప్లను మీ హోమ్ స్క్రీన్కి తరలించండి."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"మీ సంస్థ ద్వారా నిర్వహించబడతాయి"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"నోటిఫికేషన్లు మరియు యాప్లు ఆఫ్ చేయబడ్డాయి"</string>
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 69ff0a2..5006d2e 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"งาน"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"โปรไฟล์งาน"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"หาแอปงานที่นี่"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"แอปงานแต่ละแอปมีป้ายสีส้ม ซึ่งหมายความว่าองค์กรรักษาความปลอดภัยให้อยู่ คุณสามารถย้ายแอปงานไปไว้ที่หน้าจอหลักเพื่อให้เข้าถึงได้ง่ายขึ้น"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"แอปงานแต่ละแอปมีป้ายสีส้มและได้รับการรักษาความปลอดภัยจากองค์กรของคุณ ย้ายแอปไปยังหน้าจอหลักเพื่อให้เข้าถึงได้ง่ายขึ้น"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"จัดการโดยองค์กร"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"ปิดการแจ้งเตือนและแอปอยู่"</string>
</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 9b228cd..de90f30 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Trabaho"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profile sa trabaho"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Maghanap ng mga app para sa trabaho rito"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"May orange na badge ang bawat app para sa trabaho, na nangangahulugang pinapanatili itong ligtas ng iyong organisasyon. Maaaring ilipat ang mga app para sa trabaho sa iyong Home Screen para sa mas madaling pag-access."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Ang bawat app para sa trabaho ay may orange na badge at pinapanatiling ligtas ng iyong organisasyon. Ilipat ang mga app sa iyong Home screen para mas madaling ma-access."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Pinamamahalaan ng iyong organisasyon"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Naka-off ang mga notification at app"</string>
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 0ced91c..d8184e4 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"İş"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"İş profili"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"İş uygulamalarını burada bulabilirsiniz"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Her iş uygulamasında turuncu bir rozet bulunur. Bu rozet, uygulamanın güvenliğinin kuruluşunuz tarafından sağlandığını gösterir. İş uygulamaları daha kolay erişim için Ana Ekranınıza taşınabilir."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Her iş uygulamasında, uygulama güvenliğinin kuruluşunuz tarafından sağlandığını gösteren turuncu bir rozet bulunur. Uygulamaları daha kolay erişim için Ana ekranınıza taşıyın."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Kuruluşunuz tarafından yönetiliyor"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Bildirimler ve uygulamalar kapalı"</string>
</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 832afab..eb0d2be 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Робочі додатки"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Робочий профіль"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Робочі додатки містяться тут"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Кожний робочий додаток має оранжевий значок, який указує, що його захищає організація. Для швидкого доступу робочі додатки можна перенести на головний екран."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Кожний робочий додаток має оранжевий значок. Його захищає організація. Для швидкого доступу перенесіть додатки на головний екран."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Профілем керує ваша організація"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Сповіщення та додатки вимкнено"</string>
</resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 53c8975..1070d89 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"دفتری"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"دفتری پروفائل"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"یہاں دفتری ایپس تلاش کریں"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"ہر دفتری ایپ میں نارنجی بَیج ہوتا ہے، جس کا مطلب ہے کہ آپ کے ادارے نے اسے محفوظ کر رکھا ہے۔ دفتری ایپس کو آسان تر رسائی کے لیے آپ کے ہوم اسکرین میں منتقل کیا جا سکتا ہے۔"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ہر دفتری ایپ میں نارنجی بَیج ہوتا ہے اور اسے آپ کی تنظیم محفوظ رکھتی ہے۔ زیادہ آسان رسائی کیلئے ایپس کو اپنی ہوم اسکرین پر منتقل کریں۔"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"آپ کی تنظیم کے زیر انتظام"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"اطلاعات اور ایپس آف ہیں"</string>
</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index cb5130d..54a4ec0 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -132,6 +132,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Shaxsiy"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Ishchi"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Ishchi profil"</string>
- <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Ishchi ilovalarni shu yerdan topish mumkin"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Apelsinrangli nishonga ega har bir ishchi ilova tashkilotingiz tomonidan himoyalanganini bildiradi. Ishchi ilovalarga osonroq kirish uchun ularni bosh ekranga chiqarish mumkin."</string>
+ <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Ishga oid ilovalarni shu yerdan topish mumkin"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Apelsinrangli nishonga ega har bir ishga oid ilova tashkilotingiz tomonidan himoyalanadi. Ishga oid ilovalarga osonroq kirish uchun ularni bosh ekranga chiqaring."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Tashkilotingiz tomonidan boshqariladi"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Bildirishnomalar va ilovalar faol emas"</string>
</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index ebb29d8..1bd7317 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Cơ quan"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Hồ sơ công việc"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Tìm ứng dụng công việc tại đây"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Mỗi ứng dụng công việc đều có một huy hiệu màu cam cho biết ứng dụng đó được tổ chức của bạn bảo mật. Bạn có thể di chuyển các ứng dụng công việc đến Màn hình chính để truy cập dễ dàng hơn."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Mỗi ứng dụng công việc đều có một huy hiệu màu cam và được tổ chức của bạn bảo mật. Bạn có thể di chuyển ứng dụng đến Màn hình chính để truy cập dễ dàng hơn."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Do tổ chức của bạn quản lý"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Thông báo và ứng dụng đang tắt"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 1bc8f9b..3610ef0 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"工作"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"工作资料"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"请在此处查找工作应用"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"每个工作应用均有一个橙色徽标,表示该应用由贵组织负责确保其安全。您可以将工作应用移到主屏幕,以便轻松访问。"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"每个工作应用均有一个橙色徽标,并由贵单位负责确保其安全。请将工作应用移到主屏幕,以便轻松访问。"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"由贵单位管理"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"通知和应用均已关闭"</string>
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index e5c28ff..0895651 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"商務"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"工作設定檔"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"請在此處尋找工作應用程式"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"每個工作應用程式都有橙色徽章,表示該應用程式由您的機構負責確保其安全。您可以將工作應用程式移至主畫面,以便輕鬆存取。"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"每個工作應用程式都有橙色徽章,並由您的機構負責保持安全。您可以將工作應用程式移至主畫面,以便輕鬆存取。"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"由您的機構管理"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"通知和應用程式已關閉"</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index fc4b31c..76fbdb1 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"公司"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Work 設定檔"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"在這裡尋找辦公應用程式"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"每個辦公應用程式都有橘色徽章,表示該應用程式由貴機構負責管理,並確保其安全。你可以將辦公應用程式移至主螢幕以便輕鬆存取。"</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"每個辦公應用程式都有橘色徽章,並由貴機構負責管理及確保其安全。請將辦公應用程式移至主螢幕以便輕鬆存取。"</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"由貴機構所管理"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"已關閉通知和應用程式"</string>
</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 0e3b320..53dbdd6 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -133,5 +133,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Umsebenzi"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Iphrofayela yomsebenzi"</string>
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Thola izinhlelo zokusebenza lapha"</string>
- <string name="bottom_work_tab_user_education_body" msgid="5834430249581360068">"Uhlelo lokusebenza ngalunye lunebheji ewolintshi, esho ukuthi igcinwe iphephile inhlangano yakho. Izinhlelo zokusebenza zomsebenzi zingayiswa esikrinini sakho sasekhaya ngokufinyelela okulula."</string>
+ <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Uhlo lokusebenza ngalunye lomsebenzi linebheji ewolintshi futhi igcinwa iphephile inhlangano yakho. Hambisa izinhlelo zokusebenza esikrinini sakho sasekhaya ngokufinyelela okulula."</string>
+ <string name="work_mode_on_label" msgid="4781128097185272916">"Kuphethwe inhlangano yakho"</string>
+ <string name="work_mode_off_label" msgid="3194894777601421047">"Izaziso nezinhlelo zokusebenza kuvaliwe"</string>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index ad5f0b8..2033d46 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -91,10 +91,6 @@
<attr name="layout_ignoreInsets" format="boolean" />
</declare-styleable>
- <declare-styleable name="ButtonDropTarget">
- <attr name="hideParentOnDisable" format="boolean" />
- </declare-styleable>
-
<declare-styleable name="InvariantDeviceProfile">
<attr name="name" format="string" />
<attr name="minWidthDps" format="float" />
diff --git a/res/values/config.xml b/res/values/config.xml
index 2096200..3dddac2 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -92,6 +92,9 @@
<!-- Name of a user event dispatcher class. -->
<string name="user_event_dispatcher_class" translatable="false"></string>
+ <!-- Name of an app transition manager class. -->
+ <string name="app_transition_manager_class" translatable="false"></string>
+
<!-- Name of a color extraction implementation class. -->
<string name="color_extraction_impl_class" translatable="false"></string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f53fe79..2aff936 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -43,14 +43,13 @@
<dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
<!-- Hotseat/all-apps scrim -->
- <dimen name="all_apps_scrim_radius">10dp</dimen>
- <dimen name="all_apps_scrim_margin">10dp</dimen>
- <dimen name="all_apps_scrim_blur">5dp</dimen>
+ <dimen name="all_apps_scrim_radius">8dp</dimen>
+ <dimen name="all_apps_scrim_margin">8dp</dimen>
+ <dimen name="all_apps_scrim_blur">4dp</dimen>
<!-- Drop target bar -->
<dimen name="dynamic_grid_drop_target_size">48dp</dimen>
- <dimen name="vert_drop_target_vertical_gap">20dp</dimen>
- <dimen name="vert_drop_target_horizontal_gap">14dp</dimen>
+ <dimen name="drop_target_vertical_gap">20dp</dimen>
<!-- App Widget resize frame -->
<dimen name="widget_handle_margin">13dp</dimen>
@@ -204,7 +203,7 @@
<dimen name="system_shortcut_header_icon_padding">12dp</dimen>
<!-- Notifications -->
- <dimen name="bg_round_rect_radius">12dp</dimen>
+ <dimen name="bg_round_rect_radius">8dp</dimen>
<dimen name="notification_padding_start">16dp</dimen>
<dimen name="notification_padding_end">12dp</dimen>
<!-- notification_padding_end + (icon_size - footer_icon_size) / 2 -->
@@ -228,6 +227,6 @@
<dimen name="popup_item_divider_height">0.5dp</dimen>
<dimen name="swipe_helper_falsing_threshold">70dp</dimen>
-<!-- Recents -->
- <dimen name="recents_page_spacing">10dp</dimen>
+<!-- Overview -->
+ <dimen name="options_menu_icon_size">48dp</dimen>
</resources>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 824040a..12f022f 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -42,9 +42,11 @@
TYPE_WIDGETS_BOTTOM_SHEET,
TYPE_WIDGET_RESIZE_FRAME,
TYPE_WIDGETS_FULL_SHEET,
- TYPE_QUICKSTEP_PREVIEW,
TYPE_ON_BOARD_POPUP,
- TYPE_TASK_MENU
+
+ TYPE_QUICKSTEP_PREVIEW,
+ TYPE_TASK_MENU,
+ TYPE_OPTIONS_POPUP
})
@Retention(RetentionPolicy.SOURCE)
public @interface FloatingViewType {}
@@ -53,17 +55,20 @@
public static final int TYPE_WIDGETS_BOTTOM_SHEET = 1 << 2;
public static final int TYPE_WIDGET_RESIZE_FRAME = 1 << 3;
public static final int TYPE_WIDGETS_FULL_SHEET = 1 << 4;
- public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 5;
- public static final int TYPE_ON_BOARD_POPUP = 1 << 6;
+ public static final int TYPE_ON_BOARD_POPUP = 1 << 5;
+
+ // Popups related to quickstep UI
+ public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 6;
public static final int TYPE_TASK_MENU = 1 << 7;
+ public static final int TYPE_OPTIONS_POPUP = 1 << 8;
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
- | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_TASK_MENU;
+ | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_TASK_MENU | TYPE_OPTIONS_POPUP;
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
- | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP;
+ | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_OPTIONS_POPUP;
protected boolean mIsOpen;
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index cfb55cc..a9cf8cc 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -16,27 +16,28 @@
package com.android.launcher3;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
import static com.android.launcher3.LauncherState.NORMAL;
import android.animation.AnimatorSet;
import android.animation.FloatArrayEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
-import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
+import android.widget.PopupWindow;
import android.widget.TextView;
import com.android.launcher3.anim.Interpolators;
@@ -56,7 +57,10 @@
private static final int[] sTempCords = new int[2];
private static final int DRAG_VIEW_DROP_DURATION = 285;
- private final boolean mHideParentOnDisable;
+ public static final int TOOLTIP_DEFAULT = 0;
+ public static final int TOOLTIP_LEFT = 1;
+ public static final int TOOLTIP_RIGHT = 2;
+
protected final Launcher mLauncher;
private int mBottomDragPadding;
@@ -75,6 +79,10 @@
protected CharSequence mText;
protected ColorStateList mOriginalTextColor;
protected Drawable mDrawable;
+ private boolean mTextVisible = true;
+
+ private PopupWindow mToolTip;
+ private int mToolTipLocation;
private AnimatorSet mCurrentColorAnim;
@Thunk ColorMatrix mSrcFilter, mDstFilter, mCurrentFilter;
@@ -89,11 +97,6 @@
Resources resources = getResources();
mBottomDragPadding = resources.getDimensionPixelSize(R.dimen.drop_target_drag_padding);
-
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.ButtonDropTarget, defStyle, 0);
- mHideParentOnDisable = a.getBoolean(R.styleable.ButtonDropTarget_hideParentOnDisable, false);
- a.recycle();
mDragDistanceThreshold = resources.getDimensionPixelSize(R.dimen.drag_distanceThreshold);
}
@@ -102,21 +105,56 @@
super.onFinishInflate();
mText = getText();
mOriginalTextColor = getTextColors();
+ setContentDescription(mText);
}
protected void setDrawable(int resId) {
// We do not set the drawable in the xml as that inflates two drawables corresponding to
// drawableLeft and drawableStart.
- setCompoundDrawablesRelativeWithIntrinsicBounds(resId, 0, 0, 0);
- mDrawable = getCompoundDrawablesRelative()[0];
+ if (mTextVisible) {
+ setCompoundDrawablesRelativeWithIntrinsicBounds(resId, 0, 0, 0);
+ mDrawable = getCompoundDrawablesRelative()[0];
+ } else {
+ setCompoundDrawablesRelativeWithIntrinsicBounds(0, resId, 0, 0);
+ mDrawable = getCompoundDrawablesRelative()[1];
+ }
}
public void setDropTargetBar(DropTargetBar dropTargetBar) {
mDropTargetBar = dropTargetBar;
}
+ private void hideTooltip() {
+ if (mToolTip != null) {
+ mToolTip.dismiss();
+ mToolTip = null;
+ }
+ }
+
@Override
public final void onDragEnter(DragObject d) {
+ if (!d.accessibleDrag && !mTextVisible) {
+ // Show tooltip
+ hideTooltip();
+
+ TextView message = (TextView) LayoutInflater.from(getContext()).inflate(
+ R.layout.drop_target_tool_tip, null);
+ message.setText(mText);
+
+ mToolTip = new PopupWindow(message, WRAP_CONTENT, WRAP_CONTENT);
+ int x = 0, y = 0;
+ if (mToolTipLocation != TOOLTIP_DEFAULT) {
+ y = -getMeasuredHeight();
+ message.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ if (mToolTipLocation == TOOLTIP_LEFT) {
+ x = - getMeasuredWidth() - message.getMeasuredWidth() / 2;
+ } else {
+ x = getMeasuredWidth() / 2 + message.getMeasuredWidth() / 2;
+ }
+ }
+ mToolTip.showAsDropDown(this, x, y);
+ }
+
d.dragView.setColor(mHoverColor);
animateTextColor(mHoverColor);
if (d.stateAnnouncer != null) {
@@ -153,13 +191,9 @@
ValueAnimator anim1 = ValueAnimator.ofObject(
new FloatArrayEvaluator(mCurrentFilter.getArray()),
mSrcFilter.getArray(), mDstFilter.getArray());
- anim1.addUpdateListener(new AnimatorUpdateListener() {
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mDrawable.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
- invalidate();
- }
+ anim1.addUpdateListener((anim) -> {
+ mDrawable.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
+ invalidate();
});
mCurrentColorAnim.play(anim1);
@@ -169,6 +203,8 @@
@Override
public final void onDragExit(DragObject d) {
+ hideTooltip();
+
if (!d.dragComplete) {
d.dragView.setColor(0);
resetHoverColor();
@@ -187,8 +223,7 @@
mCurrentColorAnim = null;
}
setTextColor(mOriginalTextColor);
- (mHideParentOnDisable ? ((ViewGroup) getParent()) : this)
- .setVisibility(mActive ? View.VISIBLE : View.GONE);
+ setVisibility(mActive ? View.VISIBLE : View.GONE);
mAccessibleDrag = options.isAccessibleDrag;
setOnClickListener(mAccessibleDrag ? this : null);
@@ -230,14 +265,12 @@
final float scale = (float) to.width() / from.width();
mDropTargetBar.deferOnDragEnd();
- Runnable onAnimationEndRunnable = new Runnable() {
- @Override
- public void run() {
- completeDrop(d);
- mDropTargetBar.onDragEnd();
- mLauncher.getStateManager().goToState(NORMAL);
- }
+ Runnable onAnimationEndRunnable = () -> {
+ completeDrop(d);
+ mDropTargetBar.onDragEnd();
+ mLauncher.getStateManager().goToState(NORMAL);
};
+
dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
DRAG_VIEW_DROP_DURATION,
Interpolators.DEACCEL_2, Interpolators.LINEAR, onAnimationEndRunnable,
@@ -294,8 +327,8 @@
to.set(left, top, right, bottom);
// Center the destination rect about the trash icon
- final int xOffset = (int) -(viewWidth - width) / 2;
- final int yOffset = (int) -(viewHeight - height) / 2;
+ final int xOffset = -(viewWidth - width) / 2;
+ final int yOffset = -(viewHeight - height) / 2;
to.offset(xOffset, yOffset);
return to;
@@ -310,25 +343,24 @@
return getTextColors().getDefaultColor();
}
- /**
- * Returns True if any update was made.
- */
- public boolean updateText(boolean hide) {
- if ((hide && getText().toString().isEmpty()) || (!hide && mText.equals(getText()))) {
- return false;
+ public void setTextVisible(boolean isVisible) {
+ if (mTextVisible != isVisible) {
+ mTextVisible = isVisible;
+ setText(isVisible ? mText : "");
+ if (mTextVisible) {
+ setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null);
+ } else {
+ setCompoundDrawablesRelativeWithIntrinsicBounds(null, mDrawable, null, null);
+ }
}
-
- setText(hide ? "" : mText);
- return true;
}
- public boolean isTextTruncated() {
- int availableWidth = getMeasuredWidth();
- if (mHideParentOnDisable) {
- ViewGroup parent = (ViewGroup) getParent();
- availableWidth = parent.getMeasuredWidth() - parent.getPaddingLeft()
- - parent.getPaddingRight();
- }
+ public void setToolTipLocation(int location) {
+ mToolTipLocation = location;
+ hideTooltip();
+ }
+
+ public boolean isTextTruncated(int availableWidth) {
availableWidth -= (getPaddingLeft() + getPaddingRight() + mDrawable.getIntrinsicWidth()
+ getCompoundDrawablePadding());
CharSequence displayedText = TextUtils.ellipsize(mText, getPaint(), availableWidth,
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 164efe5..5789755 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -412,7 +412,7 @@
padding.bottom = edgeMarginPx;
padding.left = hotseatBarSidePaddingPx;
padding.right = hotseatBarSidePaddingPx;
- if (mInsets.left > mInsets.right) {
+ if (isSeascape()) {
padding.left += hotseatBarSizePx;
padding.right += pageIndicatorSizePx;
} else {
@@ -480,6 +480,11 @@
return isLandscape && transposeLayoutWithOrientation;
}
+ public boolean isSeascape() {
+ // TODO: This might not hold true for multi window mode, use configuration insead.
+ return isVerticalBarLayout() && mInsets.left > mInsets.right;
+ }
+
public boolean shouldFadeAdjacentWorkspaceScreens() {
return isVerticalBarLayout() || isLargeTablet;
}
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index 494aae4..cc6a58f 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -17,6 +17,9 @@
package com.android.launcher3;
import static com.android.launcher3.AlphaUpdateListener.updateVisibility;
+import static com.android.launcher3.ButtonDropTarget.TOOLTIP_DEFAULT;
+import static com.android.launcher3.ButtonDropTarget.TOOLTIP_LEFT;
+import static com.android.launcher3.ButtonDropTarget.TOOLTIP_RIGHT;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.TimeInterpolator;
@@ -26,22 +29,18 @@
import android.view.Gravity;
import android.view.View;
import android.view.ViewDebug;
-import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
-import android.widget.LinearLayout;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragController.DragListener;
import com.android.launcher3.dragndrop.DragOptions;
-import java.util.ArrayList;
-
/*
* The top bar containing various drop targets: Delete/App Info/Uninstall.
*/
-public class DropTargetBar extends LinearLayout
+public class DropTargetBar extends FrameLayout
implements DragListener, Insettable {
protected static final int DEFAULT_DRAG_FADE_DURATION = 175;
@@ -59,6 +58,8 @@
private ButtonDropTarget[] mDropTargets;
private ViewPropertyAnimator mCurrentAnimation;
+ private boolean mIsVertical = true;
+
public DropTargetBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -70,25 +71,30 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
-
- // Initialize with hidden state
- setAlpha(0f);
+ mDropTargets = new ButtonDropTarget[getChildCount()];
+ for (int i = 0; i < mDropTargets.length; i++) {
+ mDropTargets[i] = (ButtonDropTarget) getChildAt(i);
+ mDropTargets[i].setDropTargetBar(this);
+ }
}
@Override
public void setInsets(Rect insets) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
+ mIsVertical = grid.isVerticalBarLayout();
lp.leftMargin = insets.left;
lp.topMargin = insets.top;
lp.bottomMargin = insets.bottom;
lp.rightMargin = insets.right;
+ int tooltipLocation = TOOLTIP_DEFAULT;
if (grid.isVerticalBarLayout()) {
lp.width = grid.dropTargetBarSizePx;
lp.height = grid.availableHeightPx - 2 * grid.edgeMarginPx;
- lp.gravity = insets.left > insets.right ? Gravity.RIGHT : Gravity.LEFT;
+ lp.gravity = grid.isSeascape() ? Gravity.RIGHT : Gravity.LEFT;
+ tooltipLocation = grid.isSeascape() ? TOOLTIP_LEFT : TOOLTIP_RIGHT;
} else {
int gap;
if (grid.isTablet) {
@@ -107,83 +113,95 @@
lp.height = grid.dropTargetBarSizePx;
}
setLayoutParams(lp);
+ for (ButtonDropTarget button : mDropTargets) {
+ button.setToolTipLocation(tooltipLocation);
+ }
}
public void setup(DragController dragController) {
dragController.addDragListener(this);
- ArrayList<ButtonDropTarget> outList = new ArrayList<>();
- findDropTargets(this, outList);
-
- mDropTargets = new ButtonDropTarget[outList.size()];
for (int i = 0; i < mDropTargets.length; i++) {
- mDropTargets[i] = outList.get(i);
- mDropTargets[i].setDropTargetBar(this);
dragController.addDragListener(mDropTargets[i]);
dragController.addDropTarget(mDropTargets[i]);
}
}
- private static void findDropTargets(View view, ArrayList<ButtonDropTarget> outTargets) {
- if (view instanceof ButtonDropTarget) {
- outTargets.add((ButtonDropTarget) view);
- } else if (view instanceof ViewGroup) {
- ViewGroup vg = (ViewGroup) view;
- for (int i = vg.getChildCount() - 1; i >= 0; i--) {
- findDropTargets(vg.getChildAt(i), outTargets);
- }
- }
- }
-
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
- boolean hideText = hideTextHelper(false /* shouldUpdateText */, false /* no-op */);
- if (hideTextHelper(true /* shouldUpdateText */, hideText)) {
- // Text has changed, so we need to re-measure.
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- }
+ if (mIsVertical) {
+ int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
- /**
- * Helper method that iterates through the children and returns whether any of the visible
- * {@link ButtonDropTarget} has truncated text.
- *
- * @param shouldUpdateText If True, updates the text of all children.
- * @param hideText If True and {@param shouldUpdateText} is True, clears the text of all
- * children; otherwise it sets the original text value.
- *
- *
- * @return If shouldUpdateText is True, returns whether any of the children updated their text.
- * Else, returns whether any of the children have truncated their text.
- */
- private boolean hideTextHelper(boolean shouldUpdateText, boolean hideText) {
- boolean result = false;
- View visibleView;
- ButtonDropTarget dropTarget;
- for (int i = getChildCount() - 1; i >= 0; --i) {
- if (getChildAt(i) instanceof ButtonDropTarget) {
- visibleView = dropTarget = (ButtonDropTarget) getChildAt(i);
- } else if (getChildAt(i) instanceof ViewGroup) {
- // The Drop Target is wrapped in a FrameLayout.
- visibleView = getChildAt(i);
- dropTarget = (ButtonDropTarget) ((ViewGroup) visibleView).getChildAt(0);
- } else {
- // Ignore other views.
- continue;
+ for (ButtonDropTarget button : mDropTargets) {
+ if (button.getVisibility() != GONE) {
+ button.setTextVisible(false);
+ button.measure(widthSpec, heightSpec);
+ }
+ }
+ } else {
+ int visibleCount = getVisibleButtonsCount();
+ int availableWidth = width / visibleCount;
+ boolean textVisible = true;
+ for (ButtonDropTarget buttons : mDropTargets) {
+ if (buttons.getVisibility() != GONE) {
+ textVisible = textVisible && !buttons.isTextTruncated(availableWidth);
+ }
}
- if (visibleView.getVisibility() == View.VISIBLE) {
- if (shouldUpdateText) {
- result |= dropTarget.updateText(hideText);
- } else if (dropTarget.isTextTruncated()) {
- result = true;
- break;
+ int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
+ int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ for (ButtonDropTarget button : mDropTargets) {
+ if (button.getVisibility() != GONE) {
+ button.setTextVisible(textVisible);
+ button.measure(widthSpec, heightSpec);
}
}
}
+ setMeasuredDimension(width, height);
+ }
- return result;
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mIsVertical) {
+ int gap = getResources().getDimensionPixelSize(R.dimen.drop_target_vertical_gap);
+ int start = gap;
+ int end;
+
+ for (ButtonDropTarget button : mDropTargets) {
+ if (button.getVisibility() != GONE) {
+ end = start + button.getMeasuredHeight();
+ button.layout(0, start, button.getMeasuredWidth(), end);
+ start = end + gap;
+ }
+ }
+ } else {
+ int visibleCount = getVisibleButtonsCount();
+ int frameSize = (right - left) / visibleCount;
+
+ int start = frameSize / 2;
+ int halfWidth;
+ for (ButtonDropTarget button : mDropTargets) {
+ if (button.getVisibility() != GONE) {
+ halfWidth = button.getMeasuredWidth() / 2;
+ button.layout(start - halfWidth, 0,
+ start + halfWidth, button.getMeasuredHeight());
+ start = start + frameSize;
+ }
+ }
+ }
+ }
+
+ private int getVisibleButtonsCount() {
+ int visibleCount = 0;
+ for (ButtonDropTarget buttons : mDropTargets) {
+ if (buttons.getVisibility() != GONE) {
+ visibleCount++;
+ }
+ }
+ return visibleCount;
}
private void animateToVisibility(boolean isVisible) {
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 25eacb5..9d2bb07 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -164,7 +164,7 @@
mContent.setGridSize(1, grid.inv.numHotseatIcons);
lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
- if (insets.left > insets.right) {
+ if (grid.isSeascape()) {
lp.gravity = Gravity.LEFT;
lp.width = grid.hotseatBarSizePx + insets.left + grid.hotseatBarSidePaddingPx;
getLayout().setPadding(
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index a5ca3ee..957a5e5 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -118,8 +118,7 @@
mIconDpi = inv.fillResIconDpi;
mIconDb = new IconDB(context, inv.iconBitmapSize);
- mIconProvider = Utilities.getOverrideObject(
- IconProvider.class, context, R.string.icon_provider_class);
+ mIconProvider = IconProvider.newInstance(context);
mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
mLowResOptions = new BitmapFactory.Options();
@@ -254,7 +253,7 @@
// Remove all active icon update tasks.
mWorkerHandler.removeCallbacksAndMessages(ICON_UPDATE_TOKEN);
- mIconProvider.updateSystemStateString();
+ mIconProvider.updateSystemStateString(mContext);
for (UserHandle user : mUserManager.getUserProfiles()) {
// Query for the set of apps
final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java
index 4dee2b5..b469a8f 100644
--- a/src/com/android/launcher3/IconProvider.java
+++ b/src/com/android/launcher3/IconProvider.java
@@ -1,5 +1,6 @@
package com.android.launcher3;
+import android.content.Context;
import android.content.pm.LauncherActivityInfo;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -8,17 +9,26 @@
public class IconProvider {
- private static final boolean DBG = false;
- private static final String TAG = "IconProvider";
-
protected String mSystemState;
- public IconProvider() {
- updateSystemStateString();
+ public static IconProvider newInstance(Context context) {
+ IconProvider provider = Utilities.getOverrideObject(
+ IconProvider.class, context, R.string.icon_provider_class);
+ provider.updateSystemStateString(context);
+ return provider;
}
- public void updateSystemStateString() {
- mSystemState = Locale.getDefault().toString() + "," + Build.VERSION.SDK_INT;
+ public IconProvider() { }
+
+ public void updateSystemStateString(Context context) {
+ final String locale;
+ if (Utilities.ATLEAST_NOUGAT) {
+ locale = context.getResources().getConfiguration().getLocales().toLanguageTags();
+ } else {
+ locale = Locale.getDefault().toString();
+ }
+
+ mSystemState = locale + "," + Build.VERSION.SDK_INT;
}
public String getIconSystemState(String packageName) {
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index 289242f..e52fd76 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -70,7 +70,7 @@
Rect sourceBounds, Bundle opts) {
if (info instanceof PromiseAppInfo) {
PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info;
- context.startActivity(promiseAppInfo.getMarketIntent());
+ context.startActivity(promiseAppInfo.getMarketIntent(context));
return null;
}
ComponentName componentName = null;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index e3682b4..85443ed 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -56,6 +56,7 @@
import android.content.pm.PackageManager;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
@@ -213,6 +214,8 @@
private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
@Thunk static final int NEW_APPS_ANIMATION_DELAY = 500;
+ private LauncherAppTransitionManager mAppTransitionManager;
+
@Thunk Workspace mWorkspace;
private View mLauncherView;
@Thunk DragLayer mDragLayer;
@@ -268,7 +271,7 @@
*/
private PendingRequestArgs mPendingRequestArgs;
- private float mLastDispatchTouchEventX = 0.0f;
+ private final PointF mLastDispatchTouchEvent = new PointF();
public ViewGroupFocusHelper mFocusHandler;
private boolean mRotationEnabled = false;
@@ -402,6 +405,11 @@
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
+ mAppTransitionManager = Utilities.getOverrideObject(LauncherAppTransitionManager.class,
+ this, R.string.app_transition_manager_class);
+
+ mAppTransitionManager.registerRemoteAnimations();
+
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onCreate(savedInstanceState);
}
@@ -769,12 +777,12 @@
mAppWidgetHost.setListenIfResumed(true);
NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
- if (mShouldFadeInScrim && mDragLayer.getBackground() != null) {
+ if (mShouldFadeInScrim && mLauncherView.getBackground() != null) {
if (mScrimAnimator != null) {
mScrimAnimator.cancel();
}
- mDragLayer.getBackground().setAlpha(0);
- mScrimAnimator = ObjectAnimator.ofInt(mDragLayer.getBackground(),
+ mLauncherView.getBackground().setAlpha(0);
+ mScrimAnimator = ObjectAnimator.ofInt(mLauncherView.getBackground(),
LauncherAnimUtils.DRAWABLE_ALPHA, 0, 255);
mScrimAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -1164,6 +1172,10 @@
return mAllAppsController;
}
+ public LauncherRootView getRootView() {
+ return (LauncherRootView) mLauncherView;
+ }
+
public DragLayer getDragLayer() {
return mDragLayer;
}
@@ -1738,7 +1750,7 @@
private void startMarketIntentForPackage(View v, String packageName) {
ItemInfo item = (ItemInfo) v.getTag();
- Intent intent = PackageManagerHelper.getMarketIntent(packageName);
+ Intent intent = new PackageManagerHelper(v.getContext()).getMarketIntent(packageName);
startActivitySafely(v, intent, item);
}
@@ -1803,7 +1815,7 @@
Intent intent;
if (item instanceof PromiseAppInfo) {
PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
- intent = promiseAppInfo.getMarketIntent();
+ intent = promiseAppInfo.getMarketIntent(this);
} else {
intent = item.getIntent();
}
@@ -1857,7 +1869,9 @@
if (v != null) {
intent.setSourceBounds(getViewBounds(v));
// If there is no target package, use the default intent chooser animation
- launchOptions = hasTargetPackage ? getActivityLaunchOptions(v) : null;
+ launchOptions = hasTargetPackage
+ ? getActivityLaunchOptions(v, isInMultiWindowModeCompat())
+ : null;
} else {
launchOptions = null;
}
@@ -1912,30 +1926,10 @@
}
@TargetApi(Build.VERSION_CODES.M)
- public Bundle getActivityLaunchOptions(View v) {
- if (Utilities.ATLEAST_MARSHMALLOW) {
- int left = 0, top = 0;
- int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
- if (v instanceof BubbleTextView) {
- // Launch from center of icon, not entire view
- Drawable icon = ((BubbleTextView) v).getIcon();
- if (icon != null) {
- Rect bounds = icon.getBounds();
- left = (width - bounds.width()) / 2;
- top = v.getPaddingTop();
- width = bounds.width();
- height = bounds.height();
- }
- }
- return ActivityOptions.makeClipRevealAnimation(v, left, top, width, height).toBundle();
- } else if (Utilities.ATLEAST_LOLLIPOP_MR1) {
- // On L devices, we use the device default slide-up transition.
- // On L MR1 devices, we use a custom version of the slide-up transition which
- // doesn't have the delay present in the device default.
- return ActivityOptions.makeCustomAnimation(
- this, R.anim.task_open_enter, R.anim.no_anim).toBundle();
- }
- return null;
+ public Bundle getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
+ return useDefaultLaunchOptions
+ ? mAppTransitionManager.getDefaultActivityLaunchOptions(this, v)
+ : mAppTransitionManager.getActivityLaunchOptions(this, v);
}
public Rect getViewBounds(View v) {
@@ -1950,11 +1944,20 @@
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return mAppLaunchSuccess;
}
+
+ boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
+ && (item instanceof ShortcutInfo)
+ && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
+ || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
+ && !((ShortcutInfo) item).isPromise();
+
// Only launch using the new animation if the shortcut has not opted out (this is a
// private contract between launcher and may be ignored in the future).
boolean useLaunchAnimation = (v != null) &&
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
- Bundle optsBundle = useLaunchAnimation ? getActivityLaunchOptions(v) : null;
+ Bundle optsBundle = useLaunchAnimation
+ ? getActivityLaunchOptions(v, isShortcut || isInMultiWindowModeCompat())
+ : null;
UserHandle user = item == null ? null : item.user;
@@ -1964,11 +1967,7 @@
intent.setSourceBounds(getViewBounds(v));
}
try {
- if (Utilities.ATLEAST_MARSHMALLOW
- && (item instanceof ShortcutInfo)
- && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
- || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
- && !((ShortcutInfo) item).isPromise()) {
+ if (isShortcut) {
// Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(Process.myUserHandle())) {
@@ -1999,7 +1998,7 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
- mLastDispatchTouchEventX = ev.getX();
+ mLastDispatchTouchEvent.set(ev.getX(), ev.getY());
return super.dispatchTouchEvent(ev);
}
@@ -2010,7 +2009,7 @@
if (!isInState(NORMAL) && !isInState(OVERVIEW)) return false;
boolean ignoreLongPressToOverview =
- mDeviceProfile.shouldIgnoreLongPressToOverview(mLastDispatchTouchEventX);
+ mDeviceProfile.shouldIgnoreLongPressToOverview(mLastDispatchTouchEvent.x);
if (v instanceof Workspace) {
if (!isInState(OVERVIEW)) {
@@ -2018,7 +2017,7 @@
getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
Action.Direction.NONE, ContainerType.WORKSPACE,
mWorkspace.getCurrentPage());
- UiFactory.onWorkspaceLongPress(this);
+ UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent);
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
return true;
@@ -2055,7 +2054,7 @@
getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
Action.Direction.NONE, ContainerType.WORKSPACE,
mWorkspace.getCurrentPage());
- UiFactory.onWorkspaceLongPress(this);
+ UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent);
}
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
new file mode 100644
index 0000000..9d68dc9
--- /dev/null
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+
+import android.app.ActivityOptions;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+
+/**
+ * Manages the opening and closing app transitions from Launcher.
+ */
+public class LauncherAppTransitionManager {
+
+ public Bundle getDefaultActivityLaunchOptions(Launcher launcher, View v) {
+ if (Utilities.ATLEAST_MARSHMALLOW) {
+ int left = 0, top = 0;
+ int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
+ if (v instanceof BubbleTextView) {
+ // Launch from center of icon, not entire view
+ Drawable icon = ((BubbleTextView) v).getIcon();
+ if (icon != null) {
+ Rect bounds = icon.getBounds();
+ left = (width - bounds.width()) / 2;
+ top = v.getPaddingTop();
+ width = bounds.width();
+ height = bounds.height();
+ }
+ }
+ return ActivityOptions.makeClipRevealAnimation(v, left, top, width, height)
+ .toBundle();
+ } else if (Utilities.ATLEAST_LOLLIPOP_MR1) {
+ // On L devices, we use the device default slide-up transition.
+ // On L MR1 devices, we use a custom version of the slide-up transition which
+ // doesn't have the delay present in the device default.
+ return ActivityOptions.makeCustomAnimation(launcher, R.anim.task_open_enter,
+ R.anim.no_anim).toBundle();
+ }
+ return null;
+ }
+
+ public Bundle getActivityLaunchOptions(Launcher launcher, View v) {
+ return getDefaultActivityLaunchOptions(launcher, v);
+ }
+
+ public void registerRemoteAnimations() {
+ }
+}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 1b169f5..929606e 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -40,21 +39,18 @@
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.model.AddWorkspaceItemsTask;
+import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.CacheDataUpdatedTask;
-import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.LoaderResults;
import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.PackageInstallStateChangedTask;
-import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.model.PackageUpdatedTask;
import com.android.launcher3.model.ShortcutsChangedTask;
import com.android.launcher3.model.UserLockStateChangedTask;
-import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 1a1bec6..18d5234 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -11,6 +11,8 @@
import android.view.View;
import android.view.ViewDebug;
+import com.android.launcher3.util.Themes;
+
import static com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV;
import static com.android.launcher3.util.SystemUiController.UI_STATE_ROOT_VIEW;
@@ -66,6 +68,7 @@
// Update device profile before notifying th children.
mLauncher.getDeviceProfile().updateInsets(insets);
+ boolean resetState = !insets.equals(mInsets);
setInsets(insets);
if (mAlignedView != null) {
@@ -77,10 +80,20 @@
mAlignedView.setLayoutParams(lp);
}
}
+ if (resetState) {
+ mLauncher.getStateManager().reapplyState();
+ }
return true; // I'll take it from here
}
+ @Override
+ public void setInsets(Rect insets) {
+ super.setInsets(insets);
+ setBackground(insets.top == 0 ? null
+ : Themes.getAttrDrawable(getContext(), R.attr.workspaceStatusBarScrim));
+ }
+
public void dispatchInsets() {
fitSystemWindows(mInsets);
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index bcb6252..8eeeec3 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -146,6 +146,14 @@
goToState(state, true, delay, null);
}
+ public void reapplyState() {
+ if (mConfig.mCurrentAnimation == null) {
+ for (StateHandler handler : getStateHandlers()) {
+ handler.setState(mState);
+ }
+ }
+ }
+
private void goToState(LauncherState state, boolean animated, long delay,
Runnable onCompleteRunnable) {
if (mLauncher.isInState(state) && mConfig.mCurrentAnimation == null) {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 4c30853..ad94a6b 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -563,13 +563,21 @@
computeScrollHelper();
}
+ public int getExpectedHeight() {
+ return getMeasuredHeight();
+ }
+
public int getNormalChildHeight() {
- return getMeasuredHeight() - getPaddingTop() - getPaddingBottom()
+ return getExpectedHeight() - getPaddingTop() - getPaddingBottom()
- mInsets.top - mInsets.bottom;
}
+ public int getExpectedWidth() {
+ return getMeasuredWidth();
+ }
+
public int getNormalChildWidth() {
- return getMeasuredWidth() - getPaddingLeft() - getPaddingRight()
+ return getExpectedWidth() - getPaddingLeft() - getPaddingRight()
- mInsets.left - mInsets.right;
}
diff --git a/src/com/android/launcher3/PromiseAppInfo.java b/src/com/android/launcher3/PromiseAppInfo.java
index 07515d0..ea9f752 100644
--- a/src/com/android/launcher3/PromiseAppInfo.java
+++ b/src/com/android/launcher3/PromiseAppInfo.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
@@ -46,7 +47,7 @@
return shortcut;
}
- public Intent getMarketIntent() {
- return PackageManagerHelper.getMarketIntent(componentName.getPackageName());
+ public Intent getMarketIntent(Context context) {
+ return new PackageManagerHelper(context).getMarketIntent(componentName.getPackageName());
}
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index de3b09a..e6aa6be 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -179,27 +179,6 @@
private SpringLoadedDragController mSpringLoadedDragController;
- // Direction used for moving the workspace and hotseat UI
- public enum Direction {
- X (TRANSLATION_X),
- Y (TRANSLATION_Y);
-
- private final Property<View, Float> viewProperty;
-
- Direction(Property<View, Float> viewProperty) {
- this.viewProperty = viewProperty;
- }
- }
-
- private static final int HOTSEAT_STATE_ALPHA_INDEX = 2;
-
- /**
- * Hotseat alpha can be changed when moving horizontally, vertically, changing states.
- * The values correspond to {@link Direction#X}, {@link Direction#Y} &
- * {@link #HOTSEAT_STATE_ALPHA_INDEX} respectively.
- */
- private final float[] mHotseatAlpha = new float[] {1, 1, 1};
-
private boolean mIsSwitchingState = false;
boolean mChildrenLayersEnabled = true;
@@ -1206,81 +1185,8 @@
// TODO(adamcohen): figure out a final effect here. We may need to recommend
// different effects based on device performance. On at least one relatively high-end
// device I've tried, translating the launcher causes things to get quite laggy.
- setWorkspaceTranslationAndAlpha(transX, alpha);
- setHotseatTranslationAndAlpha(Direction.X, transX, alpha);
- }
-
- /**
- * Moves the workspace UI in the provided direction.
- * @param translation the amount of horizontal shift.
- * @param alpha the alpha for the workspace page
- */
- private void setWorkspaceTranslationAndAlpha(float translation, float alpha) {
- float finalAlpha = alpha;
-
- View currentChild = getChildAt(getCurrentPage());
- if (currentChild != null) {
- currentChild.setTranslationX(translation);
- currentChild.setAlpha(finalAlpha);
- }
-
- // When the animation finishes, reset all pages, just in case we missed a page.
- if (Float.compare(translation, 0) == 0) {
- for (int i = getChildCount() - 1; i >= 0; i--) {
- View child = getChildAt(i);
- child.setTranslationX(0);
- child.setAlpha(finalAlpha);
- }
- }
- }
-
- /**
- * Moves the Hotseat UI in the provided direction.
- * @param direction the direction to move the workspace
- * @param translation the amount of shift.
- * @param alpha the alpha for the hotseat page
- */
- public void setHotseatTranslationAndAlpha(Direction direction, float translation, float alpha) {
- Property<View, Float> property = direction.viewProperty;
- // Skip the page indicator movement in the vertical bar layout
- if (direction != Direction.Y || !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- property.set(mPageIndicator, translation);
- }
- property.set(mLauncher.getHotseat(), translation);
- setHotseatAlphaAtIndex(alpha, direction.ordinal());
- }
-
- private void setHotseatAlphaAtIndex(float alpha, int index) {
- mHotseatAlpha[index] = alpha;
- final float hotseatAlpha = mHotseatAlpha[0] * mHotseatAlpha[1] * mHotseatAlpha[2];
- final float pageIndicatorAlpha = mHotseatAlpha[0] * mHotseatAlpha[2];
-
- mLauncher.getHotseat().setAlpha(hotseatAlpha);
- mPageIndicator.setAlpha(pageIndicatorAlpha);
- }
-
- public ValueAnimator createHotseatAlphaAnimator(float finalValue) {
- if (Float.compare(finalValue, mHotseatAlpha[HOTSEAT_STATE_ALPHA_INDEX]) == 0) {
- // Return a dummy animator to avoid null checks.
- return ValueAnimator.ofFloat(0, 0);
- } else {
- ValueAnimator animator = ValueAnimator
- .ofFloat(mHotseatAlpha[HOTSEAT_STATE_ALPHA_INDEX], finalValue);
- animator.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- float value = (Float) valueAnimator.getAnimatedValue();
- setHotseatAlphaAtIndex(value, HOTSEAT_STATE_ALPHA_INDEX);
- }
- });
-
- final boolean accessibilityEnabled = isAccessibilityEnabled(mLauncher);
- animator.addUpdateListener(
- new AlphaUpdateListener(mLauncher.getHotseat(), accessibilityEnabled));
- animator.addUpdateListener(
- new AlphaUpdateListener(mPageIndicator, accessibilityEnabled));
- return animator;
- }
+ mLauncher.getDragLayer().setTranslationX(transX);
+ mLauncher.getDragLayer().setAlpha(alpha);
}
@Override
@@ -3447,6 +3353,18 @@
}
@Override
+ public int getExpectedHeight() {
+ return getMeasuredHeight() <= 0
+ ? mLauncher.getDeviceProfile().heightPx : getMeasuredHeight();
+ }
+
+ @Override
+ public int getExpectedWidth() {
+ return getMeasuredWidth() <= 0
+ ? mLauncher.getDeviceProfile().widthPx : getMeasuredWidth();
+ }
+
+ @Override
protected String getPageIndicatorDescription() {
return getResources().getString(R.string.all_apps_button_label);
}
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index cf35e52..21f5d67 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -138,9 +138,8 @@
propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
scaleAndTranslation[2], Interpolators.ZOOM_IN);
- float hotseatAlpha = state.getHoseatAlpha(mLauncher);
- propertySetter.setViewAlpha(mWorkspace.createHotseatAlphaAnimator(hotseatAlpha),
- mLauncher.getHotseat(), hotseatAlpha);
+ propertySetter.setViewAlpha(mLauncher.getHotseat(), state.getHoseatAlpha(mLauncher),
+ pageAlphaProvider.interpolator);
// Set scrim
propertySetter.setInt(mLauncher.getDragLayer().getScrim(), DRAWABLE_ALPHA,
@@ -165,11 +164,7 @@
public static class PropertySetter {
- public void setViewAlpha(Animator anim, View view, float alpha) {
- if (anim != null) {
- anim.end();
- return;
- }
+ public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
view.setAlpha(alpha);
AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view.getContext()));
}
@@ -196,17 +191,14 @@
}
@Override
- public void setViewAlpha(Animator anim, View view, float alpha) {
- if (anim == null) {
- if (view.getAlpha() == alpha) {
- return;
- }
- anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
- anim.addListener(new AlphaUpdateListener(view,
- isAccessibilityEnabled(view.getContext())));
+ public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
+ if (view.getAlpha() == alpha) {
+ return;
}
-
- anim.setDuration(mDuration).setInterpolator(getFadeInterpolator(alpha));
+ ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
+ anim.addListener(new AlphaUpdateListener(
+ view, isAccessibilityEnabled(view.getContext())));
+ anim.setDuration(mDuration).setInterpolator(interpolator);
mStateAnimator.play(anim);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 60b3f83..338bdf3 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -27,7 +27,6 @@
import android.support.v7.widget.RecyclerView;
import android.text.Selection;
import android.text.SpannableStringBuilder;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -56,13 +55,11 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ComponentKeyMapper;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.views.BottomUserEducationView;
-import java.util.HashMap;
import java.util.List;
import java.util.Set;
@@ -77,6 +74,7 @@
private final ClickShadowView mTouchFeedbackView;
private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
private final ItemInfoMatcher mWorkMatcher = ItemInfoMatcher.not(mPersonalMatcher);
+ private final AllAppsStore mAllAppsStore = new AllAppsStore();
private SearchUiManager mSearchUiManager;
private View mSearchContainer;
@@ -93,8 +91,6 @@
private boolean mHasPredictions = false;
private boolean mSearchModeWhileUsingTabs = false;
- private final HashMap<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>();
-
public AllAppsContainerView(Context context) {
this(context, null);
}
@@ -133,6 +129,10 @@
// TODO: Reimplement once fast scroller is fixed.
}
+ public AllAppsStore getAppsStore() {
+ return mAllAppsStore;
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -149,67 +149,30 @@
*/
public void setApps(List<AppInfo> apps) {
boolean hasWorkProfileApp = hasWorkProfileApp(apps);
- if (mUsingTabs != hasWorkProfileApp) {
- rebindAdapters(hasWorkProfileApp);
- }
- mComponentToAppMap.clear();
- addOrUpdateApps(apps);
+ rebindAdapters(hasWorkProfileApp);
+ mAllAppsStore.setApps(apps);
}
/**
* Adds or updates existing apps in the list
*/
public void addOrUpdateApps(List<AppInfo> apps) {
- for (AppInfo app : apps) {
- mComponentToAppMap.put(app.toComponentKey(), app);
- }
- onAppsUpdated();
- mSearchUiManager.refreshSearchResult();
- mHeader.onAppsUpdated();
+ mAllAppsStore.addOrUpdateApps(apps);
}
/**
* Removes some apps from the list.
*/
public void removeApps(List<AppInfo> apps) {
- for (AppInfo app : apps) {
- mComponentToAppMap.remove(app.toComponentKey());
- }
- onAppsUpdated();
- mSearchUiManager.refreshSearchResult();
- }
-
- private void onAppsUpdated() {
- for (int i = 0; i < getNumOfAdapters(); i++) {
- mAH[i].appsList.onAppsUpdated();
- }
- }
-
- private int getNumOfAdapters() {
- return mUsingTabs ? mAH.length : 1;
+ mAllAppsStore.removeApps(apps);
}
public void updatePromiseAppProgress(PromiseAppInfo app) {
- for (int i = 0; i < mAH.length; i++) {
- updatePromiseAppProgress(app, mAH[i].recyclerView);
- }
- if (isHeaderVisible()) {
- updatePromiseAppProgress(app, mHeader.getPredictionRow());
- }
- }
-
- private void updatePromiseAppProgress(PromiseAppInfo app, ViewGroup parent) {
- if (parent == null) {
- return;
- }
- int childCount = parent.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = parent.getChildAt(i);
- if (child instanceof BubbleTextView && child.getTag() == app) {
- BubbleTextView bubbleTextView = (BubbleTextView) child;
- bubbleTextView.applyProgressLevel(app.level);
+ mAllAppsStore.updateAllIcons((child) -> {
+ if (child.getTag() == app) {
+ child.applyProgressLevel(app.level);
}
- }
+ });
}
/**
@@ -262,7 +225,7 @@
});
mHeader = findViewById(R.id.all_apps_header);
- rebindAdapters(mUsingTabs);
+ rebindAdapters(mUsingTabs, true /* force */);
mSearchContainer = findViewById(R.id.search_container_all_apps);
mSearchUiManager = (SearchUiManager) mSearchContainer;
@@ -361,34 +324,15 @@
}
public void updateIconBadges(Set<PackageUserKey> updatedBadges) {
- final PackageUserKey packageUserKey = new PackageUserKey(null, null);
- for (int j = 0; j < mAH.length; j++) {
- updateIconBadges(updatedBadges, packageUserKey, mAH[j].recyclerView);
- }
- if (mHeader != null) {
- updateIconBadges(updatedBadges, packageUserKey, mHeader.getPredictionRow());
- }
- }
-
- private void updateIconBadges(Set<PackageUserKey> updatedBadges, PackageUserKey packageUserKey,
- ViewGroup parent) {
- if (parent == null) {
- return;
- }
- final int n = parent.getChildCount();
- for (int i = 0; i < n; i++) {
- View child = parent.getChildAt(i);
- if (child instanceof PredictionRowView) {
- updateIconBadges(updatedBadges, packageUserKey, (PredictionRowView) child);
+ PackageUserKey tempKey = new PackageUserKey(null, null);
+ mAllAppsStore.updateAllIcons((child) -> {
+ if (child.getTag() instanceof ItemInfo) {
+ ItemInfo info = (ItemInfo) child.getTag();
+ if (tempKey.updateFromItemInfo(info) && updatedBadges.contains(tempKey)) {
+ child.applyBadgeState(info, true /* animate */);
+ }
}
- if (!(child instanceof BubbleTextView) || !(child.getTag() instanceof ItemInfo)) {
- continue;
- }
- ItemInfo info = (ItemInfo) child.getTag();
- if (packageUserKey.updateFromItemInfo(info) && updatedBadges.contains(packageUserKey)) {
- ((BubbleTextView) child).applyBadgeState(info, true /* animate */);
- }
- }
+ });
}
public SpringAnimationHandler getSpringAnimationHandler() {
@@ -396,11 +340,19 @@
}
private void rebindAdapters(boolean showTabs) {
- if (showTabs != mUsingTabs) {
- replaceRVContainer(showTabs);
+ rebindAdapters(showTabs, false /* force */);
+ }
+
+ private void rebindAdapters(boolean showTabs, boolean force) {
+ if (showTabs == mUsingTabs && !force) {
+ return;
}
+ replaceRVContainer(showTabs);
mUsingTabs = showTabs;
+ mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.MAIN].recyclerView);
+ mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.WORK].recyclerView);
+
if (mUsingTabs) {
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
@@ -417,6 +369,9 @@
}
}
+ mAllAppsStore.registerIconContainer(mAH[AdapterHolder.MAIN].recyclerView);
+ mAllAppsStore.registerIconContainer(mAH[AdapterHolder.WORK].recyclerView);
+
applyTouchDelegate();
}
@@ -490,9 +445,6 @@
}
public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
- if (isHeaderVisible()) {
- mHeader.getPredictionRow().setPredictedApps(apps);
- }
mAH[AdapterHolder.MAIN].appsList.setPredictedApps(apps);
boolean hasPredictions = !apps.isEmpty();
if (mHasPredictions != hasPredictions) {
@@ -504,7 +456,7 @@
}
public AppInfo findApp(ComponentKeyMapper<AppInfo> mapper) {
- return mapper.getItem(mComponentToAppMap);
+ return mAllAppsStore.getApp(mapper);
}
public AlphabeticalAppsList getApps() {
@@ -524,9 +476,9 @@
return;
}
mHeader.setVisibility(View.VISIBLE);
- mHeader.setup(mAH, mComponentToAppMap, mNumPredictedAppsPerRow);
+ mHeader.setup(mAH, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null);
- int padding = mHeader.getPredictionRow().getExpectedHeight();
+ int padding = mHeader.getMaxTranslation();
if (mHasPredictions && !mUsingTabs) {
padding += mHeader.getPaddingTop() + mHeader.getPaddingBottom();
}
@@ -540,13 +492,16 @@
for (int i = 0; i < mAH.length; i++) {
mAH[i].adapter.setLastSearchQuery(query);
}
- boolean hasQuery = !TextUtils.isEmpty(query);
- if (mUsingTabs && hasQuery) {
+ if (mUsingTabs) {
mSearchModeWhileUsingTabs = true;
rebindAdapters(false); // hide tabs
- } else if (mSearchModeWhileUsingTabs && !hasQuery) {
- mSearchModeWhileUsingTabs = false;
+ }
+ }
+
+ public void onClearSearchResult() {
+ if (mSearchModeWhileUsingTabs) {
rebindAdapters(true); // show tabs
+ mSearchModeWhileUsingTabs = false;
}
}
@@ -577,14 +532,6 @@
}
}
- public List<AppInfo> getPredictedApps() {
- if (isHeaderVisible()) {
- return mHeader.getPredictionRow().getPredictedApps();
- } else {
- return mAH[AdapterHolder.MAIN].appsList.getPredictedApps();
- }
- }
-
public boolean isHeaderVisible() {
return mHeader != null && mHeader.getVisibility() == View.VISIBLE;
}
@@ -599,7 +546,7 @@
public static final int MAIN = 0;
public static final int WORK = 1;
- final AllAppsGridAdapter adapter;
+ public final AllAppsGridAdapter adapter;
final LinearLayoutManager layoutManager;
final SpringAnimationHandler animationHandler;
final AlphabeticalAppsList appsList;
@@ -609,7 +556,7 @@
boolean verticalFadingEdge;
AdapterHolder(boolean isWork) {
- appsList = new AlphabeticalAppsList(mLauncher, mComponentToAppMap, isWork);
+ appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore, isWork);
adapter = new AllAppsGridAdapter(mLauncher, appsList, mLauncher,
AllAppsContainerView.this, true);
appsList.setAdapter(adapter);
@@ -644,11 +591,6 @@
? paddingTopForTabs : padding.top;
recyclerView.setPadding(padding.left, paddingTop, padding.right, padding.bottom);
}
- if (isHeaderVisible()) {
- PredictionRowView prv = mHeader.getPredictionRow();
- prv.setPadding(padding.left, prv.getPaddingTop() , padding.right,
- prv.getPaddingBottom());
- }
}
void applyNumsPerRow() {
@@ -658,10 +600,6 @@
}
adapter.setNumAppsPerRow(mNumAppsPerRow);
appsList.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
- if (isHeaderVisible()) {
- mHeader.getPredictionRow()
- .setNumAppsPerRow(mNumPredictedAppsPerRow);
- }
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 769f9ba..2103106 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -43,8 +43,6 @@
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.discovery.AppDiscoveryAppInfo;
-import com.android.launcher3.discovery.AppDiscoveryItemView;
import com.android.launcher3.util.PackageManagerHelper;
import java.util.List;
@@ -72,17 +70,13 @@
public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 5;
// The divider that separates prediction icons from the app list
public static final int VIEW_TYPE_PREDICTION_DIVIDER = 1 << 6;
- public static final int VIEW_TYPE_APPS_LOADING_DIVIDER = 1 << 7;
- public static final int VIEW_TYPE_DISCOVERY_ITEM = 1 << 8;
- public static final int VIEW_TYPE_WORK_TAB_FOOTER = 1 << 9;
+ public static final int VIEW_TYPE_WORK_TAB_FOOTER = 1 << 7;
// Common view type masks
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER
| VIEW_TYPE_PREDICTION_DIVIDER;
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON
| VIEW_TYPE_PREDICTION_ICON;
- public static final int VIEW_TYPE_MASK_CONTENT = VIEW_TYPE_MASK_ICON
- | VIEW_TYPE_DISCOVERY_ITEM;
public static final int VIEW_TYPE_MASK_HAS_SPRINGS = VIEW_TYPE_MASK_ICON
| VIEW_TYPE_PREDICTION_DIVIDER;
@@ -161,7 +155,7 @@
adapterPosition = Math.max(adapterPosition, mApps.getAdapterItems().size() - 1);
int extraRows = 0;
for (int i = 0; i <= adapterPosition; i++) {
- if (!isViewType(items.get(i).viewType, VIEW_TYPE_MASK_CONTENT)) {
+ if (!isViewType(items.get(i).viewType, VIEW_TYPE_MASK_ICON)) {
extraRows++;
}
}
@@ -301,12 +295,6 @@
// Ensure the all apps icon height matches the workspace icons in portrait mode.
icon.getLayoutParams().height = mLauncher.getDeviceProfile().allAppsCellHeightPx;
return new ViewHolder(icon);
- case VIEW_TYPE_DISCOVERY_ITEM:
- AppDiscoveryItemView appDiscoveryItemView = (AppDiscoveryItemView) mLayoutInflater
- .inflate(R.layout.all_apps_discovery_item, parent, false);
- appDiscoveryItemView.init(mIconClickListener, mLauncher.getAccessibilityDelegate(),
- mIconLongClickListener);
- return new ViewHolder(appDiscoveryItemView);
case VIEW_TYPE_EMPTY_SEARCH:
return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
parent, false));
@@ -320,10 +308,6 @@
}
});
return new ViewHolder(searchMarketView);
- case VIEW_TYPE_APPS_LOADING_DIVIDER:
- View loadingDividerView = mLayoutInflater.inflate(
- R.layout.all_apps_discovery_loading_divider, parent, false);
- return new ViewHolder(loadingDividerView);
case VIEW_TYPE_PREDICTION_DIVIDER:
case VIEW_TYPE_ALL_APPS_DIVIDER:
return new ViewHolder(mLayoutInflater.inflate(
@@ -346,12 +330,6 @@
icon.reset();
icon.applyFromApplicationInfo(info);
break;
- case VIEW_TYPE_DISCOVERY_ITEM:
- AppDiscoveryAppInfo appDiscoveryAppInfo = (AppDiscoveryAppInfo)
- mApps.getAdapterItems().get(position).appInfo;
- AppDiscoveryItemView view = (AppDiscoveryItemView) holder.itemView;
- view.apply(appDiscoveryAppInfo);
- break;
case VIEW_TYPE_EMPTY_SEARCH:
TextView emptyViewText = (TextView) holder.itemView;
emptyViewText.setText(mEmptySearchMessage);
@@ -366,12 +344,6 @@
searchView.setVisibility(View.GONE);
}
break;
- case VIEW_TYPE_APPS_LOADING_DIVIDER:
- int visLoading = mApps.isAppDiscoveryRunning() ? View.VISIBLE : View.GONE;
- int visLoaded = !mApps.isAppDiscoveryRunning() ? View.VISIBLE : View.GONE;
- holder.itemView.findViewById(R.id.loadingProgressBar).setVisibility(visLoading);
- holder.itemView.findViewById(R.id.loadedDivider).setVisibility(visLoaded);
- break;
case VIEW_TYPE_ALL_APPS_DIVIDER:
// nothing to do
break;
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 4f931ca..4792cc2 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -170,12 +170,6 @@
AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH);
putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
AllAppsGridAdapter.VIEW_TYPE_WORK_TAB_FOOTER);
- if (FeatureFlags.DISCOVERY_ENABLED) {
- putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
- AllAppsGridAdapter.VIEW_TYPE_APPS_LOADING_DIVIDER);
- putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
- AllAppsGridAdapter.VIEW_TYPE_DISCOVERY_ITEM);
- }
}
private void putSameHeightFor(AllAppsGridAdapter adapter, int w, int h, int... viewTypes) {
@@ -263,7 +257,7 @@
// Always scroll the view to the top so the user can see the changed results
scrollToTop();
- if (mApps.shouldShowEmptySearch()) {
+ if (mApps.hasNoFilteredResults()) {
if (mEmptySearchBackground == null) {
mEmptySearchBackground = DrawableFactory.get(getContext())
.getAllAppsBackground(getContext());
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
new file mode 100644
index 0000000..17f1c89
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -0,0 +1,127 @@
+/*
+ * 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.allapps;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.ComponentKeyMapper;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * A utility class to maintain the collection of all apps.
+ */
+public class AllAppsStore {
+
+ private final HashMap<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>();
+ private final List<OnUpdateListener> mUpdateListeners = new ArrayList<>();
+ private final ArrayList<ViewGroup> mIconContainers = new ArrayList<>();
+
+ public Collection<AppInfo> getApps() {
+ return mComponentToAppMap.values();
+ }
+
+ /**
+ * Sets the current set of apps.
+ */
+ public void setApps(List<AppInfo> apps) {
+ mComponentToAppMap.clear();
+ addOrUpdateApps(apps);
+ }
+
+ public AppInfo getApp(ComponentKey key) {
+ return mComponentToAppMap.get(key);
+ }
+
+ public AppInfo getApp(ComponentKeyMapper<AppInfo> mapper) {
+ return mapper.getItem(mComponentToAppMap);
+ }
+
+ /**
+ * Adds or updates existing apps in the list
+ */
+ public void addOrUpdateApps(List<AppInfo> apps) {
+ for (AppInfo app : apps) {
+ mComponentToAppMap.put(app.toComponentKey(), app);
+ }
+ notifyUpdate();
+ }
+
+ /**
+ * Removes some apps from the list.
+ */
+ public void removeApps(List<AppInfo> apps) {
+ for (AppInfo app : apps) {
+ mComponentToAppMap.remove(app.toComponentKey());
+ }
+ notifyUpdate();
+ }
+
+
+ private void notifyUpdate() {
+ int count = mUpdateListeners.size();
+ for (int i = 0; i < count; i++) {
+ mUpdateListeners.get(i).onAppsUpdated();
+ }
+ }
+
+ public void addUpdateListener(OnUpdateListener listener) {
+ mUpdateListeners.add(listener);
+ }
+
+ public void removeUpdateListener(OnUpdateListener listener) {
+ mUpdateListeners.remove(listener);
+ }
+
+ public void registerIconContainer(ViewGroup container) {
+ if (container != null) {
+ mIconContainers.add(container);
+ }
+ }
+
+ public void unregisterIconContainer(ViewGroup container) {
+ mIconContainers.remove(container);
+ }
+
+ public void updateAllIcons(IconAction action) {
+ for (int i = mIconContainers.size() - 1; i >= 0; i--) {
+ ViewGroup parent = mIconContainers.get(i);
+ int childCount = parent.getChildCount();
+
+ for (int j = 0; j < childCount; j++) {
+ View child = parent.getChildAt(j);
+ if (child instanceof BubbleTextView) {
+ action.apply((BubbleTextView) child);
+ }
+ }
+ }
+ }
+
+ public interface OnUpdateListener {
+ void onAppsUpdated();
+ }
+
+ public interface IconAction {
+ void apply(BubbleTextView icon);
+ }
+}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index d8a0d64..dadc6cd 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -20,7 +20,6 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.AllAppsScrim;
@@ -38,8 +37,8 @@
public class AllAppsTransitionController
implements SearchUiManager.OnScrollRangeChangeListener, LauncherStateManager.StateHandler {
- private static final Property<AllAppsTransitionController, Float> PROGRESS =
- new Property<AllAppsTransitionController, Float>(Float.class, "progress") {
+ public static final Property<AllAppsTransitionController, Float> ALL_APPS_PROGRESS =
+ new Property<AllAppsTransitionController, Float>(Float.class, "allAppsProgress") {
@Override
public Float get(AllAppsTransitionController controller) {
@@ -52,8 +51,6 @@
}
};
- private final Interpolator mHotseatAccelInterpolator = Interpolators.ACCEL_1_5;
-
public static final float PARALLAX_COEFFICIENT = .125f;
private AllAppsContainerView mAppsView;
@@ -111,7 +108,6 @@
float workspaceHotseatAlpha = Utilities.boundToRange(progress, 0f, 1f);
float alpha = 1 - workspaceHotseatAlpha;
- float hotseatAlpha = mHotseatAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
mAppsView.setTranslationY(shiftCurrent);
if (mAllAppsScrim == null) {
@@ -122,8 +118,8 @@
if (!mIsVerticalLayout) {
mAppsView.setAlpha(alpha);
- mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y, hotseatTranslation,
- hotseatAlpha);
+ mLauncher.getHotseat().setTranslationY(hotseatTranslation);
+ mLauncher.getWorkspace().getPageIndicator().setTranslationY(hotseatTranslation);
// Use a light system UI (dark icons) if all apps is behind at least half of the
// status bar.
@@ -168,7 +164,8 @@
}
Interpolator interpolator = config.userControlled ? LINEAR : FAST_OUT_SLOW_IN;
- ObjectAnimator anim = ObjectAnimator.ofFloat(this, PROGRESS, mProgress, targetProgress);
+ ObjectAnimator anim =
+ ObjectAnimator.ofFloat(this, ALL_APPS_PROGRESS, mProgress, targetProgress);
anim.setDuration(config.duration);
anim.setInterpolator(interpolator);
anim.addListener(getProgressAnimatorListener());
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index eecd009..29b32b0 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -27,9 +27,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.AlphabeticIndexCompat;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.discovery.AppDiscoveryAppInfo;
-import com.android.launcher3.discovery.AppDiscoveryItem;
-import com.android.launcher3.discovery.AppDiscoveryUpdateState;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ComponentKeyMapper;
@@ -47,7 +44,7 @@
/**
* The alphabetically sorted list of applications.
*/
-public class AlphabeticalAppsList {
+public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
public static final String TAG = "AlphabeticalAppsList";
private static final boolean DEBUG = false;
@@ -58,8 +55,6 @@
private final int mFastScrollDistributionMode = FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS;
- private AppDiscoveryUpdateState mAppDiscoveryUpdateState;
-
/**
* Info about a fast scroller section, depending if sections are merged, the fast scroller
* sections will not be the same set as the section headers.
@@ -118,17 +113,6 @@
return item;
}
- public static AdapterItem asDiscoveryItem(int pos, String sectionName, AppInfo appInfo,
- int appIndex) {
- AdapterItem item = new AdapterItem();
- item.viewType = AllAppsGridAdapter.VIEW_TYPE_DISCOVERY_ITEM;
- item.position = pos;
- item.sectionName = sectionName;
- item.appInfo = appInfo;
- item.appIndex = appIndex;
- return item;
- }
-
public static AdapterItem asEmptySearch(int pos) {
AdapterItem item = new AdapterItem();
item.viewType = AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH;
@@ -150,13 +134,6 @@
return item;
}
- public static AdapterItem asLoadingDivider(int pos) {
- AdapterItem item = new AdapterItem();
- item.viewType = AllAppsGridAdapter.VIEW_TYPE_APPS_LOADING_DIVIDER;
- item.position = pos;
- return item;
- }
-
public static AdapterItem asMarketSearch(int pos) {
AdapterItem item = new AdapterItem();
item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET;
@@ -176,7 +153,7 @@
// The set of apps from the system not including predictions
private final List<AppInfo> mApps = new ArrayList<>();
- private final HashMap<ComponentKey, AppInfo> mComponentToAppMap;
+ private final AllAppsStore mAllAppsStore;
// The set of filtered apps with the current filter
private final List<AppInfo> mFilteredApps = new ArrayList<>();
@@ -188,7 +165,6 @@
private final List<ComponentKeyMapper<AppInfo>> mPredictedAppComponents = new ArrayList<>();
// The set of predicted apps resolved from the component names and the current set of apps
private final List<AppInfo> mPredictedApps = new ArrayList<>();
- private final List<AppDiscoveryAppInfo> mDiscoveredApps = new ArrayList<>();
// Is it the work profile app list.
private final boolean mIsWork;
@@ -203,16 +179,13 @@
private int mNumAppRowsInAdapter;
private ItemInfoMatcher mItemFilter;
- public AlphabeticalAppsList(
- Context context,
- HashMap<ComponentKey,
- AppInfo> componentToAppMap,
- boolean isWork) {
- mComponentToAppMap = componentToAppMap;
+ public AlphabeticalAppsList(Context context, AllAppsStore appsStore, boolean isWork) {
+ mAllAppsStore = appsStore;
mLauncher = Launcher.getLauncher(context);
mIndexer = new AlphabeticIndexCompat(context);
mAppNameComparator = new AppInfoComparator(context);
mIsWork = isWork;
+ mAllAppsStore.addUpdateListener(this);
}
public void updateItemFilter(ItemInfoMatcher itemFilter) {
@@ -293,10 +266,6 @@
return (mSearchResults != null) && mFilteredApps.isEmpty();
}
- boolean shouldShowEmptySearch() {
- return hasNoFilteredResults() && !isAppDiscoveryRunning() && mDiscoveredApps.isEmpty();
- }
-
/**
* Sets the sorted list of filtered components.
*/
@@ -310,29 +279,15 @@
return false;
}
- public void onAppDiscoverySearchUpdate(@Nullable AppDiscoveryItem app,
- @NonNull AppDiscoveryUpdateState state) {
- mAppDiscoveryUpdateState = state;
- switch (state) {
- case START:
- mDiscoveredApps.clear();
- break;
- case UPDATE:
- mDiscoveredApps.add(new AppDiscoveryAppInfo(app));
- break;
- }
- updateAdapterItems();
- }
-
private List<AppInfo> processPredictedAppComponents(List<ComponentKeyMapper<AppInfo>> components) {
- if (mComponentToAppMap.isEmpty()) {
+ if (mAllAppsStore.getApps().isEmpty()) {
// Apps have not been bound yet.
return Collections.emptyList();
}
List<AppInfo> predictedApps = new ArrayList<>();
for (ComponentKeyMapper<AppInfo> mapper : components) {
- AppInfo info = mapper.getItem(mComponentToAppMap);
+ AppInfo info = mAllAppsStore.getApp(mapper);
if (info != null) {
predictedApps.add(info);
} else {
@@ -401,11 +356,12 @@
/**
* Updates internals when the set of apps are updated.
*/
- void onAppsUpdated() {
+ @Override
+ public void onAppsUpdated() {
// Sort the list of apps
mApps.clear();
- for (AppInfo app : mComponentToAppMap.values()) {
+ for (AppInfo app : mAllAppsStore.getApps()) {
if (mItemFilter == null || mItemFilter.matches(app, null) || hasFilter()) {
mApps.add(app);
}
@@ -540,32 +496,13 @@
}
if (hasFilter()) {
- if (isAppDiscoveryRunning() || mDiscoveredApps.size() > 0) {
- mAdapterItems.add(AdapterItem.asLoadingDivider(position++));
- // Append all app discovery results
- for (int i = 0; i < mDiscoveredApps.size(); i++) {
- AppDiscoveryAppInfo appDiscoveryAppInfo = mDiscoveredApps.get(i);
- if (appDiscoveryAppInfo.isRecent) {
- // already handled in getFilteredAppInfos()
- continue;
- }
- AdapterItem item = AdapterItem.asDiscoveryItem(position++,
- "", appDiscoveryAppInfo, appIndex++);
- mAdapterItems.add(item);
- }
-
- if (!isAppDiscoveryRunning()) {
- mAdapterItems.add(AdapterItem.asMarketSearch(position++));
- }
+ // Append the search market item
+ if (hasNoFilteredResults()) {
+ mAdapterItems.add(AdapterItem.asEmptySearch(position++));
} else {
- // Append the search market item
- if (hasNoFilteredResults()) {
- mAdapterItems.add(AdapterItem.asEmptySearch(position++));
- } else {
- mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
- }
- mAdapterItems.add(AdapterItem.asMarketSearch(position++));
+ mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
}
+ mAdapterItems.add(AdapterItem.asMarketSearch(position++));
}
if (mNumAppsPerRow != 0) {
@@ -635,33 +572,17 @@
== PackageManager.PERMISSION_GRANTED);
}
- public boolean isAppDiscoveryRunning() {
- return mAppDiscoveryUpdateState == AppDiscoveryUpdateState.START
- || mAppDiscoveryUpdateState == AppDiscoveryUpdateState.UPDATE;
- }
-
private List<AppInfo> getFiltersAppInfos() {
if (mSearchResults == null) {
return mApps;
}
ArrayList<AppInfo> result = new ArrayList<>();
for (ComponentKey key : mSearchResults) {
- AppInfo match = mComponentToAppMap.get(key);
+ AppInfo match = mAllAppsStore.getApp(key);
if (match != null) {
result.add(match);
}
}
-
- // adding recently used instant apps
- if (mDiscoveredApps.size() > 0) {
- for (int i = 0; i < mDiscoveredApps.size(); i++) {
- AppDiscoveryAppInfo discoveryAppInfo = mDiscoveredApps.get(i);
- if (discoveryAppInfo.isRecent) {
- result.add(discoveryAppInfo);
- }
- }
- Collections.sort(result, mAppNameComparator);
- }
return result;
}
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index 550fcf9..fddafb2 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -21,6 +21,8 @@
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
+import android.app.ActivityManager;
+import android.content.Context;
import android.view.MotionEvent;
import com.android.launcher3.AbstractFloatingView;
@@ -98,7 +100,8 @@
if (!launcher.isInState(NORMAL)
|| launcher.getSharedPrefs().getBoolean(APPS_VIEW_SHOWN, false)
|| AbstractFloatingView.getTopOpenView(launcher) != null
- || UserManagerCompat.getInstance(launcher).isDemoUser()) {
+ || UserManagerCompat.getInstance(launcher).isDemoUser()
+ || ActivityManager.isRunningInTestHarness()) {
return;
}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 2391768..d8a9f63 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.allapps;
-
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
@@ -27,18 +26,14 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.LinearLayout;
import android.widget.RelativeLayout;
-import com.android.launcher3.AppInfo;
import com.android.launcher3.R;
-import com.android.launcher3.util.ComponentKey;
-import java.util.HashMap;
-
-public class FloatingHeaderView extends RelativeLayout implements
+public class FloatingHeaderView extends LinearLayout implements
ValueAnimator.AnimatorUpdateListener {
-
private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
private final Point mTempOffset = new Point();
@@ -63,19 +58,18 @@
}
};
- private PredictionRowView mPredictionRow;
private ViewGroup mTabLayout;
private AllAppsRecyclerView mMainRV;
private AllAppsRecyclerView mWorkRV;
private AllAppsRecyclerView mCurrentRV;
private ViewGroup mParent;
- private boolean mTabsHidden;
private boolean mHeaderCollapsed;
- private int mMaxTranslation;
private int mSnappedScrolledY;
private int mTranslationY;
private boolean mForwardToRecyclerView;
+ protected int mMaxTranslation;
+
public FloatingHeaderView(@NonNull Context context) {
this(context, null);
}
@@ -88,17 +82,10 @@
protected void onFinishInflate() {
super.onFinishInflate();
mTabLayout = findViewById(R.id.tabs);
- mPredictionRow = findViewById(R.id.header_content);
}
- public void setup(AllAppsContainerView.AdapterHolder[] mAH,
- HashMap<ComponentKey, AppInfo> componentToAppMap, int numPredictedAppsPerRow) {
- mTabsHidden = mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null;
- mTabLayout.setVisibility(mTabsHidden ? View.GONE : View.VISIBLE);
- mPredictionRow.setup(mAH[AllAppsContainerView.AdapterHolder.MAIN].adapter,
- componentToAppMap, numPredictedAppsPerRow);
- mPredictionRow.setShowDivider(mTabsHidden);
- mMaxTranslation = mPredictionRow.getExpectedHeight();
+ public void setup(AllAppsContainerView.AdapterHolder[] mAH, boolean tabsHidden) {
+ mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE);
mMainRV = setupRV(mMainRV, mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView);
mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView);
mParent = (ViewGroup) mMainRV.getParent();
@@ -117,12 +104,12 @@
mCurrentRV = active ? mMainRV : mWorkRV;
}
- public PredictionRowView getPredictionRow() {
- return mPredictionRow;
+ public int getMaxTranslation() {
+ return mMaxTranslation;
}
private boolean canSnapAt(int currentScrollY) {
- return Math.abs(currentScrollY) <= mPredictionRow.getHeight();
+ return Math.abs(currentScrollY) <= mMaxTranslation;
}
private void moved(final int currentScrollY) {
@@ -149,16 +136,12 @@
}
}
- private void apply() {
+ protected void applyScroll(int uncappedY, int currentY) { }
+
+ protected void apply() {
int uncappedTranslationY = mTranslationY;
mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
- if (mTranslationY != uncappedTranslationY) {
- // we hide it completely if already capped (for opening search anim)
- mPredictionRow.setVisibility(View.INVISIBLE);
- } else {
- mPredictionRow.setVisibility(View.VISIBLE);
- mPredictionRow.setTranslationY(uncappedTranslationY);
- }
+ applyScroll(uncappedTranslationY, mTranslationY);
mTabLayout.setTranslationY(mTranslationY);
mClip.top = mMaxTranslation + mTranslationY;
// clipping on a draw might cause additional redraw
@@ -218,10 +201,6 @@
p.x = getLeft() - mCurrentRV.getLeft() - mParent.getLeft();
p.y = getTop() - mCurrentRV.getTop() - mParent.getTop();
}
-
- public void onAppsUpdated() {
- mPredictionRow.onAppsUpdated();
- }
}
diff --git a/src/com/android/launcher3/allapps/PredictionRowView.java b/src/com/android/launcher3/allapps/PredictionRowView.java
deleted file mode 100644
index 267ef3c..0000000
--- a/src/com/android/launcher3/allapps/PredictionRowView.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.allapps;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.launcher3.AppInfo;
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.logging.UserEventDispatcher;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.ComponentKeyMapper;
-import com.android.launcher3.util.Themes;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-
-public class PredictionRowView extends LinearLayout implements
- UserEventDispatcher.LogContainerProvider {
-
- private static final String TAG = "PredictionRowView";
-
- private HashMap<ComponentKey, AppInfo> mComponentToAppMap;
- private int mNumPredictedAppsPerRow;
- // The set of predicted app component names
- private final List<ComponentKeyMapper<AppInfo>> mPredictedAppComponents = new ArrayList<>();
- // The set of predicted apps resolved from the component names and the current set of apps
- private final ArrayList<AppInfo> mPredictedApps = new ArrayList<>();
- private final Paint mPaint;
- // This adapter is only used to create an identical item w/ same behavior as in the all apps RV
- private AllAppsGridAdapter mAdapter;
- private boolean mShowDivider;
-
- public PredictionRowView(@NonNull Context context) {
- this(context, null);
- }
-
- public PredictionRowView(@NonNull Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- setOrientation(LinearLayout.HORIZONTAL);
- setWillNotDraw(false);
- mPaint = new Paint();
- mPaint.setColor(Themes.getAttrColor(context, android.R.attr.colorControlHighlight));
- mPaint.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height));
- }
-
- public void setup(AllAppsGridAdapter adapter, HashMap<ComponentKey, AppInfo> componentToAppMap,
- int numPredictedAppsPerRow) {
- mAdapter = adapter;
- mComponentToAppMap = componentToAppMap;
- mNumPredictedAppsPerRow = numPredictedAppsPerRow;
- setVisibility(mPredictedAppComponents.isEmpty() ? View.GONE : View.VISIBLE);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getExpectedHeight(),
- MeasureSpec.EXACTLY));
- }
-
- public int getExpectedHeight() {
- int height = 0;
- if (!mPredictedAppComponents.isEmpty()) {
- height += Launcher.getLauncher(getContext())
- .getDeviceProfile().allAppsCellHeightPx;
- height += getPaddingTop() + getPaddingBottom();
- }
- return height;
- }
-
- public void setShowDivider(boolean showDivider) {
- mShowDivider = showDivider;
- int paddingBottom = showDivider ? getResources()
- .getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height) : 0;
- setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
- }
-
- /**
- * Sets the number of apps per row.
- */
- public void setNumAppsPerRow(int numPredictedAppsPerRow) {
- if (mNumPredictedAppsPerRow != numPredictedAppsPerRow) {
- mNumPredictedAppsPerRow = numPredictedAppsPerRow;
- onPredictionsUpdated();
- }
- }
-
- /**
- * Returns the predicted apps.
- */
- public List<AppInfo> getPredictedApps() {
- return mPredictedApps;
- }
-
- /**
- * Sets the current set of predicted apps.
- *
- * This can be called before we get the full set of applications, we should merge the results
- * only in onPredictionsUpdated() which is idempotent.
- *
- * If the number of predicted apps is the same as the previous list of predicted apps,
- * we can optimize by swapping them in place.
- */
- public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
- mPredictedAppComponents.clear();
- mPredictedAppComponents.addAll(apps);
- mPredictedApps.clear();
- mPredictedApps.addAll(processPredictedAppComponents(mPredictedAppComponents));
- onPredictionsUpdated();
- }
-
- private void onPredictionsUpdated() {
- int childCountBefore = getChildCount();
- if (getChildCount() != mNumPredictedAppsPerRow) {
- while (getChildCount() > mNumPredictedAppsPerRow) {
- removeViewAt(0);
- }
- while (getChildCount() < mNumPredictedAppsPerRow) {
- AllAppsGridAdapter.ViewHolder holder = mAdapter
- .onCreateViewHolder(this, AllAppsGridAdapter.VIEW_TYPE_ICON);
- BubbleTextView icon = (BubbleTextView) holder.itemView;
- LinearLayout.LayoutParams params =
- new LayoutParams(0, icon.getLayoutParams().height);
- params.weight = 1;
- icon.setLayoutParams(params);
- addView(icon);
- }
- }
-
- for (int i = 0; i < getChildCount(); i++) {
- BubbleTextView icon = (BubbleTextView) getChildAt(i);
- icon.reset();
- if (mPredictedApps.size() > i) {
- icon.setVisibility(View.VISIBLE);
- icon.applyFromApplicationInfo(mPredictedApps.get(i));
- } else {
- icon.setVisibility(View.INVISIBLE);
- }
- }
-
- if (getChildCount() > 0 && childCountBefore == 0
- || getChildCount() == 0 && childCountBefore > 0) {
- // setting up header to adjust the height
- // only necessary if childcount switches from/to 0
- Launcher.getLauncher(getContext()).getAppsView().setupHeader();
- }
- }
-
- /**
- * Refreshes the app icons in the row view, while preserving the same set of predictions.
- */
- public void onAppsUpdated() {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (!(child instanceof BubbleTextView)) {
- continue;
- }
- if (i >= mPredictedApps.size()) {
- break;
- }
- BubbleTextView icon = (BubbleTextView) getChildAt(i);
- icon.reset();
- icon.applyFromApplicationInfo(mPredictedApps.get(i));
- }
- }
-
- private List<AppInfo> processPredictedAppComponents(
- List<ComponentKeyMapper<AppInfo>> components) {
- if (mComponentToAppMap.isEmpty()) {
- // Apps have not been bound yet.
- return Collections.emptyList();
- }
-
- List<AppInfo> predictedApps = new ArrayList<>();
- for (ComponentKeyMapper<AppInfo> mapper : components) {
- AppInfo info = mapper.getItem(mComponentToAppMap);
- if (info != null) {
- predictedApps.add(info);
- } else {
- if (FeatureFlags.IS_DOGFOOD_BUILD) {
- Log.e(TAG, "Predicted app not found: " + mapper);
- }
- }
- // Stop at the number of predicted apps
- if (predictedApps.size() == mNumPredictedAppsPerRow) {
- break;
- }
- }
- return predictedApps;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- if (mShowDivider) {
- int side = getResources().getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
- int y = getHeight() - (getPaddingBottom() / 2);
- int x1 = getPaddingLeft() + side;
- int x2 = getWidth() - getPaddingRight() - side;
- canvas.drawLine(x1, y, x2, y, mPaint);
- }
- }
-
- @Override
- public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
- LauncherLogProto.Target targetParent) {
- for (int i = 0; i < mPredictedApps.size(); i++) {
- AppInfo appInfo = mPredictedApps.get(i);
- if (appInfo == info) {
- targetParent.containerType = LauncherLogProto.ContainerType.PREDICTION;
- target.predictedRank = i;
- break;
- }
- }
- }
-}
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index f562b6a..bb17ed5 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -35,12 +35,6 @@
@NonNull SpringAnimation getSpringForFling();
/**
- * Notifies the search manager that the apps-list has changed and the search UI should be
- * updated accordingly.
- */
- void refreshSearchResult();
-
- /**
* Notifies the search manager to close any active search session.
*/
void reset();
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index bf03a0e..e83904f 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -28,8 +28,6 @@
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
-import com.android.launcher3.discovery.AppDiscoveryItem;
-import com.android.launcher3.discovery.AppDiscoveryUpdateState;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageManagerHelper;
@@ -164,18 +162,6 @@
* Called when the search results should be cleared.
*/
void clearSearchResult();
-
- /**
- * Called when the app discovery is providing an update of search, which can either be
- * START for starting a new discovery,
- * UPDATE for providing a new search result, can be called multiple times,
- * END for indicating the end of results.
- *
- * @param app result item if UPDATE, else null
- * @param app the update state, START, UPDATE or END
- */
- void onAppDiscoverySearchUpdate(@Nullable AppDiscoveryItem app,
- @NonNull AppDiscoveryUpdateState state);
}
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index e65a2c4..a56c8b8 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -21,7 +21,6 @@
import android.support.animation.SpringAnimation;
import android.support.animation.SpringForce;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
@@ -37,10 +36,9 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.AlphabeticalAppsList;
import com.android.launcher3.allapps.SearchUiManager;
-import com.android.launcher3.discovery.AppDiscoveryItem;
-import com.android.launcher3.discovery.AppDiscoveryUpdateState;
import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.util.ComponentKey;
@@ -50,7 +48,8 @@
* Layout to contain the All-apps search UI.
*/
public class AppsSearchContainerLayout extends FrameLayout
- implements SearchUiManager, AllAppsSearchBarController.Callbacks {
+ implements SearchUiManager, AllAppsSearchBarController.Callbacks,
+ AllAppsStore.OnUpdateListener {
private final Launcher mLauncher;
private final int mMinHeight;
@@ -113,9 +112,22 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mLauncher.getAppsView().getAppsStore().addUpdateListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mLauncher.getAppsView().getAppsStore().removeUpdateListener(this);
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- getLayoutParams().height = mLauncher.getDragLayer().getInsets().top + mMinHeight;
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ if (!dp.isVerticalBarLayout()) {
+ getLayoutParams().height = dp.getInsets().top + mMinHeight;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@@ -136,7 +148,7 @@
}
@Override
- public void refreshSearchResult() {
+ public void onAppsUpdated() {
mSearchBarController.refreshSearchResult();
}
@@ -184,15 +196,7 @@
mSearchQueryBuilder.clear();
mSearchQueryBuilder.clearSpans();
Selection.setSelection(mSearchQueryBuilder, 0);
- }
-
- @Override
- public void onAppDiscoverySearchUpdate(
- @Nullable AppDiscoveryItem app, @NonNull AppDiscoveryUpdateState state) {
- if (!mLauncher.isDestroyed()) {
- mApps.onAppDiscoverySearchUpdate(app, state);
- notifyResultChanged();
- }
+ mAppsView.onClearSearchResult();
}
private void notifyResultChanged() {
@@ -208,7 +212,7 @@
int oldLeft, int oldTop, int oldRight, int oldBottom) {
DeviceProfile dp = mLauncher.getDeviceProfile();
if (!dp.isVerticalBarLayout()) {
- Rect insets = mLauncher.getDragLayer().getInsets();
+ Rect insets = dp.getInsets();
int hotseatBottom = bottom - dp.hotseatBarBottomPaddingPx - insets.bottom;
int searchTopMargin = insets.top + (mMinHeight - mSearchBoxHeight)
+ ((MarginLayoutParams) getLayoutParams()).bottomMargin;
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 8826e64..ee0dba6 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -20,6 +20,7 @@
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
+import android.view.animation.OvershootInterpolator;
import android.view.animation.PathInterpolator;
@@ -42,6 +43,11 @@
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ public static final Interpolator AGGRESSIVE_EASE = new PathInterpolator(0.2f, 0f, 0f, 1f);
+ public static final Interpolator AGGRESSIVE_EASE_IN_OUT = new PathInterpolator(0.8f,0, 0.4f, 1);
+
+ public static final Interpolator OVERSHOOT_0 = new OvershootInterpolator(0);
+
/**
* Inversion of zInterpolate, compounded with an ease-out.
*/
diff --git a/src/com/android/launcher3/anim/RevealOutlineAnimation.java b/src/com/android/launcher3/anim/RevealOutlineAnimation.java
index c6b62fa..afb8875 100644
--- a/src/com/android/launcher3/anim/RevealOutlineAnimation.java
+++ b/src/com/android/launcher3/anim/RevealOutlineAnimation.java
@@ -80,4 +80,8 @@
public float getRadius() {
return mOutlineRadius;
}
+
+ public void getOutline(Rect out) {
+ out.set(mOutline);
+ }
}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 2d0e630..059b04e 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -44,8 +44,6 @@
public static final boolean QSB_ON_FIRST_SCREEN = true;
// When enabled the all-apps icon is not added to the hotseat.
public static final boolean NO_ALL_APPS_ICON = true;
- // When enabled, app discovery will be enabled if service is implemented
- public static final boolean DISCOVERY_ENABLED = false;
// When true, custom widgets are loaded using CustomWidgetParser.
public static final boolean ENABLE_CUSTOM_WIDGETS = false;
diff --git a/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java b/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java
deleted file mode 100644
index 26e5066..0000000
--- a/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.discovery;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.graphics.Color;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import com.android.launcher3.AppInfo;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.graphics.ColorExtractor;
-
-public class AppDiscoveryAppInfo extends AppInfo {
-
- public final boolean showAsDiscoveryItem;
- public final boolean isInstantApp;
- public final boolean isRecent;
- public final float rating;
- public final long reviewCount;
- public final @NonNull String publisher;
- public final @NonNull Intent installIntent;
- public final @NonNull Intent launchIntent;
- public final @Nullable String priceFormatted;
-
- public AppDiscoveryAppInfo(AppDiscoveryItem item) {
- this.intent = item.isInstantApp ? item.launchIntent : item.installIntent;
- this.title = item.title;
- this.iconBitmap = item.bitmap;
- this.iconColor = iconBitmap == null ? Color.TRANSPARENT :
- ColorExtractor.findDominantColorByHue(item.bitmap);
- this.usingLowResIcon = false;
- this.isInstantApp = item.isInstantApp;
- this.isRecent = item.isRecent;
- this.rating = item.starRating;
- this.showAsDiscoveryItem = true;
- this.publisher = item.publisher != null ? item.publisher : "";
- this.priceFormatted = item.price;
- this.componentName = new ComponentName(item.packageName, "");
- this.installIntent = item.installIntent;
- this.launchIntent = item.launchIntent;
- this.reviewCount = item.reviewCount;
- this.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
- }
-
- @Override
- public ShortcutInfo makeShortcut() {
- if (!isDragAndDropSupported()) {
- throw new RuntimeException("DnD is currently not supported for discovered store apps");
- }
- return super.makeShortcut();
- }
-
- public boolean isDragAndDropSupported() {
- return isInstantApp;
- }
-
-}
diff --git a/src/com/android/launcher3/discovery/AppDiscoveryItem.java b/src/com/android/launcher3/discovery/AppDiscoveryItem.java
deleted file mode 100644
index 2e48b25..0000000
--- a/src/com/android/launcher3/discovery/AppDiscoveryItem.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.discovery;
-
-import android.content.Intent;
-import android.graphics.Bitmap;
-
-/**
- * This class represents the model for a discovered app via app discovery.
- * It holds all information for one result retrieved from an app discovery service.
- */
-public class AppDiscoveryItem {
-
- public final String packageName;
- public final boolean isInstantApp;
- public final boolean isRecent;
- public final float starRating;
- public final long reviewCount;
- public final Intent launchIntent;
- public final Intent installIntent;
- public final CharSequence title;
- public final String publisher;
- public final String price;
- public final Bitmap bitmap;
-
- public AppDiscoveryItem(String packageName,
- boolean isInstantApp,
- boolean isRecent,
- float starRating,
- long reviewCount,
- CharSequence title,
- String publisher,
- Bitmap bitmap,
- String price,
- Intent launchIntent,
- Intent installIntent) {
- this.packageName = packageName;
- this.isInstantApp = isInstantApp;
- this.isRecent = isRecent;
- this.starRating = starRating;
- this.reviewCount = reviewCount;
- this.launchIntent = launchIntent;
- this.installIntent = installIntent;
- this.title = title;
- this.publisher = publisher;
- this.price = price;
- this.bitmap = bitmap;
- }
-
-}
diff --git a/src/com/android/launcher3/discovery/AppDiscoveryItemView.java b/src/com/android/launcher3/discovery/AppDiscoveryItemView.java
deleted file mode 100644
index 809d724..0000000
--- a/src/com/android/launcher3/discovery/AppDiscoveryItemView.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.discovery;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import com.android.launcher3.R;
-
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-
-public class AppDiscoveryItemView extends RelativeLayout {
-
- private static boolean SHOW_REVIEW_COUNT = false;
-
- private ImageView mImage;
- private TextView mTitle;
- private TextView mRatingText;
- private RatingView mRatingView;
- private TextView mReviewCount;
- private TextView mPrice;
- private OnLongClickListener mOnLongClickListener;
-
- public AppDiscoveryItemView(Context context) {
- this(context, null);
- }
-
- public AppDiscoveryItemView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public AppDiscoveryItemView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- this.mImage = (ImageView) findViewById(R.id.image);
- this.mTitle = (TextView) findViewById(R.id.title);
- this.mRatingText = (TextView) findViewById(R.id.rating);
- this.mRatingView = (RatingView) findViewById(R.id.rating_view);
- this.mPrice = (TextView) findViewById(R.id.price);
- this.mReviewCount = (TextView) findViewById(R.id.review_count);
- }
-
- public void init(OnClickListener clickListener,
- AccessibilityDelegate accessibilityDelegate,
- OnLongClickListener onLongClickListener) {
- setOnClickListener(clickListener);
- mImage.setOnClickListener(clickListener);
- setAccessibilityDelegate(accessibilityDelegate);
- mOnLongClickListener = onLongClickListener;
- }
-
- public void apply(@NonNull AppDiscoveryAppInfo info) {
- setTag(info);
- mImage.setTag(info);
- mImage.setImageBitmap(info.iconBitmap);
- mImage.setOnLongClickListener(info.isDragAndDropSupported() ? mOnLongClickListener : null);
- mTitle.setText(info.title);
- mPrice.setText(info.priceFormatted != null ? info.priceFormatted : "");
- mReviewCount.setVisibility(SHOW_REVIEW_COUNT ? View.VISIBLE : View.GONE);
- if (info.rating >= 0) {
- mRatingText.setText(new DecimalFormat("#.0").format(info.rating));
- mRatingView.setRating(info.rating);
- mRatingView.setVisibility(View.VISIBLE);
- String reviewCountFormatted = NumberFormat.getInstance().format(info.reviewCount);
- mReviewCount.setText("(" + reviewCountFormatted + ")");
- } else {
- // if we don't have a rating
- mRatingView.setVisibility(View.GONE);
- mRatingText.setText("");
- mReviewCount.setText("");
- }
- }
-}
diff --git a/src/com/android/launcher3/discovery/AppDiscoveryUpdateState.java b/src/com/android/launcher3/discovery/AppDiscoveryUpdateState.java
deleted file mode 100644
index 0700a10..0000000
--- a/src/com/android/launcher3/discovery/AppDiscoveryUpdateState.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.discovery;
-
-public enum AppDiscoveryUpdateState {
- START, UPDATE, END
-}
diff --git a/src/com/android/launcher3/discovery/RatingView.java b/src/com/android/launcher3/discovery/RatingView.java
deleted file mode 100644
index 8fe63d6..0000000
--- a/src/com/android/launcher3/discovery/RatingView.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.discovery;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.drawable.ClipDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-
-import com.android.launcher3.R;
-
-/**
- * A simple rating view that shows stars with a rating from 0-5.
- */
-public class RatingView extends View {
-
- private static final float WIDTH_FACTOR = 0.9f;
- private static final int MAX_LEVEL = 10000;
- private static final int MAX_STARS = 5;
-
- private final Drawable mStarDrawable;
- private final int mColorGray;
- private final int mColorHighlight;
-
- private float rating;
-
- public RatingView(Context context) {
- this(context, null);
- }
-
- public RatingView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public RatingView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mStarDrawable = getResources().getDrawable(R.drawable.ic_star_rating, null);
- mColorGray = 0x1E000000;
- mColorHighlight = 0x8A000000;
- }
-
- public void setRating(float rating) {
- this.rating = Math.min(Math.max(rating, 0), MAX_STARS);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- drawStars(canvas, MAX_STARS, mColorGray);
- drawStars(canvas, rating, mColorHighlight);
- }
-
- private void drawStars(Canvas canvas, float stars, int color) {
- int fullWidth = getLayoutParams().width;
- int cellWidth = fullWidth / MAX_STARS;
- int starWidth = (int) (cellWidth * WIDTH_FACTOR);
- int padding = cellWidth - starWidth;
- int fullStars = (int) stars;
- float partialStarFactor = stars - fullStars;
-
- for (int i = 0; i < fullStars; i++) {
- int x = i * cellWidth + padding;
- Drawable star = mStarDrawable.getConstantState().newDrawable().mutate();
- star.setTint(color);
- star.setBounds(x, padding, x + starWidth, padding + starWidth);
- star.draw(canvas);
- }
- if (partialStarFactor > 0f) {
- int x = fullStars * cellWidth + padding;
- ClipDrawable star = new ClipDrawable(mStarDrawable,
- Gravity.LEFT, ClipDrawable.HORIZONTAL);
- star.setTint(color);
- star.setLevel((int) (MAX_LEVEL * partialStarFactor));
- star.setBounds(x, padding, x + starWidth, padding + starWidth);
- star.draw(canvas);
- }
- }
-}
diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
index 4629dad..9638a75 100644
--- a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
@@ -75,13 +75,14 @@
}
@Override
- public void init(Launcher launcher, boolean alreadyOnHome) {
+ public boolean init(Launcher launcher, boolean alreadyOnHome) {
AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
launcher.getStateManager().goToState(NORMAL, alreadyOnHome /* animated */);
launcher.getDragLayer().setOnDragListener(this);
mLauncher = launcher;
mDragController = launcher.getDragController();
+ return false;
}
@Override
@@ -176,7 +177,4 @@
mLauncher.getDragLayer().setOnDragListener(null);
}
}
-
- @Override
- public void onLauncherResume() { }
}
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index c75e616..a32f6b1 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -52,7 +52,6 @@
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.uioverrides.UiFactory;
-import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.TouchController;
@@ -366,10 +365,13 @@
}
@Override
- public void setInsets(Rect insets) {
- super.setInsets(insets);
- setBackground(insets.top == 0 ? null
- : Themes.getAttrDrawable(getContext(), R.attr.workspaceStatusBarScrim));
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ ev.offsetLocation(getTranslationX(), 0);
+ try {
+ return super.dispatchTouchEvent(ev);
+ } finally {
+ ev.offsetLocation(-getTranslationX(), 0);
+ }
}
@Override
diff --git a/src/com/android/launcher3/graphics/GradientView.java b/src/com/android/launcher3/graphics/GradientView.java
index bacb063..6253e18 100644
--- a/src/com/android/launcher3/graphics/GradientView.java
+++ b/src/com/android/launcher3/graphics/GradientView.java
@@ -75,7 +75,7 @@
this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm);
this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, dm);
Launcher launcher = Launcher.getLauncher(context);
- this.mAlphaStart = launcher.getDeviceProfile().isVerticalBarLayout() ? 0 : 100;
+ this.mAlphaStart = 0;
this.mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
this.mWallpaperColorInfo = WallpaperColorInfo.getInstance(launcher);
mAlphaColors = getResources().getInteger(R.integer.extracted_color_gradient_alpha);
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 883c33d..00dd3aa 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -54,7 +54,6 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIconPreviewVerifier;
-import com.android.launcher3.graphics.IconNormalizer;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.provider.ImportDataTask;
diff --git a/src/com/android/launcher3/model/ModelPreload.java b/src/com/android/launcher3/model/ModelPreload.java
new file mode 100644
index 0000000..6f33bed
--- /dev/null
+++ b/src/com/android/launcher3/model/ModelPreload.java
@@ -0,0 +1,70 @@
+/*
+ * 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.model;
+
+import android.content.Context;
+import android.support.annotation.WorkerThread;
+import android.util.Log;
+
+import com.android.launcher3.AllAppsList;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Utility class to preload LauncherModel
+ */
+public class ModelPreload implements ModelUpdateTask {
+
+ private static final String TAG = "ModelPreload";
+
+ private LauncherAppState mApp;
+ private LauncherModel mModel;
+ private BgDataModel mBgDataModel;
+ private AllAppsList mAllAppsList;
+
+ @Override
+ public final void init(LauncherAppState app, LauncherModel model, BgDataModel dataModel,
+ AllAppsList allAppsList, Executor uiExecutor) {
+ mApp = app;
+ mModel = model;
+ mBgDataModel = dataModel;
+ mAllAppsList = allAppsList;
+ }
+
+ @Override
+ public final void run() {
+ if (!mModel.isModelLoaded()) {
+ Log.d(TAG, "Workspace not loaded, loading now");
+ mModel.startLoaderForResults(
+ new LoaderResults(mApp, mBgDataModel, mAllAppsList, 0, null));
+ }
+ Log.d(TAG, "Preload completed : " + mModel.isModelLoaded());
+ onComplete(mModel.isModelLoaded());
+ }
+
+ /**
+ * Called when the task is complete
+ */
+ @WorkerThread
+ public void onComplete(boolean isSuccess) { }
+
+ public void start(Context context) {
+ LauncherAppState.getInstance(context).getModel().enqueueModelUpdateTask(this);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLandscape.java b/src/com/android/launcher3/pageindicators/PageIndicatorLandscape.java
deleted file mode 100644
index d76998a..0000000
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLandscape.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.pageindicators;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup.MarginLayoutParams;
-import android.widget.FrameLayout;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
-
-/**
- * Simply draws the caret drawable bottom-right aligned in the view. This ensures that we can have
- * a view with as large an area as we want (for touching) while maintaining a caret of size
- * all_apps_caret_size. Used only for the landscape layout.
- */
-public class PageIndicatorLandscape extends PageIndicator implements OnClickListener, Insettable {
- // all apps pull up handle drawable.
-
- private final Launcher mLauncher;
-
- public PageIndicatorLandscape(Context context) {
- this(context, null);
- }
-
- public PageIndicatorLandscape(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public PageIndicatorLandscape(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- setOnClickListener(this);
- mLauncher = Launcher.getLauncher(context);
- setOnFocusChangeListener(mLauncher.mFocusHandler);
- }
-
- @Override
- public void onClick(View view) {
- Launcher l = Launcher.getLauncher(getContext());
- if (!l.isInState(ALL_APPS)) {
- l.getUserEventDispatcher().logActionOnControl(
- Action.Touch.TAP, ControlType.ALL_APPS_BUTTON);
- l.getStateManager().goToState(ALL_APPS);
- }
- }
-
- @Override
- public void setInsets(Rect insets) {
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
- DeviceProfile grid = mLauncher.getDeviceProfile();
- if (insets.left > insets.right) {
- lp.leftMargin = grid.hotseatBarSidePaddingPx;
- lp.rightMargin = insets.right;
- lp.gravity = Gravity.RIGHT | Gravity.BOTTOM;
- } else {
- lp.leftMargin = insets.left;
- lp.rightMargin = grid.hotseatBarSidePaddingPx;
- lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
- }
- lp.bottomMargin = grid.workspacePadding.bottom;
- setLayoutParams(lp);
- }
-}
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLine.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
similarity index 64%
rename from src/com/android/launcher3/pageindicators/PageIndicatorLine.java
rename to src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
index 8c9642c..3e4bd31 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLine.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -1,5 +1,9 @@
package com.android.launcher3.pageindicators;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -15,7 +19,10 @@
import android.util.AttributeSet;
import android.util.Property;
import android.view.Gravity;
+import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
+import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import com.android.launcher3.DeviceProfile;
@@ -24,13 +31,17 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.dynamicui.WallpaperColorInfo;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
/**
- * A PageIndicator that briefly shows a fraction of a line when moving between pages.
+ * A PageIndicator that briefly shows a fraction of a line when moving between pages in
+ * portrait mode. In Landscape simply draws the caret drawable bottom-corner aligned in
+ * the drag-layer.
*
* The fraction is 1 / number of pages and the position is based on the progress of the page scroll.
*/
-public class PageIndicatorLine extends PageIndicator implements Insettable {
+public class WorkspacePageIndicator extends PageIndicator implements Insettable, OnClickListener {
private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
@@ -45,6 +56,7 @@
private final Handler mDelayedLineFadeHandler = new Handler(Looper.getMainLooper());
private final Launcher mLauncher;
+ private final AccessibilityManager mAccessibilityManager;
private boolean mShouldAutoHide = true;
@@ -59,59 +71,61 @@
private Paint mLinePaint;
private final int mLineHeight;
- private static final Property<PageIndicatorLine, Integer> PAINT_ALPHA
- = new Property<PageIndicatorLine, Integer>(Integer.class, "paint_alpha") {
+ private boolean mIsLandscapeUi;
+
+ private static final Property<WorkspacePageIndicator, Integer> PAINT_ALPHA
+ = new Property<WorkspacePageIndicator, Integer>(Integer.class, "paint_alpha") {
@Override
- public Integer get(PageIndicatorLine obj) {
+ public Integer get(WorkspacePageIndicator obj) {
return obj.mLinePaint.getAlpha();
}
@Override
- public void set(PageIndicatorLine obj, Integer alpha) {
+ public void set(WorkspacePageIndicator obj, Integer alpha) {
obj.mLinePaint.setAlpha(alpha);
- obj.invalidate();
+ obj.invalidateIfPortrait();
}
};
- private static final Property<PageIndicatorLine, Float> NUM_PAGES
- = new Property<PageIndicatorLine, Float>(Float.class, "num_pages") {
+ private static final Property<WorkspacePageIndicator, Float> NUM_PAGES
+ = new Property<WorkspacePageIndicator, Float>(Float.class, "num_pages") {
@Override
- public Float get(PageIndicatorLine obj) {
+ public Float get(WorkspacePageIndicator obj) {
return obj.mNumPagesFloat;
}
@Override
- public void set(PageIndicatorLine obj, Float numPages) {
+ public void set(WorkspacePageIndicator obj, Float numPages) {
obj.mNumPagesFloat = numPages;
- obj.invalidate();
+ obj.invalidateIfPortrait();
}
};
- private static final Property<PageIndicatorLine, Integer> TOTAL_SCROLL
- = new Property<PageIndicatorLine, Integer>(Integer.class, "total_scroll") {
+ private static final Property<WorkspacePageIndicator, Integer> TOTAL_SCROLL
+ = new Property<WorkspacePageIndicator, Integer>(Integer.class, "total_scroll") {
@Override
- public Integer get(PageIndicatorLine obj) {
+ public Integer get(WorkspacePageIndicator obj) {
return obj.mTotalScroll;
}
@Override
- public void set(PageIndicatorLine obj, Integer totalScroll) {
+ public void set(WorkspacePageIndicator obj, Integer totalScroll) {
obj.mTotalScroll = totalScroll;
- obj.invalidate();
+ obj.invalidateIfPortrait();
}
};
private Runnable mHideLineRunnable = () -> animateLineToAlpha(0);
- public PageIndicatorLine(Context context) {
+ public WorkspacePageIndicator(Context context) {
this(context, null);
}
- public PageIndicatorLine(Context context, AttributeSet attrs) {
+ public WorkspacePageIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public PageIndicatorLine(Context context, AttributeSet attrs, int defStyle) {
+ public WorkspacePageIndicator(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
Resources res = context.getResources();
@@ -124,11 +138,13 @@
boolean darkText = WallpaperColorInfo.getInstance(context).supportsDarkText();
mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE);
+ mAccessibilityManager = (AccessibilityManager)
+ getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
}
@Override
protected void onDraw(Canvas canvas) {
- if (mTotalScroll == 0 || mNumPagesFloat == 0) {
+ if (mTotalScroll == 0 || mNumPagesFloat == 0 || mIsLandscapeUi) {
return;
}
@@ -155,7 +171,7 @@
} else if (mTotalScroll != totalScroll) {
animateToTotalScroll(totalScroll);
} else {
- invalidate();
+ invalidateIfPortrait();
}
if (mShouldAutoHide) {
@@ -233,10 +249,53 @@
@Override
public void setInsets(Rect insets) {
DeviceProfile grid = mLauncher.getDeviceProfile();
+ mIsLandscapeUi = grid.isVerticalBarLayout();
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
- lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- lp.height = grid.pageIndicatorSizePx;
- lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom;
+
+ if (mIsLandscapeUi) {
+ if (grid.isSeascape()) {
+ lp.leftMargin = grid.hotseatBarSidePaddingPx;
+ lp.rightMargin = insets.right;
+ lp.gravity = Gravity.RIGHT | Gravity.BOTTOM;
+ } else {
+ lp.leftMargin = insets.left;
+ lp.rightMargin = grid.hotseatBarSidePaddingPx;
+ lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
+ }
+ lp.bottomMargin = grid.workspacePadding.bottom;
+ lp.width = lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.dynamic_grid_min_page_indicator_size);
+
+ setBackgroundResource(R.drawable.all_apps_handle_landscape);
+ setOnFocusChangeListener(mLauncher.mFocusHandler);
+ setOnClickListener(this);
+
+ } else {
+ lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ lp.height = grid.pageIndicatorSizePx;
+ lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom;
+ lp.width = MATCH_PARENT;
+
+ setBackgroundResource(0);
+ setOnFocusChangeListener(null);
+ setOnClickListener(mAccessibilityManager.isTouchExplorationEnabled() ? this : null);
+ }
+
setLayoutParams(lp);
}
+
+ private void invalidateIfPortrait() {
+ if (!mIsLandscapeUi) {
+ invalidate();
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (!mLauncher.isInState(ALL_APPS)) {
+ mLauncher.getUserEventDispatcher().logActionOnControl(
+ Action.Touch.TAP, ControlType.ALL_APPS_BUTTON);
+ mLauncher.getStateManager().goToState(ALL_APPS);
+ }
+ }
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index f90abb4..b3ef7bb 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -62,6 +62,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate;
+import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.dragndrop.DragController;
@@ -810,10 +811,10 @@
return;
}
mEndRect.setEmpty();
+ if (getOutlineProvider() instanceof RevealOutlineAnimation) {
+ ((RevealOutlineAnimation) getOutlineProvider()).getOutline(mEndRect);
+ }
if (mOpenCloseAnimator != null) {
- Outline outline = new Outline();
- getOutlineProvider().getOutline(this, outline);
- outline.getRect(mEndRect);
mOpenCloseAnimator.cancel();
}
mIsOpen = false;
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 42aa12b..d2bcd18 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -82,7 +82,7 @@
@Override
public void onClick(View view) {
Rect sourceBounds = launcher.getViewBounds(view);
- Bundle opts = launcher.getActivityLaunchOptions(view);
+ Bundle opts = launcher.getActivityLaunchOptions(view, false);
InfoDropTarget.startDetailsActivityForInfo(itemInfo, launcher, sourceBounds, opts);
launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
ControlType.APPINFO_TARGET, view);
@@ -115,8 +115,8 @@
public View.OnClickListener createOnClickListener(Launcher launcher, ItemInfo itemInfo) {
return view -> {
- Intent intent = PackageManagerHelper.getMarketIntent(itemInfo
- .getTargetComponent().getPackageName());
+ Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent(
+ itemInfo.getTargetComponent().getPackageName());
launcher.startActivitySafely(view, intent, itemInfo);
AbstractFloatingView.closeAllOpenViews(launcher);
};
diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java
index f084fd2..4c3ef4b 100644
--- a/src/com/android/launcher3/states/InternalStateHandler.java
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -21,7 +21,11 @@
import android.os.IBinder;
import com.android.launcher3.Launcher;
-import com.android.launcher3.Launcher.OnResumeCallback;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel.Callbacks;
+import com.android.launcher3.util.Preconditions;
+
+import java.lang.ref.WeakReference;
/**
* Utility class to sending state handling logic to Launcher from within the same process.
@@ -29,11 +33,17 @@
* Extending {@link Binder} ensures that the platform maintains a single instance of each object
* which allows this object to safely navigate the system process.
*/
-public abstract class InternalStateHandler extends Binder implements OnResumeCallback {
+public abstract class InternalStateHandler extends Binder {
public static final String EXTRA_STATE_HANDLER = "launcher.state_handler";
- protected abstract void init(Launcher launcher, boolean alreadyOnHome);
+ private static WeakReference<InternalStateHandler> sPendingHandler = new WeakReference<>(null);
+
+ /**
+ * Initializes the handler when the launcher is ready.
+ * @return true if the handler wants to stay alive.
+ */
+ protected abstract boolean init(Launcher launcher, boolean alreadyOnHome);
public final Intent addToIntent(Intent intent) {
Bundle extras = new Bundle();
@@ -42,6 +52,29 @@
return intent;
}
+ public final void initWhenReady() {
+ Preconditions.assertUIThread();
+ sPendingHandler = new WeakReference<>(this);
+ LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+ if (app == null) {
+ return;
+ }
+ Callbacks cb = app.getModel().getCallback();
+ if (!(cb instanceof Launcher)) {
+ return;
+ }
+ Launcher launcher = (Launcher) cb;
+ if (!init(launcher, launcher.isStarted())) {
+ sPendingHandler.clear();
+ }
+ }
+
+ public void clearReference() {
+ if (sPendingHandler.get() == this) {
+ sPendingHandler.clear();
+ }
+ }
+
public static boolean handleCreate(Launcher launcher, Intent intent) {
return handleIntent(launcher, intent, false);
}
@@ -57,12 +90,21 @@
IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER);
if (stateBinder instanceof InternalStateHandler) {
InternalStateHandler handler = (InternalStateHandler) stateBinder;
- launcher.setOnResumeCallback(handler);
- handler.init(launcher, alreadyOnHome);
+ if (!handler.init(launcher, alreadyOnHome)) {
+ intent.getExtras().remove(EXTRA_STATE_HANDLER);
+ }
result = true;
}
- intent.getExtras().remove(EXTRA_STATE_HANDLER);
+ }
+ if (!result) {
+ InternalStateHandler pendingHandler = sPendingHandler.get();
+ if (pendingHandler != null) {
+ if (!pendingHandler.init(launcher, alreadyOnHome)) {
+ sPendingHandler.clear();
+ }
+ result = true;
+ }
}
return result;
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/util/ComponentKeyMapper.java b/src/com/android/launcher3/util/ComponentKeyMapper.java
index 916176a..a7f0d76 100644
--- a/src/com/android/launcher3/util/ComponentKeyMapper.java
+++ b/src/com/android/launcher3/util/ComponentKeyMapper.java
@@ -18,8 +18,6 @@
import android.support.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
public class ComponentKeyMapper<T> {
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 13034dd..81df153 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -143,13 +143,15 @@
return false;
}
- public static Intent getMarketIntent(String packageName) {
+ public Intent getMarketIntent(String packageName) {
return new Intent(Intent.ACTION_VIEW)
.setData(new Uri.Builder()
.scheme("market")
.authority("details")
.appendQueryParameter("id", packageName)
- .build());
+ .build())
+ .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app")
+ .authority(mContext.getPackageName()).build());
}
/**
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index 0f3ac57..bde9c0a 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -55,7 +55,7 @@
public static void partitionSection(String sectionName, String partition) {
if (ENABLED) {
MutableLong time = sUpTimes.get(sectionName);
- if (time.value >= 0) {
+ if (time != null && time.value >= 0) {
if (SYSTEM_TRACE) {
Trace.endSection();
@@ -78,7 +78,7 @@
public static void endSection(String sectionName, String msg) {
if (ENABLED) {
MutableLong time = sUpTimes.get(sectionName);
- if (time.value >= 0) {
+ if (time != null && time.value >= 0) {
if (SYSTEM_TRACE) {
Trace.endSection();
}
diff --git a/src/com/android/launcher3/util/VerticalSwipeController.java b/src/com/android/launcher3/util/VerticalSwipeController.java
index 5d47cd2..29477e3 100644
--- a/src/com/android/launcher3/util/VerticalSwipeController.java
+++ b/src/com/android/launcher3/util/VerticalSwipeController.java
@@ -259,7 +259,7 @@
});
float nextFrameProgress = Utilities.boundToRange(
- progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
+ progress + velocity * SINGLE_FRAME_MS * mProgressMultiplier, 0f, 1f);
ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
anim.setFloatValues(nextFrameProgress, targetState == mToState ? 1f : 0f);
diff --git a/src/com/android/launcher3/views/AllAppsScrim.java b/src/com/android/launcher3/views/AllAppsScrim.java
index 5d39adb..662f99c 100644
--- a/src/com/android/launcher3/views/AllAppsScrim.java
+++ b/src/com/android/launcher3/views/AllAppsScrim.java
@@ -23,6 +23,7 @@
import android.graphics.Rect;
import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
+import android.util.Property;
import android.view.View;
import com.android.launcher3.DeviceProfile;
@@ -46,6 +47,7 @@
protected final WallpaperColorInfo mWallpaperColorInfo;
private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Rect mDrawRect = new Rect();
private final Rect mPadding = new Rect();
private final Rect mInsets = new Rect();
private final DeviceProfile mGrid;
@@ -62,7 +64,7 @@
private int mFillAlpha;
private float mDrawHeight;
- private float mTranslateY;
+ private float mDrawOffsetY;
public AllAppsScrim(Context context) {
this(context, null);
@@ -108,6 +110,10 @@
return result;
}
+ public Bitmap getShadowBitmap() {
+ return mShadowBitmap;
+ }
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
@@ -135,7 +141,7 @@
@Override
protected void onDraw(Canvas canvas) {
- float edgeTop = getHeight() + mTranslateY - mDrawHeight + mPadding.top;
+ float edgeTop = getHeight() + mDrawOffsetY - mDrawHeight + mPadding.top;
float edgeRight = getWidth() - mPadding.right;
if (mPadding.left > 0 || mPadding.right > 0) {
@@ -153,12 +159,29 @@
}
public void setProgress(float translateY, float alpha) {
- mFillAlpha = Math.round(alpha * mAlphaRange + mMinAlpha);
- mFillPaint.setAlpha(mFillAlpha);
+ int newAlpha = Math.round(alpha * mAlphaRange + mMinAlpha);
+ // Negative translation means the scrim is moving up. For negative translation, we change
+ // draw offset as it requires redraw (since more area of the scrim needs to be shown). For
+ // position translation, we simply translate the scrim down as it avoids invalidate and
+ // hence could be optimized by the platform.
+ float drawOffsetY = Math.min(translateY, 0);
- mTranslateY = translateY;
+ if (newAlpha != mFillAlpha || drawOffsetY != mDrawOffsetY) {
+ invalidateDrawRect();
- invalidate();
+ mFillAlpha = newAlpha;
+ mFillPaint.setAlpha(mFillAlpha);
+ mDrawOffsetY = drawOffsetY;
+ invalidateDrawRect();
+ }
+
+ setTranslationY(Math.max(translateY, 0));
+ }
+
+ private void invalidateDrawRect() {
+ mDrawRect.top = (int) (getHeight()
+ + mDrawOffsetY - mDrawHeight + mPadding.top - mShadowBlur - 0.5f);
+ invalidate(mDrawRect);
}
public void setDrawRegion(float height) {
@@ -178,6 +201,24 @@
float scrimMargin = getResources().getDimension(R.dimen.all_apps_scrim_margin);
setDrawRegion(mGrid.hotseatBarSizePx + insets.bottom + scrimMargin);
}
+ updateDrawRect();
invalidate();
}
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ updateDrawRect();
+ }
+
+ private void updateDrawRect() {
+ mDrawRect.bottom = getHeight();
+ if (mGrid.isVerticalBarLayout()) {
+ mDrawRect.left = (int) (mPadding.left - mShadowBlur - 0.5f);
+ mDrawRect.right = (int) (getWidth() - mPadding.right + 0.5f);
+ } else {
+ mDrawRect.left = 0;
+ mDrawRect.right = getWidth();
+ }
+ }
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
index 24236d8..fd33ee1 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
@@ -62,6 +62,11 @@
}
@Override
+ public float getHoseatAlpha(Launcher launcher) {
+ return 0;
+ }
+
+ @Override
public View getFinalFocus(Launcher launcher) {
return launcher.getAppsView();
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
index 26dd68f..2d39505 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
@@ -37,6 +37,7 @@
import com.android.launcher3.WorkspaceStateTransitionAnimation.AnimatedPropertySetter;
import com.android.launcher3.WorkspaceStateTransitionAnimation.PropertySetter;
import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.widget.WidgetsFullSheet;
@@ -158,7 +159,7 @@
.setPackage(getContext().getPackageName());
intent.setSourceBounds(mLauncher.getViewBounds(v));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- getContext().startActivity(intent, mLauncher.getActivityLaunchOptions(v));
+ getContext().startActivity(intent, mLauncher.getActivityLaunchOptions(v, false));
}
@Override
@@ -173,8 +174,7 @@
}
private void setState(LauncherState state, PropertySetter setter) {
- float hotseatAlpha = state.getHoseatAlpha(mLauncher);
- setter.setViewAlpha(null, this, 1f - hotseatAlpha);
+ setter.setViewAlpha(this, 1f - state.getHoseatAlpha(mLauncher), Interpolators.ACCEL);
}
public static int getButtonBarHeight(Launcher launcher) {
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 2ea10c2..744125e 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -20,6 +20,9 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.PointF;
+import android.os.Bundle;
+import android.view.View;
import android.view.View.AccessibilityDelegate;
import com.android.launcher3.Launcher;
@@ -46,7 +49,7 @@
launcher.getAllAppsController(), launcher.getWorkspace() };
}
- public static void onWorkspaceLongPress(Launcher launcher) {
+ public static void onWorkspaceLongPress(Launcher launcher, PointF touchPoint) {
launcher.getStateManager().goToState(OVERVIEW);
}