Merge "Enable slice again" into sc-dev
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 9c14b85..7431551 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -41,7 +41,7 @@
<uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY"/>
<uses-permission android:name="${packageName}.permission.HOTSEAT_EDU" />
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
<application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 034d51f..588d676 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -56,17 +56,22 @@
return mHandler;
}
- // Called only in R+ platform
+ // Called only in S+ platform
@BinderThread
- public void onAnimationStart(RemoteAnimationTargetCompat[] appTargets,
- RemoteAnimationTargetCompat[] wallpaperTargets, Runnable runnable) {
+ public void onAnimationStart(
+ int transit,
+ RemoteAnimationTargetCompat[] appTargets,
+ RemoteAnimationTargetCompat[] wallpaperTargets,
+ RemoteAnimationTargetCompat[] nonAppTargets,
+ Runnable runnable) {
Runnable r = () -> {
finishExistingAnimation();
mAnimationResult = new AnimationResult(() -> {
UI_HELPER_EXECUTOR.execute(runnable);
mAnimationResult = null;
});
- onCreateAnimation(appTargets, wallpaperTargets, mAnimationResult);
+ onCreateAnimation(transit, appTargets, wallpaperTargets, nonAppTargets,
+ mAnimationResult);
};
if (mStartAtFrontOfQueue) {
postAtFrontOfQueueAsynchronously(mHandler, r);
@@ -75,6 +80,14 @@
}
}
+ // Called only in R platform
+ @BinderThread
+ public void onAnimationStart(RemoteAnimationTargetCompat[] appTargets,
+ RemoteAnimationTargetCompat[] wallpaperTargets, Runnable runnable) {
+ onAnimationStart(0 /* transit */, appTargets, wallpaperTargets,
+ new RemoteAnimationTargetCompat[0], runnable);
+ }
+
// Called only in Q platform
@BinderThread
@Deprecated
@@ -88,8 +101,11 @@
*/
@UiThread
public abstract void onCreateAnimation(
+ int transit,
RemoteAnimationTargetCompat[] appTargets,
- RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result);
+ RemoteAnimationTargetCompat[] wallpaperTargets,
+ RemoteAnimationTargetCompat[] nonAppTargets,
+ AnimationResult result);
@UiThread
private void finishExistingAnimation() {
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 876cabc..c4b6961 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -866,8 +866,10 @@
}
@Override
- public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
+ public void onCreateAnimation(int transit,
+ RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
+ RemoteAnimationTargetCompat[] nonAppTargets,
LauncherAnimationRunner.AnimationResult result) {
if (mLauncher.isDestroyed()) {
AnimatorSet anim = new AnimatorSet();
@@ -880,7 +882,8 @@
// If launcher is not resumed, wait until new async-frame after resume
mLauncher.addOnResumeCallback(() ->
postAsyncCallback(mHandler, () ->
- onCreateAnimation(appTargets, wallpaperTargets, result)));
+ onCreateAnimation(transit, appTargets, wallpaperTargets,
+ nonAppTargets, result)));
return;
}
@@ -964,8 +967,10 @@
}
@Override
- public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
+ public void onCreateAnimation(int transit,
+ RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
+ RemoteAnimationTargetCompat[] nonAppTargets,
LauncherAnimationRunner.AnimationResult result) {
AnimatorSet anim = new AnimatorSet();
diff --git a/quickstep/src/com/android/launcher3/WrappedAnimationRunnerImpl.java b/quickstep/src/com/android/launcher3/WrappedAnimationRunnerImpl.java
index da2aee4..03cc28e 100644
--- a/quickstep/src/com/android/launcher3/WrappedAnimationRunnerImpl.java
+++ b/quickstep/src/com/android/launcher3/WrappedAnimationRunnerImpl.java
@@ -26,7 +26,9 @@
*/
public interface WrappedAnimationRunnerImpl {
Handler getHandler();
- void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
+ void onCreateAnimation(int transit,
+ RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
+ RemoteAnimationTargetCompat[] nonAppTargets,
LauncherAnimationRunner.AnimationResult result);
}
diff --git a/quickstep/src/com/android/launcher3/WrappedLauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/WrappedLauncherAnimationRunner.java
index 1753b62..1e1631b 100644
--- a/quickstep/src/com/android/launcher3/WrappedLauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/WrappedLauncherAnimationRunner.java
@@ -46,11 +46,15 @@
}
@Override
- public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
- RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) {
+ public void onCreateAnimation(int transit,
+ RemoteAnimationTargetCompat[] appTargets,
+ RemoteAnimationTargetCompat[] wallpaperTargets,
+ RemoteAnimationTargetCompat[] nonAppTargets,
+ AnimationResult result) {
R animationRunnerImpl = mImpl.get();
if (animationRunnerImpl != null) {
- animationRunnerImpl.onCreateAnimation(appTargets, wallpaperTargets, result);
+ animationRunnerImpl.onCreateAnimation(transit, appTargets, wallpaperTargets,
+ nonAppTargets, result);
}
}
}
diff --git a/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java b/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
index e302b4f..4d7cc85 100644
--- a/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
+++ b/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
@@ -17,6 +17,7 @@
package com.android.launcher3.proxy;
import android.app.Activity;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
@@ -48,19 +49,20 @@
return;
}
- if (mParams.intent != null) {
- startActivityForResult(mParams.intent, mParams.requestCode, mParams.options);
- return;
- } else if (mParams.intentSender != null) {
- try {
+ try {
+ if (mParams.intent != null) {
+ startActivityForResult(mParams.intent, mParams.requestCode, mParams.options);
+ return;
+ } else if (mParams.intentSender != null) {
startIntentSenderForResult(mParams.intentSender, mParams.requestCode,
mParams.fillInIntent, mParams.flagsMask, mParams.flagsValues,
mParams.extraFlags,
mParams.options);
return;
- } catch (SendIntentException e) {
- mParams.deliverResult(this, RESULT_CANCELED, null);
}
+ } catch (NullPointerException | ActivityNotFoundException | SecurityException
+ | SendIntentException e) {
+ mParams.deliverResult(this, RESULT_CANCELED, null);
}
finishAndRemoveTask();
}
diff --git a/quickstep/src/com/android/launcher3/search/DeviceSearchEdu.java b/quickstep/src/com/android/launcher3/search/DeviceSearchEdu.java
index 425e557..016ec1b 100644
--- a/quickstep/src/com/android/launcher3/search/DeviceSearchEdu.java
+++ b/quickstep/src/com/android/launcher3/search/DeviceSearchEdu.java
@@ -73,16 +73,15 @@
}
- private void close(boolean animate, boolean markAsSeen) {
- handleClose(animate);
- if (markAsSeen) {
- mLauncher.getOnboardingPrefs().markChecked(SEARCH_EDU_SEEN);
- }
+ private void dismiss() {
+ handleClose(true);
+ mLauncher.getOnboardingPrefs().markChecked(SEARCH_EDU_SEEN);
}
@Override
protected void handleClose(boolean animate) {
handleClose(animate, ANIMATION_DURATION);
+ mLauncher.getAllAppsController().getInsetController().show();
mLauncher.getStateManager().removeStateListener(this);
}
@@ -110,7 +109,7 @@
findViewById(R.id.dismiss_edu).setOnClickListener((view) -> {
mSwitchFocusOnDismiss = true;
- close(true, true);
+ dismiss();
});
}
@@ -176,7 +175,7 @@
@Override
public void onStateTransitionStart(LauncherState toState) {
- close(true, false);
+ dismiss();
}
@Override
@@ -203,7 +202,7 @@
if (mSearchInput != null) {
mSearchInput.setText(charSequence.toString());
mSwitchFocusOnDismiss = true;
- close(true, true);
+ dismiss();
}
}
@@ -215,7 +214,7 @@
@Override
public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
mSearchInput.onEditorAction(i);
- close(true, true);
+ dismiss();
return true;
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
index 0093e66..3b361c4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME;
+import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
+
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
@@ -22,10 +25,18 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.anim.AlphaUpdateListener;
+import com.android.systemui.shared.system.ViewTreeObserverWrapper;
+
/**
* Top-level ViewGroup that hosts the TaskbarView as well as Views created by it such as Folder.
*/
public class TaskbarContainerView extends FrameLayout {
+
+ // Initialized in init.
+ private TaskbarView mTaskbarView;
+ private ViewTreeObserverWrapper.OnComputeInsetsListener mTaskbarInsetsComputer;
+
public TaskbarContainerView(@NonNull Context context) {
this(context, null);
}
@@ -43,4 +54,41 @@
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
+
+ protected void init(TaskbarView taskbarView) {
+ mTaskbarView = taskbarView;
+ mTaskbarInsetsComputer = createTaskbarInsetsComputer();
+ }
+
+ private ViewTreeObserverWrapper.OnComputeInsetsListener createTaskbarInsetsComputer() {
+ return insetsInfo -> {
+ if (getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
+ // We're invisible, let touches pass through us.
+ insetsInfo.touchableRegion.setEmpty();
+ insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+ } else {
+ // We're visible again, accept touches anywhere in our bounds.
+ insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
+ }
+ };
+ }
+
+ protected void cleanup() {
+ ViewTreeObserverWrapper.removeOnComputeInsetsListener(mTaskbarInsetsComputer);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ ViewTreeObserverWrapper.addOnComputeInsetsListener(getViewTreeObserver(),
+ mTaskbarInsetsComputer);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ cleanup();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
index 6a74aac..260428d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
@@ -38,7 +38,6 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepAppTransitionManagerImpl;
import com.android.launcher3.R;
-import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.states.StateAnimationConfig;
@@ -107,7 +106,6 @@
@Override
public void updateTaskbarVisibilityAlpha(float alpha) {
mTaskbarContainerView.setAlpha(alpha);
- AlphaUpdateListener.updateVisibility(mTaskbarContainerView);
}
};
}
@@ -167,6 +165,7 @@
public void init() {
mTaskbarView.init(mHotseatController.getNumHotseatIcons(),
mRecentsController.getNumRecentIcons());
+ mTaskbarContainerView.init(mTaskbarView);
addToWindowManager();
mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks());
mTaskbarVisibilityController.init();
@@ -188,6 +187,7 @@
*/
public void cleanup() {
mTaskbarView.cleanup();
+ mTaskbarContainerView.cleanup();
removeFromWindowManager();
mTaskbarStateHandler.setTaskbarCallbacks(null);
mTaskbarVisibilityController.cleanup();
@@ -218,6 +218,7 @@
mWindowLayoutParams.setFitInsetsTypes(0);
mWindowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ mWindowLayoutParams.setSystemApplicationOverlay(true);
WindowManagerWrapper wmWrapper = WindowManagerWrapper.getInstance();
wmWrapper.setProvidesInsetsTypes(
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 7beeae2..8aa0842 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -184,8 +184,11 @@
}
@Override
- public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
- RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) {
+ public void onCreateAnimation(int transit,
+ RemoteAnimationTargetCompat[] appTargets,
+ RemoteAnimationTargetCompat[] wallpaperTargets,
+ RemoteAnimationTargetCompat[] nonAppTargets,
+ AnimationResult result) {
AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
wallpaperTargets);
anim.addListener(resetStateListener());
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
index 19c6588..3adb459 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
@@ -43,8 +43,11 @@
}
@Override
- public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
- RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) {
+ public void onCreateAnimation(int transit,
+ RemoteAnimationTargetCompat[] appTargets,
+ RemoteAnimationTargetCompat[] wallpaperTargets,
+ RemoteAnimationTargetCompat[] nonApps,
+ AnimationResult result) {
result.setAnimation(createWindowAnimation(appTargets, wallpaperTargets), context);
}
};
diff --git a/res/layout/keyboard_drag_and_drop.xml b/res/layout/keyboard_drag_and_drop.xml
new file mode 100644
index 0000000..e9463c4
--- /dev/null
+++ b/res/layout/keyboard_drag_and_drop.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.keyboard.KeyboardDragAndDropView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:orientation="vertical"
+ android:elevation="6dp">
+
+ <TextView
+ android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="?attr/folderFillColor"
+ android:padding="8dp"
+ android:textColor="?attr/folderTextColor"
+ />
+
+</com.android.launcher3.keyboard.KeyboardDragAndDropView>
\ No newline at end of file
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
new file mode 100644
index 0000000..b8600a6
--- /dev/null
+++ b/res/values-v31/colors.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2021, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <color name="popup_color_primary_light">@android:color/system_main_50</color>
+ <color name="popup_color_secondary_light">@android:color/system_main_100</color>
+ <color name="popup_color_tertiary_light">@android:color/system_main_300</color>
+ <color name="popup_color_primary_dark">@android:color/system_main_800</color>
+ <color name="popup_color_secondary_dark">@android:color/system_main_900</color>
+ <color name="popup_color_tertiary_dark">@android:color/system_main_700</color>
+
+ <color name="workspace_text_color_light">@android:color/system_main_50</color>
+ <color name="workspace_text_color_dark">@android:color/system_main_900</color>
+
+ <color name="text_color_primary_dark">@android:color/system_main_50</color>
+ <color name="text_color_secondary_dark">@android:color/system_main_200</color>
+ <color name="text_color_tertiary_dark">@android:color/system_main_400</color>
+</resources>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 78c2df6..0b30253 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -40,4 +40,19 @@
<color name="gesture_tutorial_fake_previous_task_view_color">#9CCC65</color> <!-- Light Green -->
<color name="gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
<color name="gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
+
+ <color name="popup_color_primary_light">#FFF</color>
+ <color name="popup_color_secondary_light">#F1F3F4</color>
+ <color name="popup_color_tertiary_light">#E0E0E0</color> <!-- Gray 300 -->
+ <color name="popup_color_primary_dark">#3C4043</color> <!-- Gray 800 -->
+ <color name="popup_color_secondary_dark">#202124</color>
+ <color name="popup_color_tertiary_dark">#757575</color> <!-- Gray 600 -->
+
+ <color name="workspace_text_color_light">#FFF</color>
+ <color name="workspace_text_color_dark">#FF212121</color>
+
+ <color name="text_color_primary_dark">#FFFFFFFF</color>
+ <color name="text_color_secondary_dark">#FFFFFFFF</color>
+ <color name="text_color_tertiary_dark">#CCFFFFFF</color>
+
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index cf51f77..eaf7a5f 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -139,6 +139,7 @@
<dimen name="drag_flingToDeleteMinVelocity">-1500dp</dimen>
<dimen name="spring_loaded_panel_border">1dp</dimen>
+ <dimen name="keyboard_drag_stroke_width">4dp</dimen>
<!-- Folders -->
<dimen name="page_indicator_dot_size">8dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index dc7182f..adc2238 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -35,12 +35,12 @@
<item name="allAppsInterimScrimAlpha">46</item>
<item name="allAppsNavBarScrimColor">#66FFFFFF</item>
<item name="allAppsTheme">@style/AllAppsTheme</item>
- <item name="popupColorPrimary">#FFF</item>
- <item name="popupColorSecondary">#F1F3F4</item>
- <item name="popupColorTertiary">#E0E0E0</item> <!-- Gray 300 -->
+ <item name="popupColorPrimary">@color/popup_color_primary_light</item>
+ <item name="popupColorSecondary">@color/popup_color_secondary_light</item>
+ <item name="popupColorTertiary">@color/popup_color_tertiary_light</item>
<item name="isMainColorDark">false</item>
<item name="isWorkspaceDarkText">false</item>
- <item name="workspaceTextColor">@android:color/white</item>
+ <item name="workspaceTextColor">@color/workspace_text_color_light</item>
<item name="workspaceShadowColor">#B0000000</item>
<item name="workspaceAmbientShadowColor">#33000000</item>
<item name="workspaceKeyShadowColor">#44000000</item>
@@ -74,7 +74,7 @@
</style>
<style name="LauncherTheme.DarkText" parent="@style/LauncherTheme">
- <item name="workspaceTextColor">#FF212121</item>
+ <item name="workspaceTextColor">@color/workspace_text_color_dark</item>
<item name="allAppsInterimScrimAlpha">128</item>
<item name="workspaceShadowColor">@android:color/transparent</item>
<item name="workspaceAmbientShadowColor">@android:color/transparent</item>
@@ -88,9 +88,9 @@
</style>
<style name="LauncherTheme.Dark" parent="@style/LauncherTheme">
- <item name="android:textColorPrimary">#FFFFFFFF</item>
- <item name="android:textColorSecondary">#FFFFFFFF</item>
- <item name="android:textColorTertiary">#CCFFFFFF</item>
+ <item name="android:textColorPrimary">@color/text_color_primary_dark</item>
+ <item name="android:textColorSecondary">@color/text_color_secondary_dark</item>
+ <item name="android:textColorTertiary">@color/text_color_tertiary_dark</item>
<item name="android:textColorHint">#A0FFFFFF</item>
<item name="android:colorControlHighlight">#A0FFFFFF</item>
<item name="android:colorPrimary">#FF212121</item>
@@ -98,9 +98,9 @@
<item name="allAppsInterimScrimAlpha">102</item>
<item name="allAppsNavBarScrimColor">#80000000</item>
<item name="allAppsTheme">@style/AllAppsTheme.Dark</item>
- <item name="popupColorPrimary">#3C4043</item> <!-- Gray 800 -->
- <item name="popupColorSecondary">#202124</item>
- <item name="popupColorTertiary">#757575</item> <!-- Gray 600 -->
+ <item name="popupColorPrimary">@color/popup_color_primary_dark</item>
+ <item name="popupColorSecondary">@color/popup_color_secondary_dark</item>
+ <item name="popupColorTertiary">@color/popup_color_tertiary_dark</item>
<item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
<item name="folderDotColor">?android:attr/colorPrimary</item>
<item name="folderFillColor">?android:attr/colorBackground</item>
@@ -125,7 +125,7 @@
<item name="allAppsInterimScrimAlpha">25</item>
<item name="folderFillColor">#CDFFFFFF</item>
<item name="folderTextColor">?attr/workspaceTextColor</item>
- <item name="workspaceTextColor">#FF212121</item>
+ <item name="workspaceTextColor">@color/workspace_text_color_dark</item>
<item name="workspaceShadowColor">@android:color/transparent</item>
<item name="workspaceAmbientShadowColor">@android:color/transparent</item>
<item name="workspaceKeyShadowColor">@android:color/transparent</item>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 3c34444..6037c96 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -76,17 +76,18 @@
public static final int TYPE_SNACKBAR = 1 << 7;
public static final int TYPE_LISTENER = 1 << 8;
public static final int TYPE_ALL_APPS_EDU = 1 << 9;
+ public static final int TYPE_DRAG_DROP_POPUP = 1 << 10;
// Popups related to quickstep UI
- public static final int TYPE_TASK_MENU = 1 << 10;
- public static final int TYPE_OPTIONS_POPUP = 1 << 11;
- public static final int TYPE_ICON_SURFACE = 1 << 12;
+ public static final int TYPE_TASK_MENU = 1 << 11;
+ public static final int TYPE_OPTIONS_POPUP = 1 << 12;
+ public static final int TYPE_ICON_SURFACE = 1 << 13;
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
| TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
| TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER | TYPE_ALL_APPS_EDU
- | TYPE_ICON_SURFACE;
+ | TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP;
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
@@ -103,7 +104,7 @@
// These view all have particular operation associated with swipe down interaction.
public static final int TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW = TYPE_WIDGETS_BOTTOM_SHEET |
TYPE_WIDGETS_FULL_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_ON_BOARD_POPUP |
- TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU ;
+ TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU | TYPE_DRAG_DROP_POPUP;
protected boolean mIsOpen;
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index df005e6..459b9a8 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -240,7 +240,7 @@
@Override
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
- mActive = supportsDrop(dragObject.dragInfo);
+ mActive = !options.isKeyboardDrag && supportsDrop(dragObject.dragInfo);
mDrawable.setColorFilter(null);
if (mCurrentColorAnim != null) {
mCurrentColorAnim.cancel();
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 2809bd5..452207d 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -312,6 +312,13 @@
}
}
+ /**
+ * Returns the currently set accessibility delegate
+ */
+ public DragAndDropAccessibilityDelegate getDragAndDropAccessibilityDelegate() {
+ return mTouchHelper;
+ }
+
@Override
public boolean dispatchHoverEvent(MotionEvent event) {
// Always attempt to dispatch hover events to accessibility first.
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index ca001a3..c768493 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -131,7 +131,10 @@
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
- if (mIsVertical) {
+ int visibleCount = getVisibleButtonsCount();
+ if (visibleCount == 0) {
+ // do nothing
+ } else if (mIsVertical) {
int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
@@ -142,7 +145,6 @@
}
}
} else {
- int visibleCount = getVisibleButtonsCount();
int availableWidth = width / visibleCount;
boolean textVisible = true;
for (ButtonDropTarget buttons : mDropTargets) {
@@ -165,7 +167,10 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- if (mIsVertical) {
+ int visibleCount = getVisibleButtonsCount();
+ if (visibleCount == 0) {
+ // do nothing
+ } else if (mIsVertical) {
int gap = getResources().getDimensionPixelSize(R.dimen.drop_target_vertical_gap);
int start = gap;
int end;
@@ -178,7 +183,6 @@
}
}
} else {
- int visibleCount = getVisibleButtonsCount();
int frameSize = (right - left) / visibleCount;
int start = frameSize / 2;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 36963f1..344ae0a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -905,7 +905,7 @@
}
logStopAndResume(false /* isResume */);
- mAppWidgetHost.setListenIfResumed(false);
+ mAppWidgetHost.setActivityStarted(false);
NotificationListener.removeNotificationsChangedListener();
}
@@ -918,7 +918,7 @@
mOverlayManager.onActivityStarted(this);
}
- mAppWidgetHost.setListenIfResumed(true);
+ mAppWidgetHost.setActivityStarted(true);
TraceHelper.INSTANCE.endSection(traceToken);
}
@@ -938,6 +938,7 @@
NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
DiscoveryBounce.showForHomeIfNeeded(this);
+ mAppWidgetHost.setActivityResumed(true);
}
private void logStopAndResume(boolean isResume) {
@@ -1031,7 +1032,7 @@
@Override
public void onStateSetEnd(LauncherState state) {
super.onStateSetEnd(state);
- getAppWidgetHost().setResumed(state == LauncherState.NORMAL);
+ getAppWidgetHost().setStateIsNormal(state == LauncherState.NORMAL);
getWorkspace().setClipChildren(!state.hasFlag(FLAG_MULTI_PAGE));
finishAutoCancelActionMode();
@@ -1088,6 +1089,7 @@
if (!mDeferOverlayCallbacks) {
mOverlayManager.onActivityPaused(this);
}
+ mAppWidgetHost.setActivityResumed(false);
}
class LauncherOverlayCallbacksImpl implements LauncherOverlayCallbacks {
@@ -2667,7 +2669,8 @@
&& focusedView.getTag() instanceof ItemInfo
&& mAccessibilityDelegate.performAction(focusedView,
(ItemInfo) focusedView.getTag(),
- LauncherAccessibilityDelegate.DEEP_SHORTCUTS)) {
+ LauncherAccessibilityDelegate.DEEP_SHORTCUTS,
+ true)) {
PopupContainerWithArrow.getOpen(this).requestFocus();
return true;
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 7ea6851..fea26df 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -49,8 +49,11 @@
public class LauncherAppWidgetHost extends AppWidgetHost {
private static final int FLAG_LISTENING = 1;
- private static final int FLAG_RESUMED = 1 << 1;
- private static final int FLAG_LISTEN_IF_RESUMED = 1 << 2;
+ private static final int FLAG_STATE_IS_NORMAL = 1 << 1;
+ private static final int FLAG_ACTIVITY_STARTED = 1 << 2;
+ private static final int FLAG_ACTIVITY_RESUMED = 1 << 3;
+ private static final int FLAGS_SHOULD_LISTEN =
+ FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED | FLAG_ACTIVITY_RESUMED;
public static final int APPWIDGET_HOST_ID = 1024;
@@ -59,7 +62,7 @@
private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>();
private final Context mContext;
- private int mFlags = FLAG_RESUMED;
+ private int mFlags = FLAG_STATE_IS_NORMAL;
private IntConsumer mAppWidgetRemovedCallback = null;
@@ -130,49 +133,45 @@
}
/**
- * Updates the resumed state of the host.
- * When a host is not resumed, it defers calls to startListening until host is resumed again.
- * But if the host was already listening, it will not call stopListening.
- *
- * @see #setListenIfResumed(boolean)
+ * Sets or unsets a flag the can change whether the widget host should be in the listening
+ * state.
*/
- public void setResumed(boolean isResumed) {
- if (isResumed == ((mFlags & FLAG_RESUMED) != 0)) {
- return;
- }
- if (isResumed) {
- mFlags |= FLAG_RESUMED;
- // Start listening if we were supposed to start listening on resume
- if ((mFlags & FLAG_LISTEN_IF_RESUMED) != 0 && (mFlags & FLAG_LISTENING) == 0) {
- startListening();
- }
+ private void setShouldListenFlag(int flag, boolean on) {
+ if (on) {
+ mFlags |= flag;
} else {
- mFlags &= ~FLAG_RESUMED;
+ mFlags &= ~flag;
+ }
+
+ final boolean listening = isListening();
+ if (!listening && (mFlags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN) {
+ // Postpone starting listening until all flags are on.
+ startListening();
+ } else if (listening && (mFlags & FLAG_ACTIVITY_STARTED) == 0) {
+ // Postpone stopping listening until the activity is stopped.
+ stopListening();
}
}
/**
- * Updates the listening state of the host. If the host is not resumed, startListening is
- * deferred until next resume.
- *
- * @see #setResumed(boolean)
+ * Registers an "entering/leaving Normal state" event.
*/
- public void setListenIfResumed(boolean listenIfResumed) {
- if (listenIfResumed == ((mFlags & FLAG_LISTEN_IF_RESUMED) != 0)) {
- return;
- }
- if (listenIfResumed) {
- mFlags |= FLAG_LISTEN_IF_RESUMED;
- if ((mFlags & FLAG_RESUMED) != 0) {
- // If we are resumed, start listening immediately. Note we do not check for
- // duplicate calls before calling startListening as startListening is safe to call
- // multiple times.
- startListening();
- }
- } else {
- mFlags &= ~FLAG_LISTEN_IF_RESUMED;
- stopListening();
- }
+ public void setStateIsNormal(boolean isNormal) {
+ setShouldListenFlag(FLAG_STATE_IS_NORMAL, isNormal);
+ }
+
+ /**
+ * Registers an "activity started/stopped" event.
+ */
+ public void setActivityStarted(boolean isStarted) {
+ setShouldListenFlag(FLAG_ACTIVITY_STARTED, isStarted);
+ }
+
+ /**
+ * Registers an "activity paused/resumed" event.
+ */
+ public void setActivityResumed(boolean isResumed) {
+ setShouldListenFlag(FLAG_ACTIVITY_RESUMED, isResumed);
}
@Override
diff --git a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
index ddb547f..d0fc175 100644
--- a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
@@ -31,6 +31,7 @@
import com.android.launcher3.CellLayout;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.dragndrop.DragLayer;
import java.util.List;
@@ -41,30 +42,32 @@
implements OnClickListener, OnHoverListener {
protected static final int INVALID_POSITION = -1;
- private static final int[] sTempArray = new int[2];
+ protected final Rect mTempRect = new Rect();
+ protected final int[] mTempCords = new int[2];
protected final CellLayout mView;
protected final Context mContext;
protected final LauncherAccessibilityDelegate mDelegate;
-
- private final Rect mTempRect = new Rect();
+ protected final DragLayer mDragLayer;
public DragAndDropAccessibilityDelegate(CellLayout forView) {
super(forView);
mView = forView;
mContext = mView.getContext();
- mDelegate = Launcher.getLauncher(mContext).getAccessibilityDelegate();
+ Launcher launcher = Launcher.getLauncher(mContext);
+ mDelegate = launcher.getAccessibilityDelegate();
+ mDragLayer = launcher.getDragLayer();
}
@Override
- protected int getVirtualViewAt(float x, float y) {
+ public int getVirtualViewAt(float x, float y) {
if (x < 0 || y < 0 || x > mView.getMeasuredWidth() || y > mView.getMeasuredHeight()) {
return INVALID_ID;
}
- mView.pointToCellExact((int) x, (int) y, sTempArray);
+ mView.pointToCellExact((int) x, (int) y, mTempCords);
// Map cell to id
- int id = sTempArray[0] + sTempArray[1] * mView.getCountX();
+ int id = mTempCords[0] + mTempCords[1] * mView.getCountX();
return intersectsValidDropTarget(id);
}
@@ -75,7 +78,7 @@
protected abstract int intersectsValidDropTarget(int id);
@Override
- protected void getVisibleVirtualViews(List<Integer> virtualViews) {
+ public void getVisibleVirtualViews(List<Integer> virtualViews) {
// We create a virtual view for each cell of the grid
// The cell ids correspond to cells in reading order.
int nCells = mView.getCountX() * mView.getCountY();
@@ -88,7 +91,7 @@
}
@Override
- protected boolean onPerformActionForVirtualView(int viewId, int action, Bundle args) {
+ public boolean onPerformActionForVirtualView(int viewId, int action, Bundle args) {
if (action == AccessibilityNodeInfoCompat.ACTION_CLICK && viewId != INVALID_ID) {
String confirmation = getConfirmationForIconDrop(viewId);
mDelegate.handleAccessibleDrop(mView, getItemBounds(viewId), confirmation);
@@ -112,13 +115,25 @@
}
@Override
- protected void onPopulateNodeForVirtualView(int id, AccessibilityNodeInfoCompat node) {
+ public void onPopulateNodeForVirtualView(int id, AccessibilityNodeInfoCompat node) {
if (id == INVALID_ID) {
throw new IllegalArgumentException("Invalid virtual view id");
}
node.setContentDescription(getLocationDescriptionForIconDrop(id));
- node.setBoundsInParent(getItemBounds(id));
+
+ Rect itemBounds = getItemBounds(id);
+ node.setBoundsInParent(itemBounds);
+
+ // ExploreByTouchHelper does not currently handle view scale.
+ // Update BoundsInScreen to appropriate value.
+ mTempCords[0] = mTempCords[1] = 0;
+ float scale = mDragLayer.getDescendantCoordRelativeToSelf(mView, mTempCords);
+ mTempRect.left = mTempCords[0] + (int) (itemBounds.left * scale);
+ mTempRect.right = mTempCords[0] + (int) (itemBounds.right * scale);
+ mTempRect.top = mTempCords[1] + (int) (itemBounds.top * scale);
+ mTempRect.bottom = mTempCords[1] + (int) (itemBounds.bottom * scale);
+ node.setBoundsInScreen(mTempRect);
node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
node.setClickable(true);
@@ -130,6 +145,13 @@
return dispatchHoverEvent(motionEvent);
}
+ /**
+ * Returns the target host container
+ */
+ public View getHost() {
+ return mView;
+ }
+
protected abstract String getLocationDescriptionForIconDrop(int id);
protected abstract String getConfirmationForIconDrop(int id);
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 136d43e..6fac79a 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -34,6 +34,7 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.keyboard.CustomActionsPopup;
+import com.android.launcher3.keyboard.KeyboardDragAndDropView;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -107,10 +108,6 @@
launcher.getText(R.string.shortcuts_menu_with_notifications_description)));
}
- public void addAccessibilityAction(int action, int actionLabel) {
- mActions.put(action, new AccessibilityAction(action, mLauncher.getText(actionLabel)));
- }
-
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
@@ -139,7 +136,7 @@
}
// Do not add move actions for keyboard request as this uses virtual nodes.
- if (!fromKeyboard && itemSupportsAccessibleDrag(item)) {
+ if (itemSupportsAccessibleDrag(item)) {
info.addAction(mActions.get(MOVE));
if (item.container >= 0) {
@@ -178,13 +175,17 @@
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
if ((host.getTag() instanceof ItemInfo)
- && performAction(host, (ItemInfo) host.getTag(), action)) {
+ && performAction(host, (ItemInfo) host.getTag(), action, false)) {
return true;
}
return super.performAccessibilityAction(host, action, args);
}
- public boolean performAction(final View host, final ItemInfo item, int action) {
+ /**
+ * Performs the provided action on the host
+ */
+ public boolean performAction(final View host, final ItemInfo item, int action,
+ boolean fromKeyboard) {
if (action == ACTION_LONG_CLICK) {
if (PopupContainerWithArrow.canShow(host, item)) {
// Long press should be consumed for workspace items, and it should invoke the
@@ -205,7 +206,7 @@
return true;
}
if (action == MOVE) {
- beginAccessibleDrag(host, item);
+ return beginAccessibleDrag(host, item, fromKeyboard);
} else if (action == ADD_TO_WORKSPACE) {
final int[] coordinates = new int[2];
final int screenId = findSpaceOnWorkspace(item, coordinates);
@@ -406,7 +407,11 @@
}
}
- public void beginAccessibleDrag(View item, ItemInfo info) {
+ private boolean beginAccessibleDrag(View item, ItemInfo info, boolean fromKeyboard) {
+ if (!itemSupportsAccessibleDrag(info)) {
+ return false;
+ }
+
mDragInfo = new DragInfo();
mDragInfo.info = info;
mDragInfo.item = item;
@@ -423,8 +428,17 @@
DragOptions options = new DragOptions();
options.isAccessibleDrag = true;
+ options.isKeyboardDrag = fromKeyboard;
options.simulatedDndStartPoint = new Point(pos.centerX(), pos.centerY());
- ItemLongClickListener.beginDrag(item, mLauncher, info, options);
+
+ if (fromKeyboard) {
+ KeyboardDragAndDropView popup = (KeyboardDragAndDropView) mLauncher.getLayoutInflater()
+ .inflate(R.layout.keyboard_drag_and_drop, mLauncher.getDragLayer(), false);
+ popup.showForIcon(item, info, options);
+ } else {
+ ItemLongClickListener.beginDrag(item, mLauncher, info, options);
+ }
+ return true;
}
@Override
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index d4ba11e..aaaff98 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -59,7 +59,7 @@
}
@Override
- public boolean performAction(View host, ItemInfo item, int action) {
+ public boolean performAction(View host, ItemInfo item, int action, boolean fromKeyboard) {
if (action == ADD_TO_WORKSPACE) {
if (!(host.getParent() instanceof DeepShortcutView)) {
return false;
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
index 65a261d..a331924 100644
--- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -17,17 +17,12 @@
package com.android.launcher3.accessibility;
import android.content.Context;
-import android.graphics.Rect;
import android.text.TextUtils;
import android.view.View;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-
import com.android.launcher3.CellLayout;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DragType;
-import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -38,9 +33,6 @@
*/
public class WorkspaceAccessibilityHelper extends DragAndDropAccessibilityDelegate {
- private final Rect mTempRect = new Rect();
- private final int[] mTempCords = new int[2];
-
public WorkspaceAccessibilityHelper(CellLayout layout) {
super(layout);
}
@@ -134,26 +126,6 @@
}
return "";
}
-
- @Override
- protected void onPopulateNodeForVirtualView(int id, AccessibilityNodeInfoCompat node) {
- super.onPopulateNodeForVirtualView(id, node);
-
-
- // ExploreByTouchHelper does not currently handle view scale.
- // Update BoundsInScreen to appropriate value.
- DragLayer dragLayer = Launcher.getLauncher(mView.getContext()).getDragLayer();
- mTempCords[0] = mTempCords[1] = 0;
- float scale = dragLayer.getDescendantCoordRelativeToSelf(mView, mTempCords);
-
- node.getBoundsInParent(mTempRect);
- mTempRect.left = mTempCords[0] + (int) (mTempRect.left * scale);
- mTempRect.right = mTempCords[0] + (int) (mTempRect.right * scale);
- mTempRect.top = mTempCords[1] + (int) (mTempRect.top * scale);
- mTempRect.bottom = mTempCords[1] + (int) (mTempRect.bottom * scale);
- node.setBoundsInScreen(mTempRect);
- }
-
@Override
protected String getLocationDescriptionForIconDrop(int id) {
int x = id % mView.getCountX();
diff --git a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
index f6e54aa..b34c8b8 100644
--- a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
@@ -86,6 +86,10 @@
mApps = appsView;
}
+ public void show() {
+ mApps.getWindowInsetsController().show(WindowInsets.Type.ime());
+ }
+
public void hide() {
if (!Utilities.ATLEAST_R) return;
diff --git a/src/com/android/launcher3/allapps/search/LiveSearchManager.java b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
index 71aedb8..e52c790 100644
--- a/src/com/android/launcher3/allapps/search/LiveSearchManager.java
+++ b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
@@ -16,6 +16,8 @@
package com.android.launcher3.allapps.search;
import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ENTRY;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_EXIT;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -46,6 +48,8 @@
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherState;
import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.logging.InstanceIdSequence;
+import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.SafeCloseable;
@@ -71,6 +75,7 @@
new HashMap<>();
private SearchWidgetHost mSearchWidgetHost;
private InstanceId mLogInstanceId;
+ private LauncherState mPrevLauncherState;
public LiveSearchManager(Launcher launcher) {
mLauncher = launcher;
@@ -134,6 +139,11 @@
}
@Override
+ public void onStateTransitionStart(LauncherState toState) {
+ mPrevLauncherState = mLauncher.getStateManager().getCurrentStableState();
+ }
+
+ @Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState != ALL_APPS) {
// Clear all search session related objects
@@ -142,6 +152,15 @@
clearWidgetHost();
}
+
+ StatsLogger logger = mLauncher.getStatsLogManager().logger();
+ if (finalState.equals(ALL_APPS)) {
+ mLogInstanceId = new InstanceIdSequence().newInstanceId();
+ logger.withInstanceId(mLogInstanceId).log(LAUNCHER_ALLAPPS_ENTRY);
+ } else if (mPrevLauncherState.equals(ALL_APPS)) {
+ logger.withInstanceId(mLogInstanceId).log(LAUNCHER_ALLAPPS_EXIT);
+ mLogInstanceId = null;
+ }
}
/**
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index ddf44ca..e71c12d 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -85,9 +85,6 @@
private final WorkspaceAndHotseatScrim mWorkspaceScrim;
private final OverviewScrim mOverviewScrim;
- // View that should handle move events
- private View mMoveTarget;
-
/**
* Used to create a new DragLayer from XML.
*
@@ -109,7 +106,6 @@
public void setup(DragController dragController, Workspace workspace) {
mDragController = dragController;
mWorkspaceScrim.setWorkspace(workspace);
- mMoveTarget = workspace;
recreateControllers();
}
@@ -215,12 +211,6 @@
}
@Override
- public boolean dispatchUnhandledMove(View focused, int direction) {
- return super.dispatchUnhandledMove(focused, direction)
- || mMoveTarget.dispatchUnhandledMove(focused, direction);
- }
-
- @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
ev.offsetLocation(getTranslationX(), 0);
try {
diff --git a/src/com/android/launcher3/dragndrop/DragOptions.java b/src/com/android/launcher3/dragndrop/DragOptions.java
index 959602b..e8ff8da 100644
--- a/src/com/android/launcher3/dragndrop/DragOptions.java
+++ b/src/com/android/launcher3/dragndrop/DragOptions.java
@@ -28,6 +28,9 @@
/** Whether or not an accessible drag operation is in progress. */
public boolean isAccessibleDrag = false;
+ /** Whether or not the drag operation is controlled by keyboard. */
+ public boolean isKeyboardDrag = false;
+
/**
* Specifies the start location for a simulated DnD (like system drag or accessibility drag),
* null when using internal DnD
diff --git a/src/com/android/launcher3/keyboard/CustomActionsPopup.java b/src/com/android/launcher3/keyboard/CustomActionsPopup.java
index 800598e..77ce4a8 100644
--- a/src/com/android/launcher3/keyboard/CustomActionsPopup.java
+++ b/src/com/android/launcher3/keyboard/CustomActionsPopup.java
@@ -88,6 +88,7 @@
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
- return mDelegate.performAction(mIcon, (ItemInfo) mIcon.getTag(), menuItem.getItemId());
+ return mDelegate.performAction(mIcon, (ItemInfo) mIcon.getTag(), menuItem.getItemId(),
+ true);
}
}
diff --git a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
index ae7ad10..83003ff 100644
--- a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
@@ -16,233 +16,30 @@
package com.android.launcher3.keyboard;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.RectEvaluator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
import android.graphics.Rect;
-import android.util.Property;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.Themes;
/**
* A helper class to draw background of a focused view.
*/
-public abstract class FocusIndicatorHelper implements
- OnFocusChangeListener, AnimatorUpdateListener {
-
- private static final float MIN_VISIBLE_ALPHA = 0.2f;
- private static final long ANIM_DURATION = 150;
-
- public static final Property<FocusIndicatorHelper, Float> ALPHA =
- new Property<FocusIndicatorHelper, Float>(Float.TYPE, "alpha") {
- @Override
- public void set(FocusIndicatorHelper object, Float value) {
- object.setAlpha(value);
- }
-
- @Override
- public Float get(FocusIndicatorHelper object) {
- return object.mAlpha;
- }
- };
-
- public static final Property<FocusIndicatorHelper, Float> SHIFT =
- new Property<FocusIndicatorHelper, Float>(
- Float.TYPE, "shift") {
-
- @Override
- public void set(FocusIndicatorHelper object, Float value) {
- object.mShift = value;
- }
-
- @Override
- public Float get(FocusIndicatorHelper object) {
- return object.mShift;
- }
- };
-
- private static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
- private static final Rect sTempRect1 = new Rect();
- private static final Rect sTempRect2 = new Rect();
-
- private final View mContainer;
- private final Paint mPaint;
- private final int mMaxAlpha;
-
- private final Rect mDirtyRect = new Rect();
- private boolean mIsDirty = false;
-
- private View mLastFocusedView;
-
- private View mCurrentView;
- private View mTargetView;
- /**
- * The fraction indicating the position of the focusRect between {@link #mCurrentView}
- * & {@link #mTargetView}
- */
- private float mShift;
-
- private ObjectAnimator mCurrentAnimation;
- private float mAlpha;
- private float mRadius;
+public abstract class FocusIndicatorHelper extends ItemFocusIndicatorHelper<View>
+ implements OnFocusChangeListener {
public FocusIndicatorHelper(View container) {
- mContainer = container;
-
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- int color = container.getResources().getColor(R.color.focused_background);
- mMaxAlpha = Color.alpha(color);
- mPaint.setColor(0xFF000000 | color);
-
- setAlpha(0);
- mShift = 0;
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- mRadius = Themes.getDialogCornerRadius(container.getContext());
- }
- }
-
- protected void setAlpha(float alpha) {
- mAlpha = alpha;
- mPaint.setAlpha((int) (mAlpha * mMaxAlpha));
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- invalidateDirty();
- }
-
- protected void invalidateDirty() {
- if (mIsDirty) {
- mContainer.invalidate(mDirtyRect);
- mIsDirty = false;
- }
-
- Rect newRect = getDrawRect();
- if (newRect != null) {
- mContainer.invalidate(newRect);
- }
- }
-
- public void draw(Canvas c) {
- if (mAlpha <= 0) return;
-
- Rect newRect = getDrawRect();
- if (newRect != null) {
- mDirtyRect.set(newRect);
- c.drawRoundRect((float) mDirtyRect.left, (float) mDirtyRect.top,
- (float) mDirtyRect.right, (float) mDirtyRect.bottom,
- mRadius, mRadius, mPaint);
- mIsDirty = true;
- }
- }
-
- private Rect getDrawRect() {
- if (mCurrentView != null && mCurrentView.isAttachedToWindow()) {
- viewToRect(mCurrentView, sTempRect1);
-
- if (mShift > 0 && mTargetView != null) {
- viewToRect(mTargetView, sTempRect2);
- return RECT_EVALUATOR.evaluate(mShift, sTempRect1, sTempRect2);
- } else {
- return sTempRect1;
- }
- }
- return null;
+ super(container, container.getResources().getColor(R.color.focused_background));
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
- if (hasFocus) {
- endCurrentAnimation();
-
- if (mAlpha > MIN_VISIBLE_ALPHA) {
- mTargetView = v;
-
- mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
- PropertyValuesHolder.ofFloat(ALPHA, 1),
- PropertyValuesHolder.ofFloat(SHIFT, 1));
- mCurrentAnimation.addListener(new ViewSetListener(v, true));
- } else {
- setCurrentView(v);
-
- mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
- PropertyValuesHolder.ofFloat(ALPHA, 1));
- }
-
- mLastFocusedView = v;
- } else {
- if (mLastFocusedView == v) {
- mLastFocusedView = null;
- endCurrentAnimation();
- mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
- PropertyValuesHolder.ofFloat(ALPHA, 0));
- mCurrentAnimation.addListener(new ViewSetListener(null, false));
- }
- }
-
- // invalidate once
- invalidateDirty();
-
- mLastFocusedView = hasFocus ? v : null;
- if (mCurrentAnimation != null) {
- mCurrentAnimation.addUpdateListener(this);
- mCurrentAnimation.setDuration(ANIM_DURATION).start();
- }
+ changeFocus(v, hasFocus);
}
- protected void endCurrentAnimation() {
- if (mCurrentAnimation != null) {
- mCurrentAnimation.cancel();
- mCurrentAnimation = null;
- }
- }
-
- protected void setCurrentView(View v) {
- mCurrentView = v;
- mShift = 0;
- mTargetView = null;
- }
-
- /**
- * Gets the position of {@param v} relative to {@link #mContainer}.
- */
- public abstract void viewToRect(View v, Rect outRect);
-
- private class ViewSetListener extends AnimatorListenerAdapter {
- private final View mViewToSet;
- private final boolean mCallOnCancel;
- private boolean mCalled = false;
-
- public ViewSetListener(View v, boolean callOnCancel) {
- mViewToSet = v;
- mCallOnCancel = callOnCancel;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- if (!mCallOnCancel) {
- mCalled = true;
- }
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!mCalled) {
- setCurrentView(mViewToSet);
- mCalled = true;
- }
- }
+ @Override
+ protected boolean shouldDraw(View item) {
+ return item.isAttachedToWindow();
}
/**
diff --git a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
new file mode 100644
index 0000000..57fab2d
--- /dev/null
+++ b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2021 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.keyboard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.RectEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.FloatProperty;
+import android.view.View;
+
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.Themes;
+
+/**
+ * A helper class to draw background of a focused item.
+ * @param <T> Item type
+ */
+public abstract class ItemFocusIndicatorHelper<T> implements AnimatorUpdateListener {
+
+ private static final float MIN_VISIBLE_ALPHA = 0.2f;
+ private static final long ANIM_DURATION = 150;
+
+ public static final FloatProperty<ItemFocusIndicatorHelper> ALPHA =
+ new FloatProperty<ItemFocusIndicatorHelper>("alpha") {
+
+ @Override
+ public void setValue(ItemFocusIndicatorHelper object, float value) {
+ object.setAlpha(value);
+ }
+
+ @Override
+ public Float get(ItemFocusIndicatorHelper object) {
+ return object.mAlpha;
+ }
+ };
+
+ public static final FloatProperty<ItemFocusIndicatorHelper> SHIFT =
+ new FloatProperty<ItemFocusIndicatorHelper>("shift") {
+
+ @Override
+ public void setValue(ItemFocusIndicatorHelper object, float value) {
+ object.mShift = value;
+ }
+
+ @Override
+ public Float get(ItemFocusIndicatorHelper object) {
+ return object.mShift;
+ }
+ };
+
+ private static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
+ private static final Rect sTempRect1 = new Rect();
+ private static final Rect sTempRect2 = new Rect();
+
+ private final View mContainer;
+ protected final Paint mPaint;
+ private final int mMaxAlpha;
+
+ private final Rect mDirtyRect = new Rect();
+ private boolean mIsDirty = false;
+
+ private T mLastFocusedItem;
+
+ private T mCurrentItem;
+ private T mTargetItem;
+ /**
+ * The fraction indicating the position of the focusRect between {@link #mCurrentItem}
+ * & {@link #mTargetItem}
+ */
+ private float mShift;
+
+ private ObjectAnimator mCurrentAnimation;
+ private float mAlpha;
+ private float mRadius;
+
+ public ItemFocusIndicatorHelper(View container, int color) {
+ mContainer = container;
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mMaxAlpha = Color.alpha(color);
+ mPaint.setColor(0xFF000000 | color);
+
+ setAlpha(0);
+ mShift = 0;
+ if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+ mRadius = Themes.getDialogCornerRadius(container.getContext());
+ }
+ }
+
+ protected void setAlpha(float alpha) {
+ mAlpha = alpha;
+ mPaint.setAlpha((int) (mAlpha * mMaxAlpha));
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ invalidateDirty();
+ }
+
+ protected void invalidateDirty() {
+ if (mIsDirty) {
+ mContainer.invalidate(mDirtyRect);
+ mIsDirty = false;
+ }
+
+ Rect newRect = getDrawRect();
+ if (newRect != null) {
+ mContainer.invalidate(newRect);
+ }
+ }
+
+ /**
+ * Draws the indicator on the canvas
+ */
+ public void draw(Canvas c) {
+ if (mAlpha <= 0) return;
+
+ Rect newRect = getDrawRect();
+ if (newRect != null) {
+ mDirtyRect.set(newRect);
+ c.drawRoundRect((float) mDirtyRect.left, (float) mDirtyRect.top,
+ (float) mDirtyRect.right, (float) mDirtyRect.bottom,
+ mRadius, mRadius, mPaint);
+ mIsDirty = true;
+ }
+ }
+
+ private Rect getDrawRect() {
+ if (mCurrentItem != null && shouldDraw(mCurrentItem)) {
+ viewToRect(mCurrentItem, sTempRect1);
+
+ if (mShift > 0 && mTargetItem != null) {
+ viewToRect(mTargetItem, sTempRect2);
+ return RECT_EVALUATOR.evaluate(mShift, sTempRect1, sTempRect2);
+ } else {
+ return sTempRect1;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if the provided item is valid
+ */
+ protected boolean shouldDraw(T item) {
+ return true;
+ }
+
+ protected void changeFocus(T item, boolean hasFocus) {
+ if (hasFocus) {
+ endCurrentAnimation();
+
+ if (mAlpha > MIN_VISIBLE_ALPHA) {
+ mTargetItem = item;
+
+ mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(ALPHA, 1),
+ PropertyValuesHolder.ofFloat(SHIFT, 1));
+ mCurrentAnimation.addListener(new ViewSetListener(item, true));
+ } else {
+ setCurrentItem(item);
+
+ mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(ALPHA, 1));
+ }
+
+ mLastFocusedItem = item;
+ } else {
+ if (mLastFocusedItem == item) {
+ mLastFocusedItem = null;
+ endCurrentAnimation();
+ mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(ALPHA, 0));
+ mCurrentAnimation.addListener(new ViewSetListener(null, false));
+ }
+ }
+
+ // invalidate once
+ invalidateDirty();
+
+ mLastFocusedItem = hasFocus ? item : null;
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.addUpdateListener(this);
+ mCurrentAnimation.setDuration(ANIM_DURATION).start();
+ }
+ }
+
+ protected void endCurrentAnimation() {
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.cancel();
+ mCurrentAnimation = null;
+ }
+ }
+
+ protected void setCurrentItem(T item) {
+ mCurrentItem = item;
+ mShift = 0;
+ mTargetItem = null;
+ }
+
+ /**
+ * Gets the position of the item relative to {@link #mContainer}.
+ */
+ public abstract void viewToRect(T item, Rect outRect);
+
+ private class ViewSetListener extends AnimatorListenerAdapter {
+ private final T mItemToSet;
+ private final boolean mCallOnCancel;
+ private boolean mCalled = false;
+
+ ViewSetListener(T item, boolean callOnCancel) {
+ mItemToSet = item;
+ mCallOnCancel = callOnCancel;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (!mCallOnCancel) {
+ mCalled = true;
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCalled) {
+ setCurrentItem(mItemToSet);
+ mCalled = true;
+ }
+ }
+ }
+}
diff --git a/src/com/android/launcher3/keyboard/KeyboardDragAndDropView.java b/src/com/android/launcher3/keyboard/KeyboardDragAndDropView.java
new file mode 100644
index 0000000..a6c897f
--- /dev/null
+++ b/src/com/android/launcher3/keyboard/KeyboardDragAndDropView.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2021 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.keyboard;
+
+import static android.app.Activity.DEFAULT_KEYS_SEARCH_LOCAL;
+
+import static com.android.launcher3.LauncherState.SPRING_LOADED;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint.Style;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewParent;
+import android.widget.TextView;
+
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.PagedView;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.folder.Folder;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.statemanager.StateManager.StateListener;
+import com.android.launcher3.touch.ItemLongClickListener;
+import com.android.launcher3.util.Themes;
+
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.function.ToIntBiFunction;
+import java.util.function.ToIntFunction;
+
+/**
+ * A floating view to allow keyboard navigation across virtual nodes
+ */
+public class KeyboardDragAndDropView extends AbstractFloatingView
+ implements Insettable, StateListener<LauncherState> {
+
+ private static final long MINOR_AXIS_WEIGHT = 13;
+
+ private final ArrayList<Integer> mIntList = new ArrayList<>();
+ private final ArrayList<DragAndDropAccessibilityDelegate> mDelegates = new ArrayList<>();
+ private final ArrayList<VirtualNodeInfo> mNodes = new ArrayList<>();
+
+ private final Rect mTempRect = new Rect();
+ private final Rect mTempRect2 = new Rect();
+ private final AccessibilityNodeInfoCompat mTempNodeInfo = AccessibilityNodeInfoCompat.obtain();
+
+ private final RectFocusIndicator mFocusIndicator;
+
+ private final Launcher mLauncher;
+ private VirtualNodeInfo mCurrentSelection;
+
+
+ public KeyboardDragAndDropView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public KeyboardDragAndDropView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = Launcher.getLauncher(context);
+ mFocusIndicator = new RectFocusIndicator(this);
+ setWillNotDraw(false);
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ mLauncher.getDragLayer().removeView(this);
+ mLauncher.getStateManager().removeStateListener(this);
+ mLauncher.setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
+ mIsOpen = false;
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_DRAG_DROP_POPUP) != 0;
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ // Consume all touch
+ return true;
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ setPadding(insets.left, insets.top, insets.right, insets.bottom);
+ }
+
+ @Override
+ public void onStateTransitionStart(LauncherState toState) {
+ if (toState != SPRING_LOADED) {
+ close(false);
+ }
+ }
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ if (mCurrentSelection != null) {
+ setCurrentSelection(mCurrentSelection);
+ }
+ }
+
+ private void setCurrentSelection(VirtualNodeInfo nodeInfo) {
+ mCurrentSelection = nodeInfo;
+ ((TextView) findViewById(R.id.label))
+ .setText(nodeInfo.populate(mTempNodeInfo).getContentDescription());
+
+ Rect bounds = new Rect();
+ mTempNodeInfo.getBoundsInParent(bounds);
+ View host = nodeInfo.delegate.getHost();
+ ViewParent parent = host.getParent();
+ if (parent instanceof PagedView) {
+ PagedView pv = (PagedView) parent;
+ int pageIndex = pv.indexOfChild(host);
+
+ pv.setCurrentPage(pageIndex);
+ bounds.offset(pv.getScrollX() - pv.getScrollForPage(pageIndex), 0);
+ }
+ float[] pos = new float[] {bounds.left, bounds.top, bounds.right, bounds.bottom};
+ Utilities.getDescendantCoordRelativeToAncestor(host, mLauncher.getDragLayer(), pos, true);
+
+ new RectF(pos[0], pos[1], pos[2], pos[3]).roundOut(bounds);
+ mFocusIndicator.changeFocus(bounds, true);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ mFocusIndicator.draw(canvas);
+ }
+
+ @Override
+ public boolean dispatchUnhandledMove(View focused, int direction) {
+ VirtualNodeInfo nodeInfo = getNextSelection(direction);
+ if (nodeInfo == null) {
+ return false;
+ }
+ setCurrentSelection(nodeInfo);
+ return true;
+ }
+
+ /**
+ * Focus finding logic:
+ * Collect all virtual nodes in reading order (used for forward and backwards).
+ * Then find the closest view by comparing the distances spatially. Since it is a move
+ * operation. consider all cell sizes to be approximately of the same size.
+ */
+ private VirtualNodeInfo getNextSelection(int direction) {
+ // Collect all virtual nodes
+ mDelegates.clear();
+ mNodes.clear();
+
+ Folder openFolder = Folder.getOpen(mLauncher);
+ PagedView pv = openFolder == null ? mLauncher.getWorkspace() : openFolder.getContent();
+ int count = pv.getPageCount();
+ for (int i = 0; i < count; i++) {
+ mDelegates.add(((CellLayout) pv.getChildAt(i)).getDragAndDropAccessibilityDelegate());
+ }
+ if (openFolder == null) {
+ mDelegates.add(pv.getNextPage() + 1,
+ mLauncher.getHotseat().getDragAndDropAccessibilityDelegate());
+ }
+ mDelegates.forEach(delegate -> {
+ mIntList.clear();
+ delegate.getVisibleVirtualViews(mIntList);
+ mIntList.forEach(id -> mNodes.add(new VirtualNodeInfo(delegate, id)));
+ });
+
+ if (mNodes.isEmpty()) {
+ return null;
+ }
+ int index = mNodes.indexOf(mCurrentSelection);
+ if (mCurrentSelection == null || index < 0) {
+ return null;
+ }
+ int totalNodes = mNodes.size();
+
+ final ToIntBiFunction<Rect, Rect> majorAxis;
+ final ToIntFunction<Rect> minorAxis;
+
+ switch (direction) {
+ case View.FOCUS_RIGHT:
+ majorAxis = (source, dest) -> dest.left - source.left;
+ minorAxis = Rect::centerY;
+ break;
+ case View.FOCUS_LEFT:
+ majorAxis = (source, dest) -> source.left - dest.left;
+ minorAxis = Rect::centerY;
+ break;
+ case View.FOCUS_UP:
+ majorAxis = (source, dest) -> source.top - dest.top;
+ minorAxis = Rect::centerX;
+ break;
+ case View.FOCUS_DOWN:
+ majorAxis = (source, dest) -> dest.top - source.top;
+ minorAxis = Rect::centerX;
+ break;
+ case View.FOCUS_FORWARD:
+ return mNodes.get((index + 1) % totalNodes);
+ case View.FOCUS_BACKWARD:
+ return mNodes.get((index + totalNodes - 1) % totalNodes);
+ default:
+ // Unknown direction
+ return null;
+ }
+ mCurrentSelection.populate(mTempNodeInfo).getBoundsInScreen(mTempRect);
+
+ float minWeight = Float.MAX_VALUE;
+ VirtualNodeInfo match = null;
+ for (int i = 0; i < totalNodes; i++) {
+ VirtualNodeInfo node = mNodes.get(i);
+ node.populate(mTempNodeInfo).getBoundsInScreen(mTempRect2);
+
+ int majorAxisWeight = majorAxis.applyAsInt(mTempRect, mTempRect2);
+ if (majorAxisWeight <= 0) {
+ continue;
+ }
+ int minorAxisWeight = minorAxis.applyAsInt(mTempRect2)
+ - minorAxis.applyAsInt(mTempRect);
+
+ float weight = majorAxisWeight * majorAxisWeight
+ + minorAxisWeight * minorAxisWeight * MINOR_AXIS_WEIGHT;
+ if (weight < minWeight) {
+ minWeight = weight;
+ match = node;
+ }
+ }
+ return match;
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_ENTER && mCurrentSelection != null) {
+ mCurrentSelection.delegate.onPerformActionForVirtualView(
+ mCurrentSelection.id, AccessibilityNodeInfoCompat.ACTION_CLICK, null);
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ /**
+ * Shows the keyboard drag popup for the provided view
+ */
+ public void showForIcon(View icon, ItemInfo item, DragOptions dragOptions) {
+ mIsOpen = true;
+ mLauncher.getDragLayer().addView(this);
+ mLauncher.getStateManager().addStateListener(this);
+
+ // Find current selection
+ CellLayout currentParent = (CellLayout) icon.getParent().getParent();
+ float[] iconPos = new float[] {currentParent.getCellWidth() / 2,
+ currentParent.getCellHeight() / 2};
+ Utilities.getDescendantCoordRelativeToAncestor(icon, currentParent, iconPos, false);
+
+ ItemLongClickListener.beginDrag(icon, mLauncher, item, dragOptions);
+
+ DragAndDropAccessibilityDelegate dndDelegate =
+ currentParent.getDragAndDropAccessibilityDelegate();
+ setCurrentSelection(new VirtualNodeInfo(
+ dndDelegate, dndDelegate.getVirtualViewAt(iconPos[0], iconPos[1])));
+
+ mLauncher.setDefaultKeyMode(Activity.DEFAULT_KEYS_DISABLE);
+ requestFocus();
+ }
+
+ private static class VirtualNodeInfo {
+ public final DragAndDropAccessibilityDelegate delegate;
+ public final int id;
+
+ VirtualNodeInfo(DragAndDropAccessibilityDelegate delegate, int id) {
+ this.id = id;
+ this.delegate = delegate;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof VirtualNodeInfo)) {
+ return false;
+ }
+ VirtualNodeInfo that = (VirtualNodeInfo) o;
+ return id == that.id && delegate.equals(that.delegate);
+ }
+
+ public AccessibilityNodeInfoCompat populate(AccessibilityNodeInfoCompat nodeInfo) {
+ delegate.onPopulateNodeForVirtualView(id, nodeInfo);
+ return nodeInfo;
+ }
+
+ public void getBounds(AccessibilityNodeInfoCompat nodeInfo, Rect out) {
+ delegate.onPopulateNodeForVirtualView(id, nodeInfo);
+ nodeInfo.getBoundsInScreen(out);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, delegate);
+ }
+ }
+
+ private static class RectFocusIndicator extends ItemFocusIndicatorHelper<Rect> {
+
+ RectFocusIndicator(View container) {
+ super(container, Themes.getColorAccent(container.getContext()));
+ mPaint.setStrokeWidth(container.getResources()
+ .getDimension(R.dimen.keyboard_drag_stroke_width));
+ mPaint.setStyle(Style.STROKE);
+ }
+
+ @Override
+ public void viewToRect(Rect item, Rect outRect) {
+ outRect.set(item);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 2066cd3..0292d20 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -344,6 +344,12 @@
@UiEvent(doc = "Current grid size is changed to 2.")
LAUNCHER_GRID_SIZE_2(665),
+
+ @UiEvent(doc = "Launcher entered into AllApps state.")
+ LAUNCHER_ALLAPPS_ENTRY(692),
+
+ @UiEvent(doc = "Launcher exited from AllApps state.")
+ LAUNCHER_ALLAPPS_EXIT(693),
;
// ADD MORE
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 5464dd8..15f7730 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -455,12 +455,6 @@
}
@Override
- public boolean dispatchUnhandledMove(View focused, int direction) {
- // Consume the unhandled move if a container is open, to avoid switching pages underneath.
- return AbstractFloatingView.getTopOpenView(mActivity) != null;
- }
-
- @Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
View topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null) {