Merge "Create a new DragOptions for every drag operation" into sc-dev
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 6f36d45..641e108 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -63,6 +63,7 @@
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import java.util.List;
import java.util.stream.Stream;
/**
@@ -244,15 +245,12 @@
}
@Override
- protected StateHandler<LauncherState>[] createStateHandlers() {
- return new StateHandler[] {
- getAllAppsController(),
- getWorkspace(),
- getDepthController(),
- new RecentsViewStateController(this),
- new BackButtonAlphaHandler(this),
- getTaskbarStateHandler(),
- };
+ protected void collectStateHandlers(List<StateHandler> out) {
+ super.collectStateHandlers(out);
+ out.add(getDepthController());
+ out.add(new RecentsViewStateController(this));
+ out.add(new BackButtonAlphaHandler(this));
+ out.add(getTaskbarStateHandler());
}
public DepthController getDepthController() {
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index c4b6961..f14c5bf 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -16,6 +16,9 @@
package com.android.launcher3;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+
import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
@@ -80,6 +83,7 @@
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.SurfaceTransactionApplier;
+import com.android.systemui.shared.recents.IStartingWindowListener;
import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@@ -92,6 +96,8 @@
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import java.util.LinkedHashMap;
+
/**
* {@link LauncherAppTransitionManager} with Quickstep-specific app transitions for launching from
* home and/or all-apps. Not used for 3p launchers.
@@ -145,6 +151,8 @@
// Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down.
public static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f;
+ private static final int MAX_NUM_TASKS = 5;
+
protected final BaseQuickstepLauncher mLauncher;
private final DragLayer mDragLayer;
@@ -180,6 +188,9 @@
}
};
+ // Will never be larger than MAX_NUM_TASKS
+ private LinkedHashMap<Integer, Integer> mTypeForTaskId;
+
public QuickstepAppTransitionManagerImpl(Context context) {
mLauncher = Launcher.cast(Launcher.getLauncher(context));
mDragLayer = mLauncher.getDragLayer();
@@ -194,6 +205,23 @@
mMaxShadowRadius = res.getDimensionPixelSize(R.dimen.max_shadow_radius);
mLauncher.addOnDeviceProfileChangeListener(this);
+
+ if (supportsSSplashScreen()) {
+ mTypeForTaskId = new LinkedHashMap<Integer, Integer>(MAX_NUM_TASKS) {
+ @Override
+ protected boolean removeEldestEntry(Entry<Integer, Integer> entry) {
+ return size() > MAX_NUM_TASKS;
+ }
+ };
+
+ SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(
+ new IStartingWindowListener.Stub() {
+ @Override
+ public void onTaskLaunching(int taskId, int supportedType) {
+ mTypeForTaskId.put(taskId, supportedType);
+ }
+ });
+ }
}
@Override
@@ -336,6 +364,15 @@
return bounds;
}
+ private int getOpeningTaskId(RemoteAnimationTargetCompat[] appTargets) {
+ for (RemoteAnimationTargetCompat target : appTargets) {
+ if (target.mode == MODE_OPENING) {
+ return target.taskId;
+ }
+ }
+ return -1;
+ }
+
public void setRemoteAnimationProvider(final RemoteAnimationProvider animationProvider,
CancellationSignal cancellationSignal) {
mRemoteAnimationProvider = animationProvider;
@@ -471,8 +508,19 @@
int[] dragLayerBounds = new int[2];
mDragLayer.getLocationOnScreen(dragLayerBounds);
+ final boolean hasSplashScreen;
+ if (supportsSSplashScreen()) {
+ int taskId = getOpeningTaskId(appTargets);
+ int type = mTypeForTaskId.getOrDefault(taskId, STARTING_WINDOW_TYPE_NONE);
+ mTypeForTaskId.remove(taskId);
+ hasSplashScreen = type == STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ } else {
+ hasSplashScreen = false;
+ }
+
AnimOpenProperties prop = new AnimOpenProperties(mLauncher.getResources(), mDeviceProfile,
- windowTargetBounds, launcherIconBounds, v, dragLayerBounds[0], dragLayerBounds[1]);
+ windowTargetBounds, launcherIconBounds, v, dragLayerBounds[0], dragLayerBounds[1],
+ hasSplashScreen);
int left = (int) (prop.cropCenterXStart - prop.cropWidthStart / 2);
int top = (int) (prop.cropCenterYStart - prop.cropHeightStart / 2);
int right = (int) (left + prop.cropWidthStart);
@@ -562,7 +610,7 @@
Utilities.scaleRectFAboutCenter(tmpRectF, mIconScaleToFitScreen.value);
float windowTransX0 = tmpRectF.left - offsetX;
float windowTransY0 = tmpRectF.top - offsetY;
- if (ENABLE_SHELL_STARTING_SURFACE) {
+ if (hasSplashScreen) {
windowTransX0 -= crop.left * scale;
windowTransY0 -= crop.top * scale;
}
@@ -686,6 +734,14 @@
}
}
+ @Override
+ public void onActivityDestroyed() {
+ super.onActivityDestroyed();
+ unregisterRemoteAnimations();
+ unregisterRemoteTransitions();
+ SystemUiProxy.INSTANCE.getNoCreate().setStartingWindowListener(null);
+ }
+
/**
* Unregisters all remote animations.
*/
@@ -821,6 +877,12 @@
return closingAnimator;
}
+ private boolean supportsSSplashScreen() {
+ return hasControlRemoteAppTransitionPermission()
+ && Utilities.ATLEAST_S
+ && ENABLE_SHELL_STARTING_SURFACE;
+ }
+
private boolean hasControlRemoteAppTransitionPermission() {
return mLauncher.checkSelfPermission(CONTROL_REMOTE_APP_TRANSITION_PERMISSION)
== PackageManager.PERMISSION_GRANTED;
@@ -1030,7 +1092,8 @@
public final float iconAlphaStart;
AnimOpenProperties(Resources r, DeviceProfile dp, Rect windowTargetBounds,
- RectF launcherIconBounds, View view, int dragLayerLeft, int dragLayerTop) {
+ RectF launcherIconBounds, View view, int dragLayerLeft, int dragLayerTop,
+ boolean hasSplashScreen) {
// Scale the app icon to take up the entire screen. This simplifies the math when
// animating the app window position / scale.
float smallestSize = Math.min(windowTargetBounds.height(), windowTargetBounds.width());
@@ -1063,7 +1126,7 @@
alphaDuration = useUpwardAnimation ? APP_LAUNCH_ALPHA_DURATION
: APP_LAUNCH_ALPHA_DOWN_DURATION;
- if (ENABLE_SHELL_STARTING_SURFACE) {
+ if (hasSplashScreen) {
iconAlphaStart = 0;
// TOOD: Share value from shell when available.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
index 1e5e3e7..528f43e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
@@ -83,10 +83,15 @@
private ViewTreeObserverWrapper.OnComputeInsetsListener createTaskbarInsetsComputer() {
return insetsInfo -> {
- if (getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
- // We're invisible, let touches pass through us.
+ if (getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD
+ || mTaskbarView.isDraggingItem()) {
+ // We're invisible or dragging out of taskbar, let touches pass through us.
insetsInfo.touchableRegion.setEmpty();
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+ // TODO(b/182234653): Shouldn't need to do this, but for the meantime, reporting
+ // that visibleInsets is empty allows DragEvents through. Setting them as completely
+ // empty reverts to default behavior, so set 1 px instead.
+ insetsInfo.visibleInsets.set(0, 0, 0, 1);
} else {
// We're visible again, accept touches anywhere in our bounds.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
index 74a82ab..544835c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
@@ -85,6 +85,7 @@
// Contains all loaded Hotseat items.
private ItemInfo[] mLatestLoadedHotseatItems;
+ private @Nullable Animator mAnimator;
private boolean mIsAnimatingToLauncher;
public TaskbarController(BaseQuickstepLauncher launcher,
@@ -252,6 +253,10 @@
mTaskbarVisibilityController.cleanup();
mHotseatController.cleanup();
mRecentsController.cleanup();
+
+ if (mAnimator != null) {
+ mAnimator.end();
+ }
}
private void removeFromWindowManager() {
@@ -294,13 +299,21 @@
*/
public void onLauncherResumedOrPaused(boolean isResumed) {
long duration = QuickstepAppTransitionManagerImpl.CONTENT_ALPHA_DURATION;
- final Animator anim;
- if (isResumed) {
- anim = createAnimToLauncher(null, duration);
- } else {
- anim = createAnimToApp(duration);
+ if (mAnimator != null) {
+ mAnimator.cancel();
}
- anim.start();
+ if (isResumed) {
+ mAnimator = createAnimToLauncher(null, duration);
+ } else {
+ mAnimator = createAnimToApp(duration);
+ }
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimator = null;
+ }
+ });
+ mAnimator.start();
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java
index 082343e..b1bafdb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java
@@ -78,7 +78,10 @@
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
// Since the hotseat might be laid out vertically or horizontally, use whichever
// index is higher.
- hotseatItemInfos[Math.max(lp.cellX, lp.cellY)] = itemInfo;
+ int index = Math.max(lp.cellX, lp.cellY);
+ if (0 <= index && index < hotseatItemInfos.length) {
+ hotseatItemInfos[index] = itemInfo;
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 7f2af6b..e0c041e 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -934,7 +934,9 @@
duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
}
}
- Interpolator interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL;
+ Interpolator interpolator =
+ endTarget == RECENTS ? (mDp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()
+ ? ACCEL_DEACCEL : OVERSHOOT_1_2) : DEACCEL;
if (endTarget.isLauncher) {
mInputConsumerProxy.enable();
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 6a32dc4..a749f9a 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -273,7 +273,6 @@
Point size = display.realSize;
int rotation = display.rotation;
int touchHeight = mNavBarGesturalHeight;
- int largerGesturalHeight = mNavBarLargerGesturalHeight;
OrientationRectF orientationRectF =
new OrientationRectF(0, 0, size.x, size.y, rotation);
if (mMode == SysUINavigationMode.Mode.NO_BUTTON) {
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 8aa0842..1b2fd41 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -71,6 +71,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.List;
/**
* A recents activity that shows the recently launched tasks as swipable task cards.
@@ -317,8 +318,8 @@
}
@Override
- protected StateHandler<RecentsState>[] createStateHandlers() {
- return new StateHandler[] { new FallbackRecentsStateController(this) };
+ protected void collectStateHandlers(List<StateHandler> out) {
+ out.add(new FallbackRecentsStateController(this));
}
@Override
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 17822e6..aa1b8e1 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -180,6 +180,7 @@
boolean parallaxCenterAndAdjacentTask =
taskIndex != recentsView.getCurrentPage() && !(dp.isTablet
&& FeatureFlags.ENABLE_OVERVIEW_GRID.get());
+ float gridProgress = recentsView.getGridProgress();
float gridTranslationSecondary = recentsView.getGridTranslationSecondary(taskIndex);
int startScroll = recentsView.getScrollOffset(taskIndex);
@@ -197,7 +198,7 @@
tsv.setPreview(targets.apps[targets.apps.length - 1]);
tsv.fullScreenProgress.value = 0;
tsv.recentsViewScale.value = 1;
- tsv.gridProgress.value = 1;
+ tsv.gridProgress.value = gridProgress;
tsv.gridTranslationSecondary.value = gridTranslationSecondary;
tsv.setScroll(startScroll);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java
index b10bdde..cd69cf1 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java
@@ -21,14 +21,18 @@
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
+import static com.android.launcher3.ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE;
import static com.android.launcher3.Utilities.squaredHypot;
import android.content.Context;
+import android.graphics.Point;
import android.graphics.PointF;
import android.view.MotionEvent;
import com.android.launcher3.R;
+import com.android.launcher3.ResourceUtils;
import com.android.launcher3.Utilities;
+import com.android.launcher3.util.DisplayController;
import com.android.quickstep.InputConsumer;
import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.SystemUiProxy;
@@ -45,11 +49,15 @@
private static final int ANGLE_MIN = 30;
private final Context mContext;
+ private final DisplayController.DisplayHolder mDisplayHolder;
+ private final Point mDisplaySize;
private final RecentsAnimationDeviceState mDeviceState;
private final float mDragDistThreshold;
private final float mSquaredSlop;
+ private final int mNavBarSize;
+
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
@@ -60,10 +68,14 @@
InputConsumer delegate, InputMonitorCompat inputMonitor) {
super(delegate, inputMonitor);
mContext = context;
+ mDisplayHolder = DisplayController.getDefaultDisplay(mContext);
mDeviceState = deviceState;
mDragDistThreshold = context.getResources().getDimensionPixelSize(
R.dimen.gestures_onehanded_drag_threshold);
mSquaredSlop = Utilities.squaredTouchSlop(context);
+ mDisplaySize = mDisplayHolder.getInfo().realSize;
+ mNavBarSize = ResourceUtils.getNavbarSize(NAVBAR_BOTTOM_GESTURE_SIZE,
+ mContext.getResources());
}
@Override
@@ -96,7 +108,8 @@
mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y))
|| (mDeviceState.isOneHandedModeActive() && isValidExitAngle(
mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y))) {
- mPassedSlop = true;
+ // To avoid mis-trigger when motion not touch system gesture region.
+ mPassedSlop = isInSystemGestureRegion(mLastPos);
setActive(ev);
} else {
mState = STATE_DELEGATE_ACTIVE;
@@ -154,6 +167,11 @@
SystemUiProxy.INSTANCE.get(mContext).stopOneHandedMode();
}
+ private boolean isInSystemGestureRegion(PointF lastPos) {
+ final int navBarUpperBound = mDisplaySize.y - mNavBarSize;
+ return mDeviceState.isGesturalNavMode() && lastPos.y > navBarUpperBound;
+ }
+
private boolean isValidStartAngle(float deltaX, float deltaY) {
final float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
return angle > -(ANGLE_MAX) && angle < -(ANGLE_MIN);
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index a762cb7..66c24c8 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -31,6 +31,7 @@
import android.content.Context;
import android.util.Log;
+import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
@@ -55,6 +56,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LogConfig;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.SysUiStatsLog;
import java.util.Optional;
@@ -94,7 +96,7 @@
@Override
protected StatsLogger createLogger() {
- return new StatsCompatLogger();
+ return new StatsCompatLogger(mContext);
}
/**
@@ -136,6 +138,7 @@
private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo();
+ private Context mContext;
private ItemInfo mItemInfo = DEFAULT_ITEM_INFO;
private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
private OptionalInt mRank = OptionalInt.empty();
@@ -147,6 +150,10 @@
private Optional<String> mEditText = Optional.empty();
private SliceItem mSliceItem;
+ StatsCompatLogger(Context context) {
+ mContext = context;
+ }
+
@Override
public StatsLogger withItemInfo(ItemInfo itemInfo) {
if (mContainerInfo.isPresent()) {
@@ -220,7 +227,6 @@
if (!Utilities.ATLEAST_R) {
return;
}
-
LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
if (mSliceItem != null) {
@@ -256,6 +262,26 @@
}
}
+ @Override
+ public void sendToInteractionJankMonitor(EventEnum event, View view) {
+ if (!(event instanceof LauncherEvent)) {
+ return;
+ }
+ switch ((LauncherEvent) event) {
+ case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN:
+ InteractionJankMonitorWrapper.begin(
+ view,
+ InteractionJankMonitorWrapper.CUJ_ALL_APPS_SCROLL);
+ break;
+ case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END:
+ InteractionJankMonitorWrapper.end(
+ InteractionJankMonitorWrapper.CUJ_ALL_APPS_SCROLL);
+ break;
+ default:
+ break;
+ }
+ }
+
private LauncherAtom.ItemInfo applyOverwrites(LauncherAtom.ItemInfo atomInfo) {
LauncherAtom.ItemInfo.Builder itemInfoBuilder = atomInfo.toBuilder();
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index bdd0a36..efe1f75 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2773,6 +2773,15 @@
taskView.getGridTranslationY());
}
+ /**
+ * Returns the progress of forming a grid from carousel.
+ *
+ * @return A float from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
+ */
+ public float getGridProgress() {
+ return mGridProgress;
+ }
+
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
float degreesRotated;
if (navbarRotation == 0) {
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index 28a8c6f..6c18d7a 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -15,6 +15,7 @@
-->
<com.android.launcher3.widget.picker.WidgetsFullSheet
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
@@ -27,6 +28,14 @@
android:background="?android:attr/colorPrimary"
android:elevation="4dp">
+ <TextView
+ android:id="@+id/no_widgets_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:visibility="gone"
+ tools:text="No widgets available" />
+
<!-- Fast scroller popup -->
<TextView
android:id="@+id/fast_scroller_popup"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 44b5ee7..6fb72b1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -74,6 +74,9 @@
<!-- Search bar text shown in the popup view showing all available widgets installed on the
device. [CHAR_LIMIT=50] -->
<string name="widgets_full_sheet_search_bar_hint">Search</string>
+ <!-- Text shown when there is no widgets shown in the popup view showing all available widgets
+ installed on the device. [CHAR_LIMIT=none] -->
+ <string name="no_widgets_available">No widgets available</string>
<!-- All Apps -->
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 3b28d4d..9d6af9f 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -26,7 +26,6 @@
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.util.FocusLogic;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -544,7 +543,7 @@
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// Clear the frame and give focus to the widget host view when a directional key is pressed.
- if (FocusLogic.shouldConsume(keyCode)) {
+ if (shouldConsume(keyCode)) {
close(false);
mWidgetView.requestFocus();
return true;
@@ -667,4 +666,14 @@
return moveEnd ? out.size() - size() : size() - out.size();
}
}
+
+ /**
+ * Returns true only if this utility class handles the key code.
+ */
+ public static boolean shouldConsume(int keyCode) {
+ return (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
+ || keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN
+ || keyCode == KeyEvent.KEYCODE_MOVE_HOME || keyCode == KeyEvent.KEYCODE_MOVE_END
+ || keyCode == KeyEvent.KEYCODE_PAGE_UP || keyCode == KeyEvent.KEYCODE_PAGE_DOWN);
+ }
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index f2dd60e..2440854 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -472,7 +472,7 @@
final boolean isVerticalLayout = isVerticalBarLayout();
float invIconSizeDp = isVerticalLayout ? inv.landscapeIconSize : inv.iconSize;
iconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mInfo.metrics, scale));
- iconTextSizePx = pxFromDp(inv.iconTextSize, mInfo.metrics, scale);
+ iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, mInfo.metrics) * scale);
iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale);
setCellLayoutBorderSpacing((int) (cellLayoutBorderSpacingOriginalPx * scale));
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
deleted file mode 100644
index e5aecf7..0000000
--- a/src/com/android/launcher3/FocusHelper.java
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.SoundEffectConstants;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.folder.Folder;
-import com.android.launcher3.folder.FolderPagedView;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.util.FocusLogic;
-import com.android.launcher3.util.Thunk;
-
-/**
- * A keyboard listener we set on all the workspace icons.
- */
-class IconKeyEventListener implements View.OnKeyListener {
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- return FocusHelper.handleIconKeyEvent(v, keyCode, event);
- }
-}
-
-/**
- * A keyboard listener we set on all the hotseat buttons.
- */
-class HotseatIconKeyEventListener implements View.OnKeyListener {
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event);
- }
-}
-
-/**
- * A keyboard listener we set on full screen pages (e.g. custom content).
- */
-class FullscreenKeyEventListener implements View.OnKeyListener {
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
- || keyCode == KeyEvent.KEYCODE_PAGE_DOWN || keyCode == KeyEvent.KEYCODE_PAGE_UP) {
- // Handle the key event just like a workspace icon would in these cases. In this case,
- // it will basically act as if there is a single icon in the top left (so you could
- // think of the fullscreen page as a focusable fullscreen widget).
- return FocusHelper.handleIconKeyEvent(v, keyCode, event);
- }
- return false;
- }
-}
-
-/**
- * TODO: Reevaluate if this is still required
- */
-public class FocusHelper {
-
- private static final String TAG = "FocusHelper";
- private static final boolean DEBUG = false;
-
- /**
- * Handles key events in paged folder.
- */
- public static class PagedFolderKeyEventListener implements View.OnKeyListener {
-
- private final Folder mFolder;
-
- public PagedFolderKeyEventListener(Folder folder) {
- mFolder = folder;
- }
-
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent e) {
- boolean consume = FocusLogic.shouldConsume(keyCode);
- if (e.getAction() == KeyEvent.ACTION_UP) {
- return consume;
- }
- if (DEBUG) {
- Log.v(TAG, String.format("Handle ALL Folders keyevent=[%s].",
- KeyEvent.keyCodeToString(keyCode)));
- }
-
- if (!(v.getParent() instanceof ShortcutAndWidgetContainer)) {
- if (FeatureFlags.IS_STUDIO_BUILD) {
- throw new IllegalStateException("Parent of the focused item is not supported.");
- } else {
- return false;
- }
- }
-
- // Initialize variables.
- final ShortcutAndWidgetContainer itemContainer = (ShortcutAndWidgetContainer) v.getParent();
- final CellLayout cellLayout = (CellLayout) itemContainer.getParent();
-
- final int iconIndex = itemContainer.indexOfChild(v);
- final FolderPagedView pagedView = (FolderPagedView) cellLayout.getParent();
-
- final int pageIndex = pagedView.indexOfChild(cellLayout);
- final int pageCount = pagedView.getPageCount();
- final boolean isLayoutRtl = Utilities.isRtl(v.getResources());
-
- int[][] matrix = FocusLogic.createSparseMatrix(cellLayout);
- // Process focus.
- int newIconIndex = FocusLogic.handleKeyEvent(keyCode, matrix, iconIndex, pageIndex,
- pageCount, isLayoutRtl);
- if (newIconIndex == FocusLogic.NOOP) {
- handleNoopKey(keyCode, v);
- return consume;
- }
- ShortcutAndWidgetContainer newParent = null;
- View child = null;
-
- switch (newIconIndex) {
- case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
- case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
- newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1);
- if (newParent != null) {
- int row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
- pagedView.snapToPage(pageIndex - 1);
- child = newParent.getChildAt(
- ((newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN)
- ^ newParent.invertLayoutHorizontally()) ? 0 : matrix.length - 1,
- row);
- }
- break;
- case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
- newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1);
- if (newParent != null) {
- pagedView.snapToPage(pageIndex - 1);
- child = newParent.getChildAt(0, 0);
- }
- break;
- case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
- newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1);
- if (newParent != null) {
- pagedView.snapToPage(pageIndex - 1);
- child = newParent.getChildAt(matrix.length - 1, matrix[0].length - 1);
- }
- break;
- case FocusLogic.NEXT_PAGE_FIRST_ITEM:
- newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex + 1);
- if (newParent != null) {
- pagedView.snapToPage(pageIndex + 1);
- child = newParent.getChildAt(0, 0);
- }
- break;
- case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
- case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
- newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex + 1);
- if (newParent != null) {
- pagedView.snapToPage(pageIndex + 1);
- child = FocusLogic.getAdjacentChildInNextFolderPage(
- newParent, v, newIconIndex);
- }
- break;
- case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
- child = cellLayout.getChildAt(0, 0);
- break;
- case FocusLogic.CURRENT_PAGE_LAST_ITEM:
- child = pagedView.getLastItem();
- break;
- default: // Go to some item on the current page.
- child = itemContainer.getChildAt(newIconIndex);
- break;
- }
- if (child != null) {
- child.requestFocus();
- playSoundEffect(keyCode, v);
- } else {
- handleNoopKey(keyCode, v);
- }
- return consume;
- }
-
- public void handleNoopKey(int keyCode, View v) {
- if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- mFolder.mFolderName.requestFocus();
- playSoundEffect(keyCode, v);
- }
- }
- }
-
- /**
- * Handles key events in the workspace hotseat (bottom of the screen).
- * <p>Currently we don't special case for the phone UI in different orientations, even though
- * the hotseat is on the side in landscape mode. This is to ensure that accessibility
- * consistency is maintained across rotations.
- */
- static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e) {
- boolean consume = FocusLogic.shouldConsume(keyCode);
- if (e.getAction() == KeyEvent.ACTION_UP || !consume) {
- return consume;
- }
-
- final Launcher launcher = Launcher.getLauncher(v.getContext());
- final DeviceProfile profile = launcher.getDeviceProfile();
-
- if (DEBUG) {
- Log.v(TAG, String.format(
- "Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, isVertical=%s",
- KeyEvent.keyCodeToString(keyCode), profile.isVerticalBarLayout()));
- }
-
- // Initialize the variables.
- final Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace);
- final ShortcutAndWidgetContainer hotseatParent = (ShortcutAndWidgetContainer) v.getParent();
- final CellLayout hotseatLayout = (CellLayout) hotseatParent.getParent();
-
- final ItemInfo itemInfo = (ItemInfo) v.getTag();
- int pageIndex = workspace.getNextPage();
- int pageCount = workspace.getChildCount();
- int iconIndex = hotseatParent.indexOfChild(v);
- int iconRank = ((CellLayout.LayoutParams) hotseatLayout.getShortcutsAndWidgets()
- .getChildAt(iconIndex).getLayoutParams()).cellX;
-
- final CellLayout iconLayout = (CellLayout) workspace.getChildAt(pageIndex);
- if (iconLayout == null) {
- // This check is to guard against cases where key strokes rushes in when workspace
- // child creation/deletion is still in flux. (e.g., during drop or fling
- // animation.)
- return consume;
- }
- final ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
-
- ViewGroup parent = null;
- int[][] matrix = null;
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP &&
- !profile.isVerticalBarLayout()) {
- matrix = FocusLogic.createSparseMatrixWithHotseat(iconLayout, hotseatLayout, profile);
- iconIndex += iconParent.getChildCount();
- parent = iconParent;
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT &&
- profile.isVerticalBarLayout()) {
- matrix = FocusLogic.createSparseMatrixWithHotseat(iconLayout, hotseatLayout, profile);
- iconIndex += iconParent.getChildCount();
- parent = iconParent;
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
- profile.isVerticalBarLayout()) {
- keyCode = KeyEvent.KEYCODE_PAGE_DOWN;
- } else {
- // For other KEYCODE_DPAD_LEFT and KEYCODE_DPAD_RIGHT navigation, do not use the
- // matrix extended with hotseat.
- matrix = FocusLogic.createSparseMatrix(hotseatLayout);
- parent = hotseatParent;
- }
-
- // Process the focus.
- int newIconIndex = FocusLogic.handleKeyEvent(keyCode, matrix, iconIndex, pageIndex,
- pageCount, Utilities.isRtl(v.getResources()));
-
- View newIcon = null;
- switch (newIconIndex) {
- case FocusLogic.NEXT_PAGE_FIRST_ITEM:
- parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
- newIcon = parent.getChildAt(0);
- // TODO(hyunyoungs): handle cases where the child is not an icon but
- // a folder or a widget.
- workspace.snapToPage(pageIndex + 1);
- break;
- case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
- parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
- newIcon = parent.getChildAt(0);
- // TODO(hyunyoungs): handle cases where the child is not an icon but
- // a folder or a widget.
- workspace.snapToPage(pageIndex - 1);
- break;
- case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
- parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
- newIcon = parent.getChildAt(parent.getChildCount() - 1);
- // TODO(hyunyoungs): handle cases where the child is not an icon but
- // a folder or a widget.
- workspace.snapToPage(pageIndex - 1);
- break;
- case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
- case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
- // Go to the previous page but keep the focus on the same hotseat icon.
- workspace.snapToPage(pageIndex - 1);
- break;
- case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
- case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
- // Go to the next page but keep the focus on the same hotseat icon.
- workspace.snapToPage(pageIndex + 1);
- break;
- }
- if (parent == iconParent && newIconIndex >= iconParent.getChildCount()) {
- newIconIndex -= iconParent.getChildCount();
- }
- if (parent != null) {
- if (newIcon == null && newIconIndex >= 0) {
- newIcon = parent.getChildAt(newIconIndex);
- }
- if (newIcon != null) {
- newIcon.requestFocus();
- playSoundEffect(keyCode, v);
- }
- }
- return consume;
- }
-
- /**
- * Handles key events in a workspace containing icons.
- */
- static boolean handleIconKeyEvent(View v, int keyCode, KeyEvent e) {
- boolean consume = FocusLogic.shouldConsume(keyCode);
- if (e.getAction() == KeyEvent.ACTION_UP || !consume) {
- return consume;
- }
-
- Launcher launcher = Launcher.getLauncher(v.getContext());
- DeviceProfile profile = launcher.getDeviceProfile();
-
- if (DEBUG) {
- Log.v(TAG, String.format("Handle WORKSPACE ICONS keyevent=[%s] isVerticalBar=%s",
- KeyEvent.keyCodeToString(keyCode), profile.isVerticalBarLayout()));
- }
-
- // Initialize the variables.
- ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
- CellLayout iconLayout = (CellLayout) parent.getParent();
- final Workspace workspace = (Workspace) iconLayout.getParent();
- final ViewGroup dragLayer = (ViewGroup) workspace.getParent();
- final ViewGroup tabs = (ViewGroup) dragLayer.findViewById(R.id.drop_target_bar);
- final Hotseat hotseat = (Hotseat) dragLayer.findViewById(R.id.hotseat);
-
- final ItemInfo itemInfo = (ItemInfo) v.getTag();
- final int iconIndex = parent.indexOfChild(v);
- final int pageIndex = workspace.indexOfChild(iconLayout);
- final int pageCount = workspace.getChildCount();
-
- CellLayout hotseatLayout = (CellLayout) hotseat.getChildAt(0);
- ShortcutAndWidgetContainer hotseatParent = hotseatLayout.getShortcutsAndWidgets();
- int[][] matrix;
-
- // KEYCODE_DPAD_DOWN in portrait (KEYCODE_DPAD_RIGHT in landscape) is the only key allowed
- // to take a user to the hotseat. For other dpad navigation, do not use the matrix extended
- // with the hotseat.
- if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && !profile.isVerticalBarLayout()) {
- matrix = FocusLogic.createSparseMatrixWithHotseat(iconLayout, hotseatLayout, profile);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
- profile.isVerticalBarLayout()) {
- matrix = FocusLogic.createSparseMatrixWithHotseat(iconLayout, hotseatLayout, profile);
- } else {
- matrix = FocusLogic.createSparseMatrix(iconLayout);
- }
-
- // Process the focus.
- int newIconIndex = FocusLogic.handleKeyEvent(keyCode, matrix, iconIndex, pageIndex,
- pageCount, Utilities.isRtl(v.getResources()));
- boolean isRtl = Utilities.isRtl(v.getResources());
- View newIcon = null;
- CellLayout workspaceLayout = (CellLayout) workspace.getChildAt(pageIndex);
- switch (newIconIndex) {
- case FocusLogic.NOOP:
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
- newIcon = tabs;
- }
- break;
- case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
- case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
- int newPageIndex = pageIndex - 1;
- if (newIconIndex == FocusLogic.NEXT_PAGE_RIGHT_COLUMN) {
- newPageIndex = pageIndex + 1;
- }
- int row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
- parent = getCellLayoutChildrenForIndex(workspace, newPageIndex);
- if (parent != null) {
- iconLayout = (CellLayout) parent.getParent();
- matrix = FocusLogic.createSparseMatrixWithPivotColumn(iconLayout,
- iconLayout.getCountX(), row);
- newIconIndex = FocusLogic.handleKeyEvent(keyCode, matrix, FocusLogic.PIVOT,
- newPageIndex, pageCount, Utilities.isRtl(v.getResources()));
- if (newIconIndex == FocusLogic.NEXT_PAGE_FIRST_ITEM) {
- newIcon = handleNextPageFirstItem(workspace, hotseatLayout, pageIndex,
- isRtl);
- } else if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LAST_ITEM) {
- newIcon = handlePreviousPageLastItem(workspace, hotseatLayout, pageIndex,
- isRtl);
- } else {
- newIcon = parent.getChildAt(newIconIndex);
- }
- }
- break;
- case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
- workspaceLayout = (CellLayout) workspace.getChildAt(pageIndex - 1);
- newIcon = getFirstFocusableIconInReadingOrder(workspaceLayout, isRtl);
- if (newIcon == null) {
- // Check the hotseat if no focusable item was found on the workspace.
- newIcon = getFirstFocusableIconInReadingOrder(hotseatLayout, isRtl);
- workspace.snapToPage(pageIndex - 1);
- }
- break;
- case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
- newIcon = handlePreviousPageLastItem(workspace, hotseatLayout, pageIndex, isRtl);
- break;
- case FocusLogic.NEXT_PAGE_FIRST_ITEM:
- newIcon = handleNextPageFirstItem(workspace, hotseatLayout, pageIndex, isRtl);
- break;
- case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
- case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
- newPageIndex = pageIndex + 1;
- if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) {
- newPageIndex = pageIndex - 1;
- }
- row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
- parent = getCellLayoutChildrenForIndex(workspace, newPageIndex);
- if (parent != null) {
- iconLayout = (CellLayout) parent.getParent();
- matrix = FocusLogic.createSparseMatrixWithPivotColumn(iconLayout, -1, row);
- newIconIndex = FocusLogic.handleKeyEvent(keyCode, matrix, FocusLogic.PIVOT,
- newPageIndex, pageCount, Utilities.isRtl(v.getResources()));
- if (newIconIndex == FocusLogic.NEXT_PAGE_FIRST_ITEM) {
- newIcon = handleNextPageFirstItem(workspace, hotseatLayout, pageIndex,
- isRtl);
- } else if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LAST_ITEM) {
- newIcon = handlePreviousPageLastItem(workspace, hotseatLayout, pageIndex,
- isRtl);
- } else {
- newIcon = parent.getChildAt(newIconIndex);
- }
- }
- break;
- case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
- newIcon = getFirstFocusableIconInReadingOrder(workspaceLayout, isRtl);
- if (newIcon == null) {
- // Check the hotseat if no focusable item was found on the workspace.
- newIcon = getFirstFocusableIconInReadingOrder(hotseatLayout, isRtl);
- }
- break;
- case FocusLogic.CURRENT_PAGE_LAST_ITEM:
- newIcon = getFirstFocusableIconInReverseReadingOrder(workspaceLayout, isRtl);
- if (newIcon == null) {
- // Check the hotseat if no focusable item was found on the workspace.
- newIcon = getFirstFocusableIconInReverseReadingOrder(hotseatLayout, isRtl);
- }
- break;
- default:
- // current page, some item.
- if (0 <= newIconIndex && newIconIndex < parent.getChildCount()) {
- newIcon = parent.getChildAt(newIconIndex);
- } else if (parent.getChildCount() <= newIconIndex &&
- newIconIndex < parent.getChildCount() + hotseatParent.getChildCount()) {
- newIcon = hotseatParent.getChildAt(newIconIndex - parent.getChildCount());
- }
- break;
- }
- if (newIcon != null) {
- newIcon.requestFocus();
- playSoundEffect(keyCode, v);
- }
- return consume;
- }
-
- //
- // Helper methods.
- //
-
- /**
- * Private helper method to get the CellLayoutChildren given a CellLayout index.
- */
- @Thunk static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex(
- ViewGroup container, int i) {
- CellLayout parent = (CellLayout) container.getChildAt(i);
- return parent.getShortcutsAndWidgets();
- }
-
- /**
- * Helper method to be used for playing sound effects.
- */
- @Thunk static void playSoundEffect(int keyCode, View v) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_PAGE_DOWN:
- case KeyEvent.KEYCODE_MOVE_END:
- v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_PAGE_UP:
- case KeyEvent.KEYCODE_MOVE_HOME:
- v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
- break;
- default:
- break;
- }
- }
-
- private static View handlePreviousPageLastItem(Workspace workspace, CellLayout hotseatLayout,
- int pageIndex, boolean isRtl) {
- if (pageIndex - 1 < 0) {
- return null;
- }
- CellLayout workspaceLayout = (CellLayout) workspace.getChildAt(pageIndex - 1);
- View newIcon = getFirstFocusableIconInReverseReadingOrder(workspaceLayout, isRtl);
- if (newIcon == null) {
- // Check the hotseat if no focusable item was found on the workspace.
- newIcon = getFirstFocusableIconInReverseReadingOrder(hotseatLayout,isRtl);
- workspace.snapToPage(pageIndex - 1);
- }
- return newIcon;
- }
-
- private static View handleNextPageFirstItem(Workspace workspace, CellLayout hotseatLayout,
- int pageIndex, boolean isRtl) {
- if (pageIndex + 1 >= workspace.getPageCount()) {
- return null;
- }
- CellLayout workspaceLayout = (CellLayout) workspace.getChildAt(pageIndex + 1);
- View newIcon = getFirstFocusableIconInReadingOrder(workspaceLayout, isRtl);
- if (newIcon == null) {
- // Check the hotseat if no focusable item was found on the workspace.
- newIcon = getFirstFocusableIconInReadingOrder(hotseatLayout, isRtl);
- workspace.snapToPage(pageIndex + 1);
- }
- return newIcon;
- }
-
- private static View getFirstFocusableIconInReadingOrder(CellLayout cellLayout, boolean isRtl) {
- View icon;
- int countX = cellLayout.getCountX();
- for (int y = 0; y < cellLayout.getCountY(); y++) {
- int increment = isRtl ? -1 : 1;
- for (int x = isRtl ? countX - 1 : 0; 0 <= x && x < countX; x += increment) {
- if ((icon = cellLayout.getChildAt(x, y)) != null && icon.isFocusable()) {
- return icon;
- }
- }
- }
- return null;
- }
-
- private static View getFirstFocusableIconInReverseReadingOrder(CellLayout cellLayout,
- boolean isRtl) {
- View icon;
- int countX = cellLayout.getCountX();
- for (int y = cellLayout.getCountY() - 1; y >= 0; y--) {
- int increment = isRtl ? 1 : -1;
- for (int x = isRtl ? 0 : countX - 1; 0 <= x && x < countX; x += increment) {
- if ((icon = cellLayout.getChildAt(x, y)) != null && icon.isFocusable()) {
- return icon;
- }
- }
- }
- return null;
- }
-}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index fa63885..78e6f68 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1609,8 +1609,7 @@
LauncherAppState.getIDP(this).removeOnChangeListener(this);
mOverlayManager.onActivityDestroyed(this);
- mAppTransitionManager.unregisterRemoteAnimations();
- mAppTransitionManager.unregisterRemoteTransitions();
+ mAppTransitionManager.onActivityDestroyed();
mUserChangedCallbackCloseable.close();
mLiveSearchManager.stop();
}
@@ -2761,8 +2760,10 @@
return super.onKeyUp(keyCode, event);
}
- protected StateHandler<LauncherState>[] createStateHandlers() {
- return new StateHandler[] { getAllAppsController(), getWorkspace() };
+ @Override
+ protected void collectStateHandlers(List<StateHandler> out) {
+ out.add(getAllAppsController());
+ out.add(getWorkspace());
}
public TouchController[] createTouchControllers() {
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 0fa441a..d0bf577 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -62,6 +62,13 @@
}
/**
+ * Handles clean up when activity is destroyed.
+ */
+ public void onActivityDestroyed() {
+ // Do nothing
+ }
+
+ /**
* Unregisters all remote animations.
*/
public void unregisterRemoteAnimations() {
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index a05e036..bb175ea 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -290,8 +290,10 @@
public void setAppsPerRow(int appsPerRow) {
mAppsPerRow = appsPerRow;
int totalSpans = mAppsPerRow;
- for (int itemPerRow : mSearchAdapterProvider.getSupportedItemsPerRow()) {
- totalSpans *= itemPerRow;
+ for (int itemPerRow : mSearchAdapterProvider.getSupportedItemsPerRowArray()) {
+ if (totalSpans % itemPerRow != 0) {
+ totalSpans *= itemPerRow;
+ }
}
mGridLayoutMgr.setSpanCount(totalSpans);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
deleted file mode 100644
index b34c8b8..0000000
--- a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright (C) 2020 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.annotation.TargetApi;
-import android.graphics.Insets;
-import android.os.Build;
-import android.util.Log;
-import android.view.View;
-import android.view.WindowInsets;
-import android.view.WindowInsetsAnimationControlListener;
-import android.view.WindowInsetsAnimationController;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.UiThreadHelper;
-
-/**
- * Handles IME over all apps to be synchronously transitioning along with the passed in
- * root inset.
- */
-public class AllAppsInsetTransitionController {
-
- private static final boolean DEBUG = true;
- private static final String TAG = "AllAppsInsetTransitionController";
- private static final Interpolator LINEAR = new LinearInterpolator();
-
- private WindowInsetsAnimationController mAnimationController;
- private WindowInsetsAnimationControlListener mCurrentRequest;
-
- private Runnable mSearchEduRunnable;
-
- private float mAllAppsHeight;
-
- private int mDownInsetBottom;
- private boolean mShownAtDown;
-
- private int mHiddenInsetBottom;
- private int mShownInsetBottom;
-
- private float mDown, mCurrent;
- private View mApps;
-
- /**
- *
- */
- public boolean showSearchEduIfNecessary() {
- if (mSearchEduRunnable == null) {
- return false;
- }
- mSearchEduRunnable.run();
- return true;
- }
-
- public void setSearchEduRunnable(Runnable eduRunnable) {
- mSearchEduRunnable = eduRunnable;
- }
-
- // Only purpose of these states is to keep track of fast fling transition
- enum State {
- RESET, DRAG_START_BOTTOM, DRAG_START_BOTTOM_IME_CANCELLED,
- FLING_END_TOP, FLING_END_TOP_IME_CANCELLED,
- DRAG_START_TOP, FLING_END_BOTTOM
- }
-
- private State mState;
-
- public AllAppsInsetTransitionController(float allAppsHeight, View appsView) {
- mAllAppsHeight = allAppsHeight;
- mApps = appsView;
- }
-
- public void show() {
- mApps.getWindowInsetsController().show(WindowInsets.Type.ime());
- }
-
- public void hide() {
- if (!Utilities.ATLEAST_R) return;
-
- WindowInsets insets = mApps.getRootWindowInsets();
- if (insets == null) return;
-
- boolean imeVisible = insets.isVisible(WindowInsets.Type.ime());
-
- if (DEBUG) {
- Log.d(TAG, "\nhide imeVisible=" + imeVisible);
- }
- if (insets.isVisible(WindowInsets.Type.ime())) {
- mApps.getWindowInsetsController().hide(WindowInsets.Type.ime());
- }
- }
-
- /**
- * Initializes member variables and requests for the {@link WindowInsetsAnimationController}
- * object.
- *
- * @param progress value between 0..1
- */
- @TargetApi(Build.VERSION_CODES.R)
- public void onDragStart(float progress) {
- if (!Utilities.ATLEAST_R) return;
-
- // Until getRootWindowInsets().isVisible(...) method returns correct value,
- // only support InsetController based IME transition during swipe up and
- // NOT swipe down
- if (Float.compare(progress, 0f) == 0) return;
-
- setState(true, false, progress);
- mDown = progress * mAllAppsHeight;
-
- // Below two values are sometimes incorrect. Possibly a platform bug
- // mDownInsetBottom = mApps.getRootWindowInsets().getInsets(WindowInsets.Type.ime()).bottom;
- // mShownAtDown = mApps.getRootWindowInsets().isVisible(WindowInsets.Type.ime());
-
- if (DEBUG) {
- Log.d(TAG, "\nonDragStart progress=" + progress
- + " mDownInsets=" + mDownInsetBottom
- + " mShownAtDown=" + mShownAtDown);
- }
-
- mApps.getWindowInsetsController().controlWindowInsetsAnimation(
- WindowInsets.Type.ime(), -1 /* no predetermined duration */, LINEAR, null,
- mCurrentRequest = new WindowInsetsAnimationControlListener() {
-
- @Override
- public void onReady(WindowInsetsAnimationController controller, int types) {
- if (DEBUG) {
- Log.d(TAG, "Listener.onReady " + (mCurrentRequest == this));
- }
- if (controller != null) {
- if (mCurrentRequest == this && !handleFinishOnFling(controller)) {
- mAnimationController = controller;
- } else {
- controller.finish(false /* just don't show */);
- }
- }
- }
-
- @Override
- public void onFinished(WindowInsetsAnimationController controller) {
- // when screen lock happens, then this method get called
- if (DEBUG) {
- Log.d(TAG, "Listener.onFinished ctrl=" + controller
- + " mAnimationController=" + mAnimationController);
- }
- if (mAnimationController != null) {
- mAnimationController.finish(true);
- mAnimationController = null;
- }
- }
-
- @Override
- public void onCancelled(@Nullable WindowInsetsAnimationController controller) {
- if (DEBUG) {
- // Keep the verbose logging to chase down IME not showing up issue.
- // b/178904132
- Log.e(TAG, "Listener.onCancelled ctrl=" + controller
- + " mAnimationController=" + mAnimationController,
- new Exception());
- }
- if (mState == State.DRAG_START_BOTTOM) {
- mState = State.DRAG_START_BOTTOM_IME_CANCELLED;
- }
- mAnimationController = null;
- if (controller != null) {
- controller.finish(true);
- }
- }
- });
- }
-
- /**
- * If IME bounds after touch sequence finishes, call finish.
- */
- private boolean handleFinishOnFling(WindowInsetsAnimationController controller) {
- if (!Utilities.ATLEAST_R) return false;
-
- if (mState == State.FLING_END_TOP) {
- controller.finish(true);
- return true;
- } else if (mState == State.FLING_END_BOTTOM) {
- controller.finish(false);
- return true;
- }
- return false;
- }
-
- /**
- * Handles the translation using the progress.
- *
- * @param progress value between 0..1
- */
- @TargetApi(Build.VERSION_CODES.R)
- public void setProgress(float progress) {
- if (!Utilities.ATLEAST_R) return;
- // progress that equals to 0 or 1 is error prone. Do not use them.
- // Instead use onDragStart and onAnimationEnd
- if (mAnimationController == null || progress <= 0f || progress >= 1f) return;
-
- mCurrent = progress * mAllAppsHeight;
- mHiddenInsetBottom = mAnimationController.getHiddenStateInsets().bottom; // 0
- mShownInsetBottom = mAnimationController.getShownStateInsets().bottom; // 1155
-
- int shift = mShownAtDown ? 0 : (int) (mAllAppsHeight - mShownInsetBottom);
-
- int inset = (int) (mDownInsetBottom + (mDown - mCurrent) - shift);
-
- final int start = mShownAtDown ? mShownInsetBottom : mHiddenInsetBottom;
- final int end = mShownAtDown ? mHiddenInsetBottom : mShownInsetBottom;
- inset = Math.max(inset, mHiddenInsetBottom);
- inset = Math.min(inset, mShownInsetBottom);
- if (DEBUG && false) {
- Log.d(TAG, "updateInset mCurrent=" + mCurrent + " mDown="
- + mDown + " hidden=" + mHiddenInsetBottom
- + " shown=" + mShownInsetBottom
- + " mDownInsets.bottom=" + mDownInsetBottom + " inset=" + inset
- + " shift= " + shift);
- }
-
- mAnimationController.setInsetsAndAlpha(
- Insets.of(0, 0, 0, inset),
- 1f, (inset - start) / (float) (end - start));
- }
-
- /**
- * Report to the animation controller that we no longer plan to translate anymore.
- *
- * @param progress value between 0..1
- */
- @TargetApi(Build.VERSION_CODES.R)
- public void onAnimationEnd(float progress) {
- if (DEBUG) {
- Log.d(TAG, "onAnimationEnd progress=" + progress
- + " mAnimationController=" + mAnimationController);
- }
- if (mState == null) {
- // only called when launcher restarting.
- UiThreadHelper.hideKeyboardAsync(mApps.getContext(), mApps.getWindowToken());
- }
-
- setState(false, true, progress);
-
-
- if (mAnimationController == null) {
- if (mState == State.FLING_END_TOP_IME_CANCELLED) {
- mApps.getWindowInsetsController().show(WindowInsets.Type.ime());
- }
- return;
- }
-
- /* handle finish */
- if (mState == State.FLING_END_TOP) {
- mAnimationController.finish(true /* show */);
- } else {
- if (Float.compare(progress, 1f) == 0 /* bottom */) {
- mAnimationController.finish(false /* gone */);
- } else {
- mAnimationController.finish(mShownAtDown);
- }
- }
- /* handle finish */
-
- if (DEBUG) {
- Log.d(TAG, "endTranslation progress=" + progress
- + " mAnimationController=" + mAnimationController);
- }
- mAnimationController = null;
- mCurrentRequest = null;
- setState(false, false, progress);
- }
-
- private void setState(boolean start, boolean end, float progress) {
- State state = State.RESET;
- if (start && end) {
- throw new IllegalStateException("drag start and end cannot happen in same call");
- }
- if (start) {
- if (Float.compare(progress, 1f) == 0) {
- state = State.DRAG_START_BOTTOM;
- } else if (Float.compare(progress, 0f) == 0) {
- state = State.DRAG_START_TOP;
- }
- } else if (end) {
- if (Float.compare(progress, 1f) == 0 && mState == State.DRAG_START_TOP) {
- state = State.FLING_END_BOTTOM;
- } else if (Float.compare(progress, 0f) == 0) {
- if (mState == State.DRAG_START_BOTTOM) {
- state = State.FLING_END_TOP;
- } else if (mState == State.DRAG_START_BOTTOM_IME_CANCELLED) {
- state = State.FLING_END_TOP_IME_CANCELLED;
- }
- }
- }
- if (DEBUG) {
- Log.d(TAG, "setState " + mState + " -> " + state);
- }
- mState = state;
- }
-}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index ace9938..179cb77 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -19,6 +19,9 @@
import static android.view.View.MeasureSpec.UNSPECIFIED;
import static android.view.View.MeasureSpec.makeMeasureSpec;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END;
+
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -36,6 +39,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.views.RecyclerViewFastScroller;
import java.util.ArrayList;
@@ -176,6 +180,23 @@
}
@Override
+ public void onScrollStateChanged(int state) {
+ super.onScrollStateChanged(state);
+
+ StatsLogManager mgr = BaseDraggingActivity.fromContext(getContext()).getStatsLogManager();
+ switch (state) {
+ case SCROLL_STATE_DRAGGING:
+ mgr.logger().sendToInteractionJankMonitor(
+ LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN, this);
+ break;
+ case SCROLL_STATE_IDLE:
+ mgr.logger().sendToInteractionJankMonitor(
+ LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END, this);
+ break;
+ }
+ }
+
+ @Override
public boolean onInterceptTouchEvent(MotionEvent e) {
boolean result = super.onInterceptTouchEvent(e);
if (!result && e.getAction() == MotionEvent.ACTION_DOWN
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index a48e423..abf63dc 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -33,18 +33,15 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.content.SharedPreferences;
import android.util.FloatProperty;
import android.view.View;
import android.view.animation.Interpolator;
-import android.widget.EditText;
-
-import androidx.core.os.BuildCompat;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
@@ -63,8 +60,8 @@
* If release velocity < THRES1, snap according to either top or bottom depending on whether it's
* closer to top or closer to the page indicator.
*/
-public class AllAppsTransitionController implements StateHandler<LauncherState>,
- OnDeviceProfileChangeListener, SharedPreferences.OnSharedPreferenceChangeListener {
+public class AllAppsTransitionController
+ implements StateHandler<LauncherState>, OnDeviceProfileChangeListener {
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
@@ -81,7 +78,6 @@
};
private static final int APPS_VIEW_ALPHA_CHANNEL_INDEX = 0;
- private static final String PREF_KEY_SHOW_SEARCH_IME = "pref_search_show_ime";
private AllAppsContainerView mAppsView;
private ScrimView mScrimView;
@@ -99,8 +95,6 @@
private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent
private float mScrollRangeDelta = 0;
- private AllAppsInsetTransitionController mInsetController;
- private boolean mSearchImeEnabled;
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
@@ -109,19 +103,12 @@
mIsVerticalLayout = mLauncher.getDeviceProfile().isVerticalBarLayout();
mLauncher.addOnDeviceProfileChangeListener(this);
-
- onSharedPreferenceChanged(mLauncher.getSharedPrefs(), PREF_KEY_SHOW_SEARCH_IME);
- mLauncher.getSharedPrefs().registerOnSharedPreferenceChangeListener(this);
}
public float getShiftRange() {
return mShiftRange;
}
- public AllAppsInsetTransitionController getInsetController() {
- return mInsetController;
- }
-
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
mIsVerticalLayout = dp.isVerticalBarLayout();
@@ -146,14 +133,7 @@
mProgress = progress;
mScrimView.setProgress(progress);
- float shiftCurrent = progress * mShiftRange;
- mAppsView.setTranslationY(shiftCurrent);
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mSearchImeEnabled) {
- if (mInsetController == null) {
- setupInsetTransitionController();
- }
- mInsetController.setProgress(progress);
- }
+ mAppsView.setTranslationY(progress * mShiftRange);
}
public float getProgress() {
@@ -242,18 +222,13 @@
public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) {
mAppsView = appsView;
mScrimView = scrimView;
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && BuildCompat.isAtLeastR()) {
- setupInsetTransitionController();
+ if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && Utilities.ATLEAST_R) {
+ mLauncher.getSystemUiController().updateUiState(UI_STATE_ALLAPPS,
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
}
- private void setupInsetTransitionController() {
- mInsetController = new AllAppsInsetTransitionController(mShiftRange, mAppsView);
- mLauncher.getSystemUiController().updateUiState(UI_STATE_ALLAPPS,
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
- }
-
/**
* Updates the total scroll range but does not update the UI.
*/
@@ -274,23 +249,5 @@
if (Float.compare(mProgress, 1f) == 0) {
mAppsView.reset(false /* animate */);
}
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mSearchImeEnabled
- && BuildCompat.isAtLeastR()) {
- mInsetController.onAnimationEnd(mProgress);
- if (Float.compare(mProgress, 0f) == 0) {
- EditText editText = mAppsView.getSearchUiManager().getEditText();
- if (editText != null && !mInsetController.showSearchEduIfNecessary()) {
- editText.requestFocus();
- }
- }
- // TODO: should make the controller hide synchronously
- }
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
- if (s.equals(PREF_KEY_SHOW_SEARCH_IME)) {
- mSearchImeEnabled = sharedPreferences.getBoolean(s, true);
- }
}
}
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index 39410a7..0d42950 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -20,10 +20,10 @@
import android.graphics.Rect;
import android.view.KeyEvent;
import android.view.animation.Interpolator;
-import android.widget.EditText;
import androidx.annotation.Nullable;
+import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.anim.PropertySetter;
/**
@@ -75,7 +75,7 @@
* @return the edit text object
*/
@Nullable
- EditText getEditText();
+ ExtendedEditText getEditText();
/**
* sets highlight result's title
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 426fd0c..2261d51 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -32,7 +32,6 @@
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.animation.Interpolator;
-import android.widget.EditText;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
@@ -230,7 +229,7 @@
}
@Override
- public EditText getEditText() {
+ public ExtendedEditText getEditText() {
return this;
}
}
diff --git a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
index 6d491fd..fdacd3d 100644
--- a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
@@ -53,7 +53,7 @@
/**
* Returns supported item per row combinations supported
*/
- public int[] getSupportedItemsPerRow() {
+ public int[] getSupportedItemsPerRowArray() {
return new int[]{};
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index d554bb9..c5ffff9 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
import android.content.Context;
+import android.view.View;
import androidx.annotation.Nullable;
import androidx.slice.SliceItem;
@@ -407,6 +408,12 @@
@UiEvent(doc = "User switched to AllApps Work tab by tapping on it.")
LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB(722),
+
+ @UiEvent(doc = "All apps vertical fling started.")
+ LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN(724),
+
+ @UiEvent(doc = "All apps vertical fling ended.")
+ LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END(725)
;
// ADD MORE
@@ -525,6 +532,13 @@
*/
default void log(EventEnum event) {
}
+
+ /**
+ * Builds the final message and logs it to two different atoms, one for
+ * event tracking and the other for jank tracking.
+ */
+ default void sendToInteractionJankMonitor(EventEnum event, View v) {
+ }
}
/**
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index a18f340..2b51e97 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -26,14 +26,12 @@
import android.animation.AnimatorSet;
import android.os.Handler;
import android.os.Looper;
-import android.util.Log;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
-import com.android.launcher3.testing.TestProtocol;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -90,7 +88,9 @@
public StateHandler[] getStateHandlers() {
if (mStateHandlers == null) {
- mStateHandlers = mActivity.createStateHandlers();
+ ArrayList<StateHandler> handlers = new ArrayList<>();
+ mActivity.collectStateHandlers(handlers);
+ mStateHandlers = handlers.toArray(new StateHandler[handlers.size()]);
}
return mStateHandlers;
}
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
index 7abb653..8a35cb3 100644
--- a/src/com/android/launcher3/statemanager/StatefulActivity.java
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -30,6 +30,8 @@
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.views.BaseDragLayer;
+import java.util.List;
+
/**
* Abstract activity with state management
* @param <STATE_TYPE> Type of state object
@@ -46,7 +48,7 @@
/**
* Create handlers to control the property changes for this activity
*/
- protected abstract StateHandler<STATE_TYPE>[] createStateHandlers();
+ protected abstract void collectStateHandlers(List<StateHandler> out);
/**
* Returns true if the activity is in the provided state
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 6f1b2f9..516fc74 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -38,24 +38,19 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.os.SystemClock;
-import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
-import androidx.core.os.BuildCompat;
-
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.FlingBlockCheck;
import com.android.launcher3.util.TouchController;
@@ -265,13 +260,6 @@
}
mCanBlockFling = mFromState == NORMAL;
mFlingBlockCheck.unblockFling();
- // Must be called after all the animation controllers have been paused
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()
- && BuildCompat.isAtLeastR()
- && (mToState == ALL_APPS || mToState == NORMAL)) {
- mLauncher.getAllAppsController().getInsetController().onDragStart(
- mFromState == NORMAL ? 1f : 0f);
- }
}
@Override
diff --git a/src/com/android/launcher3/util/FocusLogic.java b/src/com/android/launcher3/util/FocusLogic.java
deleted file mode 100644
index 4f4cccd..0000000
--- a/src/com/android/launcher3/util/FocusLogic.java
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.util;
-
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.launcher3.CellLayout;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.ShortcutAndWidgetContainer;
-import com.android.launcher3.config.FeatureFlags;
-
-import java.util.Arrays;
-
-/**
- * Calculates the next item that a {@link KeyEvent} should change the focus to.
- *<p>
- * Note, this utility class calculates everything regards to icon index and its (x,y) coordinates.
- * Currently supports:
- * <ul>
- * <li> full matrix of cells that are 1x1
- * <li> sparse matrix of cells that are 1x1
- * [ 1][ ][ 2][ ]
- * [ ][ ][ 3][ ]
- * [ ][ 4][ ][ ]
- * [ ][ 5][ 6][ 7]
- * </ul>
- * *<p>
- * For testing, one can use a BT keyboard, or use following adb command.
- * ex. $ adb shell input keyevent 20 // KEYCODE_DPAD_LEFT
- */
-public class FocusLogic {
-
- private static final String TAG = "FocusLogic";
- private static final boolean DEBUG = false;
-
- /** Item and page index related constant used by {@link #handleKeyEvent}. */
- public static final int NOOP = -1;
-
- public static final int PREVIOUS_PAGE_RIGHT_COLUMN = -2;
- public static final int PREVIOUS_PAGE_FIRST_ITEM = -3;
- public static final int PREVIOUS_PAGE_LAST_ITEM = -4;
- public static final int PREVIOUS_PAGE_LEFT_COLUMN = -5;
-
- public static final int CURRENT_PAGE_FIRST_ITEM = -6;
- public static final int CURRENT_PAGE_LAST_ITEM = -7;
-
- public static final int NEXT_PAGE_FIRST_ITEM = -8;
- public static final int NEXT_PAGE_LEFT_COLUMN = -9;
- public static final int NEXT_PAGE_RIGHT_COLUMN = -10;
-
- public static final int ALL_APPS_COLUMN = -11;
-
- // Matrix related constant.
- public static final int EMPTY = -1;
- public static final int PIVOT = 100;
-
- /**
- * Returns true only if this utility class handles the key code.
- */
- public static boolean shouldConsume(int keyCode) {
- return (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
- keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
- keyCode == KeyEvent.KEYCODE_MOVE_HOME || keyCode == KeyEvent.KEYCODE_MOVE_END ||
- keyCode == KeyEvent.KEYCODE_PAGE_UP || keyCode == KeyEvent.KEYCODE_PAGE_DOWN);
- }
-
- public static int handleKeyEvent(int keyCode, int [][] map, int iconIdx, int pageIndex,
- int pageCount, boolean isRtl) {
-
- int cntX = map == null ? -1 : map.length;
- int cntY = map == null ? -1 : map[0].length;
-
- if (DEBUG) {
- Log.v(TAG, String.format(
- "handleKeyEvent START: cntX=%d, cntY=%d, iconIdx=%d, pageIdx=%d, pageCnt=%d",
- cntX, cntY, iconIdx, pageIndex, pageCount));
- }
-
- int newIndex = NOOP;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- newIndex = handleDpadHorizontal(iconIdx, cntX, cntY, map, -1 /*increment*/, isRtl);
- if (!isRtl && newIndex == NOOP && pageIndex > 0) {
- newIndex = PREVIOUS_PAGE_RIGHT_COLUMN;
- } else if (isRtl && newIndex == NOOP && pageIndex < pageCount - 1) {
- newIndex = NEXT_PAGE_RIGHT_COLUMN;
- }
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- newIndex = handleDpadHorizontal(iconIdx, cntX, cntY, map, 1 /*increment*/, isRtl);
- if (!isRtl && newIndex == NOOP && pageIndex < pageCount - 1) {
- newIndex = NEXT_PAGE_LEFT_COLUMN;
- } else if (isRtl && newIndex == NOOP && pageIndex > 0) {
- newIndex = PREVIOUS_PAGE_LEFT_COLUMN;
- }
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- newIndex = handleDpadVertical(iconIdx, cntX, cntY, map, 1 /*increment*/);
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- newIndex = handleDpadVertical(iconIdx, cntX, cntY, map, -1 /*increment*/);
- break;
- case KeyEvent.KEYCODE_MOVE_HOME:
- newIndex = handleMoveHome();
- break;
- case KeyEvent.KEYCODE_MOVE_END:
- newIndex = handleMoveEnd();
- break;
- case KeyEvent.KEYCODE_PAGE_DOWN:
- newIndex = handlePageDown(pageIndex, pageCount);
- break;
- case KeyEvent.KEYCODE_PAGE_UP:
- newIndex = handlePageUp(pageIndex);
- break;
- default:
- break;
- }
-
- if (DEBUG) {
- Log.v(TAG, String.format("handleKeyEvent FINISH: index [%d -> %s]",
- iconIdx, getStringIndex(newIndex)));
- }
- return newIndex;
- }
-
- /**
- * Returns a matrix of size (m x n) that has been initialized with {@link #EMPTY}.
- *
- * @param m number of columns in the matrix
- * @param n number of rows in the matrix
- */
- // TODO: get rid of dynamic matrix creation.
- private static int[][] createFullMatrix(int m, int n) {
- int[][] matrix = new int [m][n];
-
- for (int i=0; i < m;i++) {
- Arrays.fill(matrix[i], EMPTY);
- }
- return matrix;
- }
-
- /**
- * Returns a matrix of size same as the {@link CellLayout} dimension that is initialized with the
- * index of the child view.
- */
- // TODO: get rid of the dynamic matrix creation
- public static int[][] createSparseMatrix(CellLayout layout) {
- ShortcutAndWidgetContainer parent = layout.getShortcutsAndWidgets();
- final int m = layout.getCountX();
- final int n = layout.getCountY();
- final boolean invert = parent.invertLayoutHorizontally();
-
- int[][] matrix = createFullMatrix(m, n);
-
- // Iterate thru the children.
- for (int i = 0; i < parent.getChildCount(); i++ ) {
- View cell = parent.getChildAt(i);
- if (!cell.isFocusable()) {
- continue;
- }
- int cx = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellX;
- int cy = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellY;
- int x = invert ? (m - cx - 1) : cx;
- if (x < m && cy < n) { // check if view fits into matrix, else skip
- matrix[x][cy] = i;
- }
- }
- if (DEBUG) {
- printMatrix(matrix);
- }
- return matrix;
- }
-
- /**
- * Creates a sparse matrix that merges the icon and hotseat view group using the cell layout.
- * The size of the returning matrix is [icon column count x (icon + hotseat row count)]
- * in portrait orientation. In landscape, [(icon + hotseat) column count x (icon row count)]
- */
- // TODO: get rid of the dynamic matrix creation
- public static int[][] createSparseMatrixWithHotseat(
- CellLayout iconLayout, CellLayout hotseatLayout, DeviceProfile dp) {
-
- ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
- ViewGroup hotseatParent = hotseatLayout.getShortcutsAndWidgets();
-
- boolean isHotseatHorizontal = !dp.isVerticalBarLayout();
-
- int m, n;
- if (isHotseatHorizontal) {
- m = hotseatLayout.getCountX();
- n = iconLayout.getCountY() + hotseatLayout.getCountY();
- } else {
- m = iconLayout.getCountX() + hotseatLayout.getCountX();
- n = hotseatLayout.getCountY();
- }
- int[][] matrix = createFullMatrix(m, n);
- // Iterate through the children of the workspace.
- for (int i = 0; i < iconParent.getChildCount(); i++) {
- View cell = iconParent.getChildAt(i);
- if (!cell.isFocusable()) {
- continue;
- }
- int cx = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellX;
- int cy = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellY;
- matrix[cx][cy] = i;
- }
-
- // Iterate thru the children of the hotseat.
- for (int i = hotseatParent.getChildCount() - 1; i >= 0; i--) {
- if (isHotseatHorizontal) {
- int cx = ((CellLayout.LayoutParams)
- hotseatParent.getChildAt(i).getLayoutParams()).cellX;
- matrix[cx][iconLayout.getCountY()] = iconParent.getChildCount() + i;
- } else {
- int cy = ((CellLayout.LayoutParams)
- hotseatParent.getChildAt(i).getLayoutParams()).cellY;
- matrix[iconLayout.getCountX()][cy] = iconParent.getChildCount() + i;
- }
- }
- if (DEBUG) {
- printMatrix(matrix);
- }
- return matrix;
- }
-
- /**
- * Creates a sparse matrix that merges the icon of previous/next page and last column of
- * current page. When left key is triggered on the leftmost column, sparse matrix is created
- * that combines previous page matrix and an extra column on the right. Likewise, when right
- * key is triggered on the rightmost column, sparse matrix is created that combines this column
- * on the 0th column and the next page matrix.
- *
- * @param pivotX x coordinate of the focused item in the current page
- * @param pivotY y coordinate of the focused item in the current page
- */
- // TODO: get rid of the dynamic matrix creation
- public static int[][] createSparseMatrixWithPivotColumn(CellLayout iconLayout,
- int pivotX, int pivotY) {
-
- ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
-
- int[][] matrix = createFullMatrix(iconLayout.getCountX() + 1, iconLayout.getCountY());
-
- // Iterate thru the children of the top parent.
- for (int i = 0; i < iconParent.getChildCount(); i++) {
- View cell = iconParent.getChildAt(i);
- if (!cell.isFocusable()) {
- continue;
- }
- int cx = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellX;
- int cy = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellY;
- if (pivotX < 0) {
- matrix[cx - pivotX][cy] = i;
- } else {
- matrix[cx][cy] = i;
- }
- }
-
- if (pivotX < 0) {
- matrix[0][pivotY] = PIVOT;
- } else {
- matrix[pivotX][pivotY] = PIVOT;
- }
- if (DEBUG) {
- printMatrix(matrix);
- }
- return matrix;
- }
-
- //
- // key event handling methods.
- //
-
- /**
- * Calculates icon that has is closest to the horizontal axis in reference to the cur icon.
- *
- * Example of the check order for KEYCODE_DPAD_RIGHT:
- * [ ][ ][13][14][15]
- * [ ][ 6][ 8][10][12]
- * [ X][ 1][ 2][ 3][ 4]
- * [ ][ 5][ 7][ 9][11]
- */
- // TODO: add unit tests to verify all permutation.
- private static int handleDpadHorizontal(int iconIdx, int cntX, int cntY,
- int[][] matrix, int increment, boolean isRtl) {
- if(matrix == null) {
- throw new IllegalStateException("Dpad navigation requires a matrix.");
- }
- int newIconIndex = NOOP;
-
- int xPos = -1;
- int yPos = -1;
- // Figure out the location of the icon.
- for (int i = 0; i < cntX; i++) {
- for (int j = 0; j < cntY; j++) {
- if (matrix[i][j] == iconIdx) {
- xPos = i;
- yPos = j;
- }
- }
- }
- if (DEBUG) {
- Log.v(TAG, String.format("\thandleDpadHorizontal: \t[x, y]=[%d, %d] iconIndex=%d",
- xPos, yPos, iconIdx));
- }
-
- // Rule1: check first in the horizontal direction
- for (int x = xPos + increment; 0 <= x && x < cntX; x += increment) {
- if ((newIconIndex = inspectMatrix(x, yPos, cntX, cntY, matrix)) != NOOP
- && newIconIndex != ALL_APPS_COLUMN) {
- return newIconIndex;
- }
- }
-
- // Rule2: check (x1-n, yPos + increment), (x1-n, yPos - increment)
- // (x2-n, yPos + 2*increment), (x2-n, yPos - 2*increment)
- int nextYPos1;
- int nextYPos2;
- boolean haveCrossedAllAppsColumn1 = false;
- boolean haveCrossedAllAppsColumn2 = false;
- int x = -1;
- for (int coeff = 1; coeff < cntY; coeff++) {
- nextYPos1 = yPos + coeff * increment;
- nextYPos2 = yPos - coeff * increment;
- x = xPos + increment * coeff;
- if (inspectMatrix(x, nextYPos1, cntX, cntY, matrix) == ALL_APPS_COLUMN) {
- haveCrossedAllAppsColumn1 = true;
- }
- if (inspectMatrix(x, nextYPos2, cntX, cntY, matrix) == ALL_APPS_COLUMN) {
- haveCrossedAllAppsColumn2 = true;
- }
- for (; 0 <= x && x < cntX; x += increment) {
- int offset1 = haveCrossedAllAppsColumn1 && x < cntX - 1 ? increment : 0;
- newIconIndex = inspectMatrix(x, nextYPos1 + offset1, cntX, cntY, matrix);
- if (newIconIndex != NOOP) {
- return newIconIndex;
- }
- int offset2 = haveCrossedAllAppsColumn2 && x < cntX - 1 ? -increment : 0;
- newIconIndex = inspectMatrix(x, nextYPos2 + offset2, cntX, cntY, matrix);
- if (newIconIndex != NOOP) {
- return newIconIndex;
- }
- }
- }
-
- // Rule3: if switching between pages, do a brute-force search to find an item that was
- // missed by rules 1 and 2 (such as when going from a bottom right icon to top left)
- if (iconIdx == PIVOT) {
- if (isRtl) {
- return increment < 0 ? NEXT_PAGE_FIRST_ITEM : PREVIOUS_PAGE_LAST_ITEM;
- }
- return increment < 0 ? PREVIOUS_PAGE_LAST_ITEM : NEXT_PAGE_FIRST_ITEM;
- }
- return newIconIndex;
- }
-
- /**
- * Calculates icon that is closest to the vertical axis in reference to the current icon.
- *
- * Example of the check order for KEYCODE_DPAD_DOWN:
- * [ ][ ][ ][ X][ ][ ][ ]
- * [ ][ ][ 5][ 1][ 4][ ][ ]
- * [ ][10][ 7][ 2][ 6][ 9][ ]
- * [14][12][ 9][ 3][ 8][11][13]
- */
- // TODO: add unit tests to verify all permutation.
- private static int handleDpadVertical(int iconIndex, int cntX, int cntY,
- int [][] matrix, int increment) {
- int newIconIndex = NOOP;
- if(matrix == null) {
- throw new IllegalStateException("Dpad navigation requires a matrix.");
- }
-
- int xPos = -1;
- int yPos = -1;
- // Figure out the location of the icon.
- for (int i = 0; i< cntX; i++) {
- for (int j = 0; j < cntY; j++) {
- if (matrix[i][j] == iconIndex) {
- xPos = i;
- yPos = j;
- }
- }
- }
-
- if (DEBUG) {
- Log.v(TAG, String.format("\thandleDpadVertical: \t[x, y]=[%d, %d] iconIndex=%d",
- xPos, yPos, iconIndex));
- }
-
- // Rule1: check first in the dpad direction
- for (int y = yPos + increment; 0 <= y && y <cntY && 0 <= y; y += increment) {
- if ((newIconIndex = inspectMatrix(xPos, y, cntX, cntY, matrix)) != NOOP
- && newIconIndex != ALL_APPS_COLUMN) {
- return newIconIndex;
- }
- }
-
- // Rule2: check (xPos + increment, y_(1-n)), (xPos - increment, y_(1-n))
- // (xPos + 2*increment, y_(2-n))), (xPos - 2*increment, y_(2-n))
- int nextXPos1;
- int nextXPos2;
- boolean haveCrossedAllAppsColumn1 = false;
- boolean haveCrossedAllAppsColumn2 = false;
- int y = -1;
- for (int coeff = 1; coeff < cntX; coeff++) {
- nextXPos1 = xPos + coeff * increment;
- nextXPos2 = xPos - coeff * increment;
- y = yPos + increment * coeff;
- if (inspectMatrix(nextXPos1, y, cntX, cntY, matrix) == ALL_APPS_COLUMN) {
- haveCrossedAllAppsColumn1 = true;
- }
- if (inspectMatrix(nextXPos2, y, cntX, cntY, matrix) == ALL_APPS_COLUMN) {
- haveCrossedAllAppsColumn2 = true;
- }
- for (; 0 <= y && y < cntY; y = y + increment) {
- int offset1 = haveCrossedAllAppsColumn1 && y < cntY - 1 ? increment : 0;
- newIconIndex = inspectMatrix(nextXPos1 + offset1, y, cntX, cntY, matrix);
- if (newIconIndex != NOOP) {
- return newIconIndex;
- }
- int offset2 = haveCrossedAllAppsColumn2 && y < cntY - 1 ? -increment : 0;
- newIconIndex = inspectMatrix(nextXPos2 + offset2, y, cntX, cntY, matrix);
- if (newIconIndex != NOOP) {
- return newIconIndex;
- }
- }
- }
- return newIconIndex;
- }
-
- private static int handleMoveHome() {
- return CURRENT_PAGE_FIRST_ITEM;
- }
-
- private static int handleMoveEnd() {
- return CURRENT_PAGE_LAST_ITEM;
- }
-
- private static int handlePageDown(int pageIndex, int pageCount) {
- if (pageIndex < pageCount -1) {
- return NEXT_PAGE_FIRST_ITEM;
- }
- return CURRENT_PAGE_LAST_ITEM;
- }
-
- private static int handlePageUp(int pageIndex) {
- if (pageIndex > 0) {
- return PREVIOUS_PAGE_FIRST_ITEM;
- } else {
- return CURRENT_PAGE_FIRST_ITEM;
- }
- }
-
- //
- // Helper methods.
- //
-
- private static boolean isValid(int xPos, int yPos, int countX, int countY) {
- return (0 <= xPos && xPos < countX && 0 <= yPos && yPos < countY);
- }
-
- private static int inspectMatrix(int x, int y, int cntX, int cntY, int[][] matrix) {
- int newIconIndex = NOOP;
- if (isValid(x, y, cntX, cntY)) {
- if (matrix[x][y] != -1) {
- newIconIndex = matrix[x][y];
- if (DEBUG) {
- Log.v(TAG, String.format("\t\tinspect: \t[x, y]=[%d, %d] %d",
- x, y, matrix[x][y]));
- }
- return newIconIndex;
- }
- }
- return newIconIndex;
- }
-
- /**
- * Only used for debugging.
- */
- private static String getStringIndex(int index) {
- switch(index) {
- case NOOP: return "NOOP";
- case PREVIOUS_PAGE_FIRST_ITEM: return "PREVIOUS_PAGE_FIRST";
- case PREVIOUS_PAGE_LAST_ITEM: return "PREVIOUS_PAGE_LAST";
- case PREVIOUS_PAGE_RIGHT_COLUMN:return "PREVIOUS_PAGE_RIGHT_COLUMN";
- case CURRENT_PAGE_FIRST_ITEM: return "CURRENT_PAGE_FIRST";
- case CURRENT_PAGE_LAST_ITEM: return "CURRENT_PAGE_LAST";
- case NEXT_PAGE_FIRST_ITEM: return "NEXT_PAGE_FIRST";
- case NEXT_PAGE_LEFT_COLUMN: return "NEXT_PAGE_LEFT_COLUMN";
- case ALL_APPS_COLUMN: return "ALL_APPS_COLUMN";
- default:
- return Integer.toString(index);
- }
- }
-
- /**
- * Only used for debugging.
- */
- private static void printMatrix(int[][] matrix) {
- Log.v(TAG, "\tprintMap:");
- int m = matrix.length;
- int n = matrix[0].length;
-
- for (int j=0; j < n; j++) {
- String colY = "\t\t";
- for (int i=0; i < m; i++) {
- colY += String.format("%3d",matrix[i][j]);
- }
- Log.v(TAG, colY);
- }
- }
-
- /**
- * @param edgeColumn the column of the new icon. either {@link #NEXT_PAGE_LEFT_COLUMN} or
- * {@link #NEXT_PAGE_RIGHT_COLUMN}
- * @return the view adjacent to {@param oldView} in the {@param nextPage} of the folder.
- */
- public static View getAdjacentChildInNextFolderPage(
- ShortcutAndWidgetContainer nextPage, View oldView, int edgeColumn) {
- final int newRow = ((CellLayout.LayoutParams) oldView.getLayoutParams()).cellY;
-
- int column = (edgeColumn == NEXT_PAGE_LEFT_COLUMN) ^ nextPage.invertLayoutHorizontally()
- ? 0 : (((CellLayout) nextPage.getParent()).getCountX() - 1);
-
- for (; column >= 0; column--) {
- for (int row = newRow; row >= 0; row--) {
- View newView = nextPage.getChildAt(column, row);
- if (newView != null) {
- return newView;
- }
- }
- }
- return null;
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index bf9b849..330175f 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -82,6 +82,7 @@
@Nullable private PersonalWorkPagedView mViewPager;
private int mInitialTabsHeight = 0;
private View mTabsView;
+ private TextView mNoWidgetsView;
private SearchAndRecommendationViewHolder mSearchAndRecommendationViewHolder;
private SearchAndRecommendationsScrollController mSearchAndRecommendationsScrollController;
@@ -141,19 +142,32 @@
mViewPager);
fastScroller.setOnFastScrollChangeListener(mSearchAndRecommendationsScrollController);
+ mNoWidgetsView = findViewById(R.id.no_widgets_text);
+
onWidgetsBound();
}
@Override
public void onActivePageChanged(int currentActivePage) {
- WidgetsRecyclerView currentRecyclerView =
- mAdapters.get(currentActivePage).mWidgetsRecyclerView;
+ AdapterHolder currentAdapterHolder = mAdapters.get(currentActivePage);
+ WidgetsRecyclerView currentRecyclerView = currentAdapterHolder.mWidgetsRecyclerView;
currentRecyclerView.bindFastScrollbar();
mSearchAndRecommendationsScrollController.setCurrentRecyclerView(currentRecyclerView);
+ updateNoWidgetsView(currentAdapterHolder);
+
reset();
}
+ private void updateNoWidgetsView(AdapterHolder adapterHolder) {
+ boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.getItemCount() > 0;
+ adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
+
+ // Always resets the text in case this is updated by search.
+ mNoWidgetsView.setText(R.string.no_widgets_available);
+ mNoWidgetsView.setVisibility(isWidgetAvailable ? GONE : VISIBLE);
+ }
+
private void reset() {
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.scrollToTop();
if (mHasWorkProfile) {
@@ -276,6 +290,8 @@
AdapterHolder primaryUserAdapterHolder = mAdapters.get(AdapterHolder.PRIMARY);
primaryUserAdapterHolder.setup(findViewById(R.id.primary_widgets_list_view));
primaryUserAdapterHolder.mWidgetsListAdapter.setWidgets(allWidgets);
+ updateNoWidgetsView(primaryUserAdapterHolder);
+
if (mHasWorkProfile) {
AdapterHolder workUserAdapterHolder = mAdapters.get(AdapterHolder.WORK);
workUserAdapterHolder.setup(findViewById(R.id.work_widgets_list_view));