Merge "More grid changes, closer to final specs." into sc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 56a2595..1fad72d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -49,7 +49,7 @@
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
diff --git a/go/AndroidManifest-launcher.xml b/go/AndroidManifest-launcher.xml
index 2223036..d2575b6 100644
--- a/go/AndroidManifest-launcher.xml
+++ b/go/AndroidManifest-launcher.xml
@@ -49,7 +49,7 @@
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|uiMode"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
diff --git a/quickstep/AndroidManifest-launcher.xml b/quickstep/AndroidManifest-launcher.xml
index 53910e3..7fe9b08 100644
--- a/quickstep/AndroidManifest-launcher.xml
+++ b/quickstep/AndroidManifest-launcher.xml
@@ -49,7 +49,7 @@
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 97f4a21..5e5cf73 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -71,7 +71,7 @@
android:stateNotNeeded="true"
android:theme="@style/LauncherTheme"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""/>
diff --git a/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java
index 010694b..bb1f6fc 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java
@@ -60,6 +60,14 @@
mListeners.add(r);
}
+ @Override
+ public void removeChangeListener(Runnable r) {
+ if (mListeners == null) {
+ return;
+ }
+ mListeners.remove(r);
+ }
+
private void registerDeviceConfigChangedListener(Context context) {
DeviceConfig.addOnPropertiesChangedListener(
NAMESPACE_LAUNCHER,
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index feeee50..5f8fc6d 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1494,7 +1494,9 @@
@Override
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (mRecentsAnimationTargets.hasTask(task.taskId)) {
+ if (mRecentsView.getRunningTaskIndex() != -1
+ && mRecentsView.getRunningTaskId() == task.taskId
+ && mRecentsAnimationTargets.hasTask(task.taskId)) {
launchOtherTaskInLiveTileMode(task.taskId, mRecentsAnimationTargets.apps);
}
ActivityManagerWrapper.getInstance().unregisterTaskStackListener(
@@ -1746,7 +1748,9 @@
if (mWindowTransitionController != null) {
mWindowTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
}
- if (mRecentsAnimationTargets != null) {
+ // No need to apply any transform if there is ongoing swipe-pip-to-home animator since
+ // that animator handles the leash solely.
+ if (mRecentsAnimationTargets != null && !mIsSwipingPipToHome) {
if (mRecentsViewScrollLinked) {
mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index e243715..e4c8b6f 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -37,18 +37,23 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Icon;
+import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.util.Log;
import android.view.Choreographer;
+import android.view.Display;
import android.view.InputEvent;
import android.view.MotionEvent;
+import android.view.Surface;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.BinderThread;
@@ -91,6 +96,7 @@
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.InputMonitorCompat;
@@ -121,6 +127,9 @@
*/
private static final int SYSTEM_ACTION_ID_ALL_APPS = 14;
+ public static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
+ SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
+
private int mBackGestureNotificationCounter = -1;
@Nullable
private OverscrollPlugin mOverscrollPlugin;
@@ -248,6 +257,8 @@
private InputMonitorCompat mInputMonitorCompat;
private InputEventReceiver mInputEventReceiver;
+ private DisplayManager mDisplayManager;
+
@Override
public void onCreate() {
super.onCreate();
@@ -261,6 +272,7 @@
mDeviceState.addOneHandedModeChangedCallback(this::onOneHandedModeOverlayChanged);
mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
ProtoTracer.INSTANCE.get(this).add(this);
+ mDisplayManager = getSystemService(DisplayManager.class);
sConnected = true;
}
@@ -426,6 +438,15 @@
return;
}
MotionEvent event = (MotionEvent) ev;
+ if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
+ final Display display = mDisplayManager.getDisplay(mDeviceState.getDisplayId());
+ int rotation = display.getRotation();
+ Point sz = new Point();
+ display.getRealSize(sz);
+ if (rotation != Surface.ROTATION_0) {
+ event.transform(InputChannelCompat.createRotationMatrix(rotation, sz.x, sz.y));
+ }
+ }
TestLogging.recordMotionEvent(
TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index f2f9fb7..5baf518 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -38,10 +38,12 @@
import android.content.ContextWrapper;
import android.content.Intent;
import android.graphics.PointF;
+import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
+import android.view.Display;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
@@ -64,6 +66,7 @@
import com.android.quickstep.RotationTouchHelper;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.TaskUtils;
+import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.CachedEventDispatcher;
import com.android.quickstep.util.MotionPauseDetector;
@@ -113,6 +116,8 @@
private final PointF mLastPos = new PointF();
private int mActivePointerId = INVALID_POINTER_ID;
+ private int mLastRotation = -1;
+
// Distance after which we start dragging the window.
private final float mTouchSlop;
@@ -130,6 +135,8 @@
// Might be displacement in X or Y, depending on the direction we are swiping from the nav bar.
private float mStartDisplacement;
+ private final DisplayManager mDisplayManager;
+
private Handler mMainThreadHandler;
private Runnable mCancelRecentsAnimationRunnable = () -> {
ActivityManagerWrapper.getInstance().cancelRecentsAnimation(
@@ -172,6 +179,7 @@
mPassedPilferInputSlop = mPassedWindowMoveSlop = continuingPreviousGesture;
mDisableHorizontalSwipe = !mPassedPilferInputSlop && disableHorizontalSwipe;
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
+ mDisplayManager = getSystemService(DisplayManager.class);
}
@Override
@@ -197,6 +205,17 @@
return;
}
+ if (TouchInteractionService.ENABLE_PER_WINDOW_INPUT_ROTATION) {
+ final Display display = mDisplayManager.getDisplay(mDeviceState.getDisplayId());
+ final int rotation = display.getRotation();
+ if (rotation != mLastRotation) {
+ // If rotation changes, reset tracking to avoid degenerate velocities.
+ mLastPos.set(ev.getX(), ev.getY());
+ mVelocityTracker.clear();
+ mLastRotation = rotation;
+ }
+ }
+
// Proxy events to recents view
if (mPassedWindowMoveSlop && mInteractionHandler != null
&& !mRecentsViewDispatcher.hasConsumer()) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 248fa46..b72e05c 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1106,6 +1106,10 @@
}
}
+ public int getRunningTaskId() {
+ return mRunningTaskId;
+ }
+
public @Nullable TaskView getRunningTaskView() {
return getTaskView(mRunningTaskId);
}
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 35383d2..67840d1 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -200,8 +200,8 @@
() -> launcher.getNavigationModel() == expectedMode, WAIT_TIME_MS, launcher);
Wait.atMost(() -> "Switching nav mode: "
- + launcher.getNavigationModeMismatchError(),
- () -> launcher.getNavigationModeMismatchError() == null,
+ + launcher.getNavigationModeMismatchError(false),
+ () -> launcher.getNavigationModeMismatchError(false) == null,
WAIT_TIME_MS, launcher);
AbstractLauncherUiTest.checkDetectedLeaks(launcher);
return true;
diff --git a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
index 72116eb..4ca1f59 100644
--- a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
+++ b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
@@ -49,7 +49,6 @@
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.Until;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.tapl.Background;
@@ -58,6 +57,7 @@
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.launcher3.ui.TestViewHelpers;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.Before;
diff --git a/res/drawable/bg_widgets_searchbox.xml b/res/drawable/bg_widgets_searchbox.xml
new file mode 100644
index 0000000..81dd2aa
--- /dev/null
+++ b/res/drawable/bg_widgets_searchbox.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <solid android:color="#FFFFF7" />
+ <corners android:radius="24dp" />
+</shape>
\ No newline at end of file
diff --git a/res/layout/live_preview_widget_cell.xml b/res/layout/live_preview_widget_cell.xml
index 7a42d19..1e1ce6e 100644
--- a/res/layout/live_preview_widget_cell.xml
+++ b/res/layout/live_preview_widget_cell.xml
@@ -15,14 +15,16 @@
-->
<com.android.launcher3.dragndrop.LivePreviewWidgetCell
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:paddingHorizontal="@dimen/widget_cell_horizontal_padding"
+ android:paddingVertical="@dimen/widget_cell_vertical_padding"
android:layout_weight="1"
android:orientation="vertical"
android:focusable="true"
android:background="?android:attr/colorPrimaryDark"
android:gravity="center_horizontal">
- <include layout="@layout/widget_cell_content" />
+ <include layout="@layout/widget_cell_content" />
</com.android.launcher3.dragndrop.LivePreviewWidgetCell>
\ No newline at end of file
diff --git a/res/layout/personal_work_tabs.xml b/res/layout/personal_work_tabs.xml
index 8f29997..5fb5bcb 100644
--- a/res/layout/personal_work_tabs.xml
+++ b/res/layout/personal_work_tabs.xml
@@ -23,6 +23,7 @@
android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
android:orientation="horizontal"
+ android:elevation="2dp"
style="@style/TextHeadline">
<Button
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 148a99b..73a5737 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -15,8 +15,10 @@
-->
<com.android.launcher3.widget.WidgetCell
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:paddingHorizontal="@dimen/widget_cell_horizontal_padding"
+ android:paddingVertical="@dimen/widget_cell_vertical_padding"
android:layout_weight="1"
android:orientation="vertical"
android:focusable="true"
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 64f2362..65a49ab 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -17,47 +17,47 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/widget_preview_label_vertical_padding"
- android:paddingBottom="@dimen/widget_preview_label_vertical_padding"
- android:paddingLeft="@dimen/widget_preview_label_horizontal_padding"
- android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
- android:orientation="horizontal">
-
- <!-- The name of the widget. -->
- <TextView
- android:id="@+id/widget_name"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:ellipsize="end"
- android:fadingEdge="horizontal"
- android:gravity="start"
- android:singleLine="true"
- android:maxLines="1"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp" />
-
- <!-- The original dimensions of the widget (can't be the same text as above due to different
- style. -->
- <TextView
- android:id="@+id/widget_dims"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="5dp"
- android:layout_marginLeft="5dp"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp"
- android:alpha="0.8" />
- </LinearLayout>
-
<!-- The image of the widget. This view does not support padding. Any placement adjustment
should be done using margins. -->
<com.android.launcher3.widget.WidgetImageView
android:id="@+id/widget_preview"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="0dp"
- android:layout_weight="1" />
+ android:layout_weight="1"
+ android:layout_marginVertical="8dp" />
+
+ <!-- The name of the widget. -->
+ <TextView
+ android:id="@+id/widget_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:gravity="center_horizontal"
+ android:singleLine="true"
+ android:maxLines="1"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="14sp" />
+
+ <!-- The original dimensions of the widget (can't be the same text as above due to different
+ style. -->
+ <TextView
+ android:id="@+id/widget_dims"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="14sp"
+ android:alpha="0.8" />
+
+ <TextView
+ android:id="@+id/widget_description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textSize="12sp"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal" />
+
</merge>
\ No newline at end of file
diff --git a/res/layout/widgets_bottom_sheet.xml b/res/layout/widgets_bottom_sheet.xml
index 3fdfc96..c1b2cbf 100644
--- a/res/layout/widgets_bottom_sheet.xml
+++ b/res/layout/widgets_bottom_sheet.xml
@@ -44,11 +44,16 @@
android:textSize="14sp"
android:text="@string/long_press_widget_to_add"/>
- <include layout="@layout/widgets_scroll_container"
- android:id="@+id/widgets"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="45dp"
- android:layout_marginBottom="40dp"/>
+ <ScrollView
+ android:id="@+id/widgets_table_scroll_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="45dp"
+ android:layout_marginBottom="40dp">
+ <include layout="@layout/widgets_table_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal" />
+ </ScrollView>
</com.android.launcher3.widget.WidgetsBottomSheet>
\ No newline at end of file
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index cfbb6dd..8125db8 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -16,13 +16,15 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <include layout="@layout/personal_work_tabs" />
+ <include layout="@layout/personal_work_tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="16dp" />
<com.android.launcher3.workprofile.PersonalWorkPagedView
android:id="@+id/widgets_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@+id/tabs"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
launcher:pageIndicator="@+id/tabs">
diff --git a/res/layout/widgets_full_sheet_search_and_recommendations.xml b/res/layout/widgets_full_sheet_search_and_recommendations.xml
new file mode 100644
index 0000000..9a6f922
--- /dev/null
+++ b/res/layout/widgets_full_sheet_search_and_recommendations.xml
@@ -0,0 +1,49 @@
+<?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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/search_and_recommendations_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:orientation="vertical">
+ <View
+ android:id="@+id/collapse_handle"
+ android:layout_width="48dp"
+ android:layout_height="2dp"
+ android:layout_gravity="center_horizontal"
+ android:background="@color/popup_color_primary_dark"/>
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textSize="24sp"
+ android:layout_marginTop="16dp"
+ android:text="@string/widget_button_text"/>
+ <!-- Disable the search bar because it has not been implemented. -->
+ <EditText
+ android:id="@+id/widgets_search_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:layout_marginTop="16dp"
+ android:background="@drawable/bg_widgets_searchbox"
+ android:drawablePadding="8dp"
+ android:drawableStart="@drawable/ic_allapps_search"
+ android:hint="@string/widgets_full_sheet_search_bar_hint"
+ android:padding="12dp" />
+</LinearLayout>
diff --git a/res/layout/widgets_table_container.xml b/res/layout/widgets_table_container.xml
index ffa239a..c4dfe7e 100644
--- a/res/layout/widgets_table_container.xml
+++ b/res/layout/widgets_table_container.xml
@@ -18,4 +18,5 @@
android:id="@+id/widgets_table"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginHorizontal="8dp"
android:background="?android:attr/colorPrimaryDark" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index e532305..3b171c6 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -104,8 +104,8 @@
<dimen name="work_profile_footer_text_size">16sp</dimen>
<!-- Widget tray -->
- <dimen name="widget_preview_label_vertical_padding">8dp</dimen>
- <dimen name="widget_preview_label_horizontal_padding">16dp</dimen>
+ <dimen name="widget_cell_vertical_padding">8dp</dimen>
+ <dimen name="widget_cell_horizontal_padding">16dp</dimen>
<dimen name="widget_preview_shadow_blur">0.5dp</dimen>
<dimen name="widget_preview_key_shadow_distance">1dp</dimen>
@@ -187,13 +187,11 @@
<dimen name="popup_padding_start">10dp</dimen>
<dimen name="popup_padding_end">16dp</dimen>
<dimen name="popup_vertical_padding">4dp</dimen>
- <dimen name="popup_arrow_width">10dp</dimen>
- <dimen name="popup_arrow_height">8dp</dimen>
- <dimen name="popup_arrow_vertical_offset">-2dp</dimen>
+ <dimen name="popup_arrow_width">12dp</dimen>
+ <dimen name="popup_arrow_height">10dp</dimen>
+ <dimen name="popup_arrow_vertical_offset">-1dp</dimen>
<!-- popup_padding_start + deep_shortcut_icon_size / 2 -->
- <dimen name="popup_arrow_horizontal_center_start">28dp</dimen>
- <!-- popup_padding_end + deep_shortcut_drag_handle_size / 2 -->
- <dimen name="popup_arrow_horizontal_center_end">24dp</dimen>
+ <dimen name="popup_arrow_horizontal_center_offset">28dp</dimen>
<dimen name="popup_arrow_corner_radius">2dp</dimen>
<!-- popup_padding_start + icon_size + 10dp -->
<dimen name="deep_shortcuts_text_padding_start">56dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5a9def7..73f9e53 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -57,6 +57,12 @@
<item quantity="one"><xliff:g id="widget_count" example="1">%1$d</xliff:g> widget</item>
<item quantity="other"><xliff:g id="widget_count" example="2">%1$d</xliff:g> widgets</item>
</plurals>
+ <!-- Text for both the tile of a popup view, which shows all available widgets installed on
+ the device, and the text of a button, which opens this popup view. [CHAR LIMIT=30]-->
+ <string name="widget_button_text">Widgets</string>
+ <!-- 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>
<!-- All Apps -->
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
@@ -185,8 +191,6 @@
<string name="folder_name_format_overflow">Folder: <xliff:g id="name" example="Games">%1$s</xliff:g>, <xliff:g id="size" example="2">%2$d</xliff:g> or more items</string>
<!-- Strings for the customization mode -->
- <!-- Text for widget add button [CHAR LIMIT=30]-->
- <string name="widget_button_text">Widgets</string>
<!-- Text for wallpaper change button [CHAR LIMIT=30]-->
<string name="wallpaper_button_text">Wallpapers</string>
<!-- Text for wallpaper change button [CHAR LIMIT=30]-->
diff --git a/robolectric_tests/config/robolectric.properties b/robolectric_tests/config/robolectric.properties
index 4e811f3..936ce12 100644
--- a/robolectric_tests/config/robolectric.properties
+++ b/robolectric_tests/config/robolectric.properties
@@ -11,4 +11,4 @@
com.android.launcher3.shadows.ShadowOverrides \
com.android.launcher3.shadows.ShadowSurfaceTransactionApplier \
-application=com.android.launcher3.util.LauncherTestApplication
\ No newline at end of file
+application=com.android.launcher3.util.LauncherTestApplication
diff --git a/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java b/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
new file mode 100644
index 0000000..92f77f2
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.graphics.Point;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public final class LauncherAppWidgetProviderInfoTest {
+
+ private static final int CELL_SIZE = 50;
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ }
+
+ @Test
+ public void initSpans_minWidthSmallerThanCellWidth_shouldInitializeSpansToOne() {
+ LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
+ info.minWidth = 20;
+ info.minHeight = 20;
+ InvariantDeviceProfile idp = createIDP();
+
+ info.initSpans(mContext, idp);
+
+ assertThat(info.spanX).isEqualTo(1);
+ assertThat(info.spanY).isEqualTo(1);
+ }
+
+ @Test
+ public void initSpans_minWidthLargerThanCellWidth_shouldInitializeSpans() {
+ LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
+ info.minWidth = 80;
+ info.minHeight = 80;
+ InvariantDeviceProfile idp = createIDP();
+
+ info.initSpans(mContext, idp);
+
+ assertThat(info.spanX).isEqualTo(2);
+ assertThat(info.spanY).isEqualTo(2);
+ }
+
+ @Test
+ public void initSpans_minResizeWidthUnspecified_shouldInitializeMinSpansToOne() {
+ LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
+ InvariantDeviceProfile idp = createIDP();
+
+ info.initSpans(mContext, idp);
+
+ assertThat(info.minSpanX).isEqualTo(1);
+ assertThat(info.minSpanY).isEqualTo(1);
+ }
+
+ @Test
+ public void initSpans_minResizeWidthSmallerThanCellWidth_shouldInitializeMinSpansToOne() {
+ LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
+ info.minResizeWidth = 20;
+ info.minResizeHeight = 20;
+ InvariantDeviceProfile idp = createIDP();
+
+ info.initSpans(mContext, idp);
+
+ assertThat(info.minSpanX).isEqualTo(1);
+ assertThat(info.minSpanY).isEqualTo(1);
+ }
+
+ @Test
+ public void initSpans_minResizeWidthLargerThanCellWidth_shouldInitializeMinSpans() {
+ LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
+ info.minResizeWidth = 80;
+ info.minResizeHeight = 80;
+ InvariantDeviceProfile idp = createIDP();
+
+ info.initSpans(mContext, idp);
+
+ assertThat(info.minSpanX).isEqualTo(2);
+ assertThat(info.minSpanY).isEqualTo(2);
+ }
+
+ private InvariantDeviceProfile createIDP() {
+ DeviceProfile profile = Mockito.mock(DeviceProfile.class);
+ Mockito.when(profile.getCellSize()).thenReturn(new Point(CELL_SIZE, CELL_SIZE));
+
+ InvariantDeviceProfile idp = new InvariantDeviceProfile();
+ idp.landscapeProfile = idp.portraitProfile = profile;
+ return idp;
+ }
+
+}
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
index 04797a6..b972c6f 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
@@ -32,12 +32,12 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
index e94b253..a7c8d92 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
@@ -31,13 +31,13 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index ae5b9a5..848630e 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -34,7 +34,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.ComponentWithLabel;
@@ -42,6 +41,7 @@
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.testing.TestActivity;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetCell;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.picker.WidgetsListHeaderViewHolderBinder.OnHeaderClickListener;
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 358e6e0..8a0cf34 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -37,7 +37,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.icons.BitmapInfo;
@@ -46,6 +45,7 @@
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.testing.TestActivity;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetCell;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/model/WidgetsListContentEntryTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/model/WidgetsListContentEntryTest.java
index 86df3f8..2d22c45 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/model/WidgetsListContentEntryTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/model/WidgetsListContentEntryTest.java
@@ -26,11 +26,11 @@
import android.content.Context;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import org.junit.Before;
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
index 5922223..e68edd3 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
@@ -30,11 +30,11 @@
import android.os.UserHandle;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.util.WidgetsTableUtils;
import org.junit.Before;
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 4f008e2..a813275 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -30,6 +30,7 @@
import com.android.launcher3.util.FocusLogic;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index b85c648..75e89b2 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -21,6 +21,7 @@
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.util.ContentWriter;
+import com.android.launcher3.widget.LauncherAppWidgetHost;
public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index c55b46b..9369bdc 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -23,6 +23,7 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
+import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -188,4 +189,21 @@
super.onInitializeAccessibilityNodeInfo(info);
if (isLayoutSuppressed()) info.setScrollable(false);
}
+
+ /**
+ * Scrolls this recycler view to the top.
+ */
+ public void scrollToTop() {
+ if (mScrollbar != null) {
+ mScrollbar.reattachThumbToScroll();
+ }
+ if (getLayoutManager() instanceof LinearLayoutManager) {
+ LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
+ if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
+ // We are at the top, so don't scrollToPosition (would cause unnecessary relayout).
+ return;
+ }
+ }
+ scrollToPosition(0);
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index f7ff262..253a7c7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -181,7 +181,9 @@
import com.android.launcher3.views.FloatingSurfaceView;
import com.android.launcher3.views.OptionsPopupView;
import com.android.launcher3.views.ScrimView;
+import com.android.launcher3.widget.LauncherAppWidgetHost;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.PendingAppWidgetHostView;
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index e89b9b0..699495c 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -615,7 +615,9 @@
+ "\" bitmapIcon=" + info.bitmap.icon
+ " componentName=" + info.componentName.getPackageName());
}
+ writer.println();
}
+ mModelDelegate.dump(prefix, fd, writer, args);
mBgDataModel.dump(prefix, fd, writer, args);
}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index e151777..2ec5e90 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -71,6 +71,7 @@
import com.android.launcher3.util.NoLocaleSQLiteHelper;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.LauncherAppWidgetHost;
import org.xmlpull.v1.XmlPullParser;
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 7276887..4fd87cb 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -46,6 +46,7 @@
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import java.net.URISyntaxException;
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 2c45c77..446c873 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -50,6 +50,7 @@
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SQLiteCacheHelper;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetCell;
import com.android.launcher3.widget.WidgetManagerHelper;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 2528c03..aca3d3c 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -63,7 +63,6 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
-import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
import com.android.launcher3.anim.Interpolators;
@@ -104,6 +103,8 @@
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.WallpaperOffsetInterpolator;
+import com.android.launcher3.widget.LauncherAppWidgetHost;
+import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index ec2a6d5..a92e1aa 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -16,6 +16,8 @@
package com.android.launcher3.allapps;
import static com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
@@ -32,6 +34,7 @@
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -61,6 +64,7 @@
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
@@ -432,9 +436,19 @@
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN);
findViewById(R.id.tab_personal)
- .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.MAIN));
+ .setOnClickListener((View view) -> {
+ if (mViewPager.snapToPage(AdapterHolder.MAIN)) {
+ mLauncher.getStatsLogManager().logger()
+ .log(LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB);
+ }
+ });
findViewById(R.id.tab_work)
- .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.WORK));
+ .setOnClickListener((View view) -> {
+ if (mViewPager.snapToPage(AdapterHolder.WORK)) {
+ mLauncher.getStatsLogManager().logger()
+ .log(LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB);
+ }
+ });
onActivePageChanged(mViewPager.getNextPage());
} else {
mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
@@ -481,6 +495,10 @@
int layout = showTabs ? R.layout.all_apps_tabs : R.layout.all_apps_rv_layout;
View newView = getLayoutInflater().inflate(layout, this, false);
addView(newView, index);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.WORK_PROFILE_REMOVED, "should show tabs:" + showTabs,
+ new Exception());
+ }
if (showTabs) {
mViewPager = (AllAppsPagedView) newView;
mViewPager.initParentViews(this);
diff --git a/src/com/android/launcher3/allapps/AllAppsPagedView.java b/src/com/android/launcher3/allapps/AllAppsPagedView.java
index 647402b..14e3b51 100644
--- a/src/com/android/launcher3/allapps/AllAppsPagedView.java
+++ b/src/com/android/launcher3/allapps/AllAppsPagedView.java
@@ -15,9 +15,13 @@
*/
package com.android.launcher3.allapps;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SWIPE_TO_PERSONAL_TAB;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SWIPE_TO_WORK_TAB;
+
import android.content.Context;
import android.util.AttributeSet;
+import com.android.launcher3.Launcher;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
@@ -44,4 +48,16 @@
R.dimen.all_apps_header_top_padding);
setPadding(0, topPadding, 0, 0);
}
+
+ @Override
+ protected boolean snapToPageWithVelocity(int whichPage, int velocity) {
+ boolean resp = super.snapToPageWithVelocity(whichPage, velocity);
+ if (resp && whichPage != mCurrentPage) {
+ Launcher.getLauncher(getContext()).getStatsLogManager().logger()
+ .log(mCurrentPage < whichPage
+ ? LAUNCHER_ALLAPPS_SWIPE_TO_WORK_TAB
+ : LAUNCHER_ALLAPPS_SWIPE_TO_PERSONAL_TAB);
+ }
+ return resp;
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index e61b95d..ace9938 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -36,7 +36,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager;
import com.android.launcher3.views.RecyclerViewFastScroller;
import java.util.ArrayList;
@@ -109,23 +108,6 @@
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, grid.allAppsCellHeightPx);
}
- /**
- * Scrolls this recycler view to the top.
- */
- public void scrollToTop() {
- // Ensure we reattach the scrollbar if it was previously detached while fast-scrolling
- if (mScrollbar != null) {
- mScrollbar.reattachThumbToScroll();
- }
- if (getLayoutManager() instanceof AppsGridLayoutManager) {
- AppsGridLayoutManager layoutManager = (AppsGridLayoutManager) getLayoutManager();
- if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
- // We are at the top, so don't scrollToPosition (would cause unnecessary relayout).
- return;
- }
- }
- scrollToPosition(0);
- }
@Override
public void onDraw(Canvas c) {
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index bc2e66c..13ddc12 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -16,8 +16,6 @@
package com.android.launcher3.allapps;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SWITCHED_TO_MAIN_TAB;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SWITCHED_TO_WORK_TAB;
import android.content.Context;
import android.graphics.Rect;
@@ -90,14 +88,6 @@
public void onActivePageChanged(int currentActivePage) {
super.onActivePageChanged(currentActivePage);
if (mUsingTabs) {
- // Log tab switches only when the launcher is in AllApps state
- if (mLauncher.getStateManager().getCurrentStableState() == LauncherState.ALL_APPS) {
- mLauncher.getStatsLogManager().logger()
- .log(currentActivePage == AdapterHolder.WORK
- ? LAUNCHER_ALLAPPS_SWITCHED_TO_WORK_TAB
- : LAUNCHER_ALLAPPS_SWITCHED_TO_MAIN_TAB);
- }
-
if (currentActivePage == AdapterHolder.WORK) {
WorkEduView.showWorkEduIfNeeded(mLauncher);
} else {
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index f926086..39410a7 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -61,7 +61,8 @@
/**
* Called when activity is destroyed. Used to close search system services
*/
- default void destroy(){}
+ default void destroy() {
+ }
/**
* Returns true if the QSB should be visible for the given set of visible elements
@@ -75,4 +76,9 @@
*/
@Nullable
EditText getEditText();
+
+ /**
+ * sets highlight result's title
+ */
+ default void setFocusedResultTitle(@Nullable CharSequence title) { }
}
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index cf2e259..3319018 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -33,10 +33,10 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.search.SearchAlgorithm;
+import com.android.launcher3.search.SearchCallback;
import com.android.launcher3.util.PackageManagerHelper;
-import java.util.ArrayList;
-
/**
* An interface to a search box that AllApps can command.
*/
@@ -45,11 +45,11 @@
OnFocusChangeListener {
protected BaseDraggingActivity mLauncher;
- protected Callbacks mCb;
+ protected SearchCallback<AdapterItem> mCallback;
protected ExtendedEditText mInput;
protected String mQuery;
- protected SearchAlgorithm mSearchAlgorithm;
+ protected SearchAlgorithm<AdapterItem> mSearchAlgorithm;
public void setVisibility(int visibility) {
mInput.setVisibility(visibility);
@@ -59,9 +59,9 @@
* Sets the references to the apps model and the search result callback.
*/
public final void initialize(
- SearchAlgorithm searchAlgorithm, ExtendedEditText input,
- BaseDraggingActivity launcher, Callbacks cb) {
- mCb = cb;
+ SearchAlgorithm<AdapterItem> searchAlgorithm, ExtendedEditText input,
+ BaseDraggingActivity launcher, SearchCallback<AdapterItem> callback) {
+ mCallback = callback;
mLauncher = launcher;
mInput = input;
@@ -87,10 +87,10 @@
mQuery = s.toString();
if (mQuery.isEmpty()) {
mSearchAlgorithm.cancel(true);
- mCb.clearSearchResult();
+ mCallback.clearSearchResult();
} else {
mSearchAlgorithm.cancel(false);
- mSearchAlgorithm.doSearch(mQuery, mCb);
+ mSearchAlgorithm.doSearch(mQuery, mCallback);
}
}
@@ -100,7 +100,7 @@
}
// If play store continues auto updating an app, we want to show partial result.
mSearchAlgorithm.cancel(false);
- mSearchAlgorithm.doSearch(mQuery, mCb);
+ mSearchAlgorithm.doSearch(mQuery, mCallback);
}
@Override
@@ -153,7 +153,7 @@
* Resets the search bar state.
*/
public void reset() {
- mCb.clearSearchResult();
+ mCallback.clearSearchResult();
mInput.reset();
mQuery = null;
}
@@ -171,31 +171,4 @@
public boolean isSearchFieldFocused() {
return mInput.isFocused();
}
-
- /**
- * Callback for getting search results.
- */
- public interface Callbacks {
-
- /**
- * Called when the search from primary source is complete.
- *
- * @param items sorted list of search result adapter items
- */
- void onSearchResult(String query, ArrayList<AdapterItem> items);
-
- /**
- * Called when the search from secondary source is complete.
- *
- * @param items sorted list of search result adapter items
- */
- void onAppendSearchResult(String query, ArrayList<AdapterItem> items);
-
- /**
- * Called when the search results should be cleared.
- */
- void clearSearchResult();
- }
-
-
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index aef32d7..426fd0c 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -47,6 +47,7 @@
import com.android.launcher3.allapps.SearchUiManager;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.search.SearchCallback;
import java.util.ArrayList;
@@ -54,7 +55,7 @@
* Layout to contain the All-apps search UI.
*/
public class AppsSearchContainerLayout extends ExtendedEditText
- implements SearchUiManager, AllAppsSearchBarController.Callbacks,
+ implements SearchUiManager, SearchCallback<AdapterItem>,
AllAppsStore.OnUpdateListener, Insettable {
private final BaseDraggingActivity mLauncher;
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index 66bbd2e..4e213b0 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -19,14 +19,17 @@
import android.os.Handler;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.search.SearchAlgorithm;
+import com.android.launcher3.search.SearchCallback;
import java.text.Collator;
/**
* The default search implementation.
*/
-public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
+public class DefaultAppSearchAlgorithm implements SearchAlgorithm<AdapterItem> {
protected final Handler mResultHandler;
private final AppsSearchPipeline mAppsSearchPipeline;
@@ -45,7 +48,7 @@
@Override
public void doSearch(final String query,
- final AllAppsSearchBarController.Callbacks callback) {
+ final SearchCallback<AdapterItem> callback) {
mAppsSearchPipeline.query(query,
results -> mResultHandler.post(
() -> callback.onSearchResult(query, results)),
diff --git a/src/com/android/launcher3/allapps/search/LiveSearchManager.java b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
index 4ef154e..76099a6 100644
--- a/src/com/android/launcher3/allapps/search/LiveSearchManager.java
+++ b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
@@ -43,11 +43,11 @@
import androidx.slice.SliceViewManager.SliceCallback;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherState;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.SafeCloseable;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import java.util.ArrayList;
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 1d0a466..e406e9b 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -263,6 +263,8 @@
}
public void addChangeListener(Context context, Runnable r) { }
+
+ public void removeChangeListener(Runnable r) {}
}
public static class DebugFlag extends BooleanFlag {
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 77d2b85..5dc94ff 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -47,8 +47,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetHost;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.ItemInstallQueue;
@@ -56,6 +54,8 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.widget.LauncherAppWidgetHost;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetHostViewLoader;
diff --git a/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java b/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java
index be6a07f..fa062f5 100644
--- a/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java
+++ b/src/com/android/launcher3/dragndrop/LivePreviewWidgetCell.java
@@ -12,10 +12,10 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetCell;
/**
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index 6104d80..2290473 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -30,8 +30,8 @@
import com.android.launcher3.DragSource;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.PendingItemDragHelper;
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 3a9986e..5e9b179 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -58,7 +58,6 @@
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
@@ -91,6 +90,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.ArrayList;
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 431d534..d554bb9 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -362,11 +362,11 @@
@UiEvent(doc = "User closed the AllApps keyboard.")
LAUNCHER_ALLAPPS_KEYBOARD_CLOSED(694),
- @UiEvent(doc = "User switched to Main tab in AllApps screen.")
- LAUNCHER_ALLAPPS_SWITCHED_TO_MAIN_TAB(695),
+ @UiEvent(doc = "User switched to AllApps Main/Personal tab by swiping left.")
+ LAUNCHER_ALLAPPS_SWIPE_TO_PERSONAL_TAB(695),
- @UiEvent(doc = "User switched to Work tab in AllApps screen.")
- LAUNCHER_ALLAPPS_SWITCHED_TO_WORK_TAB(696),
+ @UiEvent(doc = "User switched to AllApps Work tab by swiping right.")
+ LAUNCHER_ALLAPPS_SWIPE_TO_WORK_TAB(696),
@UiEvent(doc = "Default event when dedicated UI event is not available for the user action"
+ " on slice .")
@@ -396,8 +396,17 @@
@UiEvent(doc = "IME is used for selecting the focused item on the AllApps screen.")
LAUNCHER_ALLAPPS_FOCUSED_ITEM_SELECTED_WITH_IME(718),
+ @UiEvent(doc = "User long-pressed on an AllApps item.")
+ LAUNCHER_ALLAPPS_ITEM_LONG_PRESSED(719),
+
@UiEvent(doc = "Launcher entered into AllApps state with device search enabled.")
LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH(720),
+
+ @UiEvent(doc = "User switched to AllApps Main/Personal tab by tapping on it.")
+ LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB(721),
+
+ @UiEvent(doc = "User switched to AllApps Work tab by tapping on it.")
+ LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB(722),
;
// ADD MORE
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index e8a52bd..804e72e 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -25,7 +25,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherSettings.Settings;
@@ -40,6 +39,7 @@
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
import java.util.ArrayList;
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
index 79467d3..c6c0791 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
@@ -39,7 +39,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
import com.android.launcher3.graphics.LauncherPreviewRenderer;
@@ -48,6 +47,7 @@
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
import java.util.ArrayList;
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index d09bf81..df8367f 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -42,7 +42,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -52,6 +51,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.PersistedItemArray;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import java.util.HashSet;
import java.util.List;
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 8438622..209c5be 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -45,12 +45,12 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.TimingLogger;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
@@ -87,6 +87,7 @@
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.TraceHelper;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
import java.util.ArrayList;
@@ -126,7 +127,7 @@
private final UserManagerState mUserManagerState = new UserManagerState();
- protected Map<ComponentKey, AppWidgetProviderInfo> mWidgetProvidersMap;
+ protected final Map<ComponentKey, AppWidgetProviderInfo> mWidgetProvidersMap = new ArrayMap<>();
private boolean mStopped;
@@ -664,12 +665,13 @@
final boolean wasProviderReady = !c.hasRestoreFlag(
LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
- if (mWidgetProvidersMap == null) {
- mWidgetProvidersMap = WidgetManagerHelper.getAllProvidersMap(
- context);
+ ComponentKey providerKey = new ComponentKey(component, c.user);
+ if (!mWidgetProvidersMap.containsKey(providerKey)) {
+ mWidgetProvidersMap.put(providerKey,
+ widgetHelper.findProvider(component, c.user));
}
- final AppWidgetProviderInfo provider = mWidgetProvidersMap.get(
- new ComponentKey(component, c.user));
+ final AppWidgetProviderInfo provider =
+ mWidgetProvidersMap.get(providerKey);
final boolean isProviderReady = isValidProvider(provider);
if (!isSafeMode && !customWidget &&
@@ -873,7 +875,6 @@
mBgDataModel.itemsIdMap.remove(folderId);
}
}
-
// Remove any ghost widgets
LauncherSettings.Settings.call(contentResolver,
LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS);
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 92bea5b..13ec1ec 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -27,6 +27,8 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ResourceBasedOverride;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Map;
/**
@@ -89,4 +91,11 @@
@WorkerThread
public void destroy() { }
+ /**
+ * Add data to a dumpsys request for Launcher (e.g. for bug reports).
+ *
+ * @see com.android.launcher3.Launcher#dump(java.lang.String, java.io.FileDescriptor,
+ * java.io.PrintWriter, java.lang.String[])
+ **/
+ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { }
}
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index f7b43d6..312435d 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -28,7 +28,6 @@
import android.util.Log;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetHost;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherSettings;
@@ -43,6 +42,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.widget.LauncherAppWidgetHost;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index de2481a..97071bb 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -4,11 +4,11 @@
import android.content.pm.PackageManager;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
/**
* An wrapper over various items displayed in a widget picker,
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 56438d0..5a34d2a 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -26,11 +26,8 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.CornerPathEffect;
import android.graphics.Outline;
-import android.graphics.Paint;
import android.graphics.Rect;
-import android.graphics.drawable.ShapeDrawable;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.Gravity;
@@ -51,7 +48,6 @@
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.graphics.TriangleShape;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
@@ -72,7 +68,11 @@
protected final T mLauncher;
protected final boolean mIsRtl;
- private final int mArrowOffset;
+ private final int mArrowOffsetVertical;
+ private final int mArrowOffsetHorizontal;
+ private final int mArrowWidth;
+ private final int mArrowHeight;
+ private final int mArrowPointRadius;
private final View mArrow;
protected boolean mIsLeftAligned;
@@ -103,11 +103,14 @@
// Initialize arrow view
final Resources resources = getResources();
- final int arrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
- final int arrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
+ mArrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
+ mArrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
mArrow = new View(context);
- mArrow.setLayoutParams(new DragLayer.LayoutParams(arrowWidth, arrowHeight));
- mArrowOffset = resources.getDimensionPixelSize(R.dimen.popup_arrow_vertical_offset);
+ mArrow.setLayoutParams(new DragLayer.LayoutParams(mArrowWidth, mArrowHeight));
+ mArrowOffsetVertical = resources.getDimensionPixelSize(R.dimen.popup_arrow_vertical_offset);
+ mArrowOffsetHorizontal = resources.getDimensionPixelSize(
+ R.dimen.popup_arrow_horizontal_center_offset) - (mArrowWidth / 2);
+ mArrowPointRadius = resources.getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
}
public ArrowPopup(Context context, AttributeSet attrs) {
@@ -200,48 +203,33 @@
orientAboutObject();
}
- private void addArrow() {
- final Resources res = getResources();
- final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart()
- ? R.dimen.popup_arrow_horizontal_center_start
- : R.dimen.popup_arrow_horizontal_center_end);
- final int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2;
- getPopupContainer().addView(mArrow);
- DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
+ private int getArrowLeft() {
if (mIsLeftAligned) {
- mArrow.setX(getX() + arrowCenterOffset - halfArrowWidth);
- } else {
- mArrow.setX(getX() + getMeasuredWidth() - arrowCenterOffset - halfArrowWidth);
+ return mArrowOffsetHorizontal;
}
+ return getMeasuredWidth() - mArrowOffsetHorizontal - mArrowWidth;
+ }
+
+ private void addArrow() {
+ getPopupContainer().addView(mArrow);
+ mArrow.setX(getX() + getArrowLeft());
if (Gravity.isVertical(mGravity)) {
// This is only true if there wasn't room for the container next to the icon,
// so we centered it instead. In that case we don't want to showDefaultOptions the arrow.
mArrow.setVisibility(INVISIBLE);
} else {
- ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
- arrowLp.width, arrowLp.height, !mIsAboveIcon));
- Paint arrowPaint = arrowDrawable.getPaint();
- arrowPaint.setColor(Themes.getAttrColor(getContext(), R.attr.popupColorPrimary));
- // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
- int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
- arrowPaint.setPathEffect(new CornerPathEffect(radius));
- mArrow.setBackground(arrowDrawable);
- // Clip off the part of the arrow that is underneath the popup.
- if (mIsAboveIcon) {
- mArrow.setClipBounds(new Rect(0, -mArrowOffset, arrowLp.width, arrowLp.height));
- } else {
- mArrow.setClipBounds(new Rect(0, 0, arrowLp.width, arrowLp.height + mArrowOffset));
- }
+ mArrow.setBackground(new RoundedArrowDrawable(
+ mArrowWidth, mArrowHeight, mArrowPointRadius,
+ mOutlineRadius, getMeasuredWidth(), getMeasuredHeight(),
+ mArrowOffsetHorizontal, -mArrowOffsetVertical,
+ !mIsAboveIcon, mIsLeftAligned,
+ Themes.getAttrColor(getContext(), R.attr.popupColorPrimary)));
mArrow.setElevation(getElevation());
}
- mArrow.setPivotX(arrowLp.width / 2);
- mArrow.setPivotY(mIsAboveIcon ? arrowLp.height : 0);
- }
-
- protected boolean isAlignedWithStart() {
- return mIsLeftAligned && !mIsRtl || !mIsLeftAligned && mIsRtl;
+ mArrow.setPivotX(mArrowWidth / 2.0f);
+ mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0);
}
/**
@@ -274,8 +262,9 @@
*/
private void orientAboutObject(boolean allowAlignLeft, boolean allowAlignRight) {
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
int width = getMeasuredWidth();
- int extraVerticalSpace = mArrow.getLayoutParams().height + mArrowOffset
+ int extraVerticalSpace = mArrowHeight + mArrowOffsetVertical
+ getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
int height = getMeasuredHeight() + extraVerticalSpace;
@@ -291,22 +280,7 @@
// Offset x so that the arrow and shortcut icons are center-aligned with the original icon.
int iconWidth = mTempRect.width();
- Resources resources = getResources();
- int xOffset;
- if (isAlignedWithStart()) {
- // Aligning with the shortcut icon.
- int shortcutIconWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcut_icon_size);
- int shortcutPaddingStart = resources.getDimensionPixelSize(
- R.dimen.popup_padding_start);
- xOffset = iconWidth / 2 - shortcutIconWidth / 2 - shortcutPaddingStart;
- } else {
- // Aligning with the drag handle.
- int shortcutDragHandleWidth = resources.getDimensionPixelSize(
- R.dimen.deep_shortcut_drag_handle_size);
- int shortcutPaddingEnd = resources.getDimensionPixelSize(
- R.dimen.popup_padding_end);
- xOffset = iconWidth / 2 - shortcutDragHandleWidth / 2 - shortcutPaddingEnd;
- }
+ int xOffset = iconWidth / 2 - mArrowOffsetHorizontal - mArrowWidth / 2;
x += mIsLeftAligned ? xOffset : -xOffset;
// Check whether we can still align as we originally wanted, now that we've calculated x.
@@ -375,12 +349,14 @@
FrameLayout.LayoutParams arrowLp = (FrameLayout.LayoutParams) mArrow.getLayoutParams();
if (mIsAboveIcon) {
arrowLp.gravity = lp.gravity = Gravity.BOTTOM;
- lp.bottomMargin = getPopupContainer().getHeight() - y - getMeasuredHeight() - insets.top;
- arrowLp.bottomMargin = lp.bottomMargin - arrowLp.height - mArrowOffset - insets.bottom;
+ lp.bottomMargin =
+ getPopupContainer().getHeight() - y - getMeasuredHeight() - insets.top;
+ arrowLp.bottomMargin =
+ lp.bottomMargin - arrowLp.height - mArrowOffsetVertical - insets.bottom;
} else {
arrowLp.gravity = lp.gravity = Gravity.TOP;
lp.topMargin = y + insets.top;
- arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrowOffset;
+ arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrowOffsetVertical;
}
}
@@ -529,22 +505,13 @@
protected void onCreateCloseAnimation(AnimatorSet anim) { }
private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
- Resources res = getResources();
- int arrowCenterX = res.getDimensionPixelSize(mIsLeftAligned ^ mIsRtl ?
- R.dimen.popup_arrow_horizontal_center_start:
- R.dimen.popup_arrow_horizontal_center_end);
- int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2;
- float arrowCornerRadius = res.getDimension(R.dimen.popup_arrow_corner_radius);
- if (!mIsLeftAligned) {
- arrowCenterX = getMeasuredWidth() - arrowCenterX;
- }
+ int arrowLeft = getArrowLeft();
int arrowCenterY = mIsAboveIcon ? getMeasuredHeight() : 0;
- mStartRect.set(arrowCenterX - halfArrowWidth, arrowCenterY, arrowCenterX + halfArrowWidth,
- arrowCenterY);
+ mStartRect.set(arrowLeft, arrowCenterY, arrowLeft + mArrowWidth, arrowCenterY);
- return new RoundedRectRevealOutlineProvider
- (arrowCornerRadius, mOutlineRadius, mStartRect, mEndRect);
+ return new RoundedRectRevealOutlineProvider(
+ mArrowPointRadius, mOutlineRadius, mStartRect, mEndRect);
}
/**
diff --git a/src/com/android/launcher3/popup/RoundedArrowDrawable.java b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
new file mode 100644
index 0000000..e662d5c
--- /dev/null
+++ b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
@@ -0,0 +1,161 @@
+/*
+ * 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.popup;
+
+import static java.lang.Math.atan;
+import static java.lang.Math.cos;
+import static java.lang.Math.sin;
+import static java.lang.Math.toDegrees;
+
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+
+/**
+ * A drawable for a very specific purpose. Used for the caret arrow on a rounded rectangle popup
+ * bubble.
+ * Draws a triangle with one rounded tip, the opposite edge is clipped by the body of the popup
+ * so there is no overlap when drawing them together.
+ */
+public class RoundedArrowDrawable extends Drawable {
+
+ private final Path mPath;
+ private final Paint mPaint;
+
+ /**
+ * Default constructor.
+ *
+ * @param width of the arrow.
+ * @param height of the arrow.
+ * @param radius of the tip of the arrow.
+ * @param popupRadius of the rect to clip this by.
+ * @param popupWidth of the rect to clip this by.
+ * @param popupHeight of the rect to clip this by.
+ * @param arrowOffsetX from the edge of the popup to the arrow.
+ * @param arrowOffsetY how much the arrow will overlap the popup.
+ * @param isPointingUp or not.
+ * @param leftAligned or false for right aligned.
+ * @param color to draw the triangle.
+ */
+ public RoundedArrowDrawable(float width, float height, float radius, float popupRadius,
+ float popupWidth, float popupHeight,
+ float arrowOffsetX, float arrowOffsetY, boolean isPointingUp, boolean leftAligned,
+ int color) {
+ mPath = new Path();
+ mPaint = new Paint();
+ mPaint.setColor(color);
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setAntiAlias(true);
+
+ // Make the drawable with the triangle pointing down and positioned on the left..
+ addDownPointingRoundedTriangleToPath(width, height, radius, mPath);
+ clipPopupBodyFromPath(popupRadius, popupWidth, popupHeight, arrowOffsetX, arrowOffsetY,
+ mPath);
+
+ // ... then flip it horizontal or vertical based on where it will be used.
+ Matrix pathTransform = new Matrix();
+ pathTransform.setScale(
+ leftAligned ? 1 : -1, isPointingUp ? -1 : 1, width * 0.5f, height * 0.5f);
+ mPath.transform(pathTransform);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawPath(mPath, mPaint);
+ }
+
+ @Override
+ public void getOutline(Outline outline) {
+ outline.setPath(mPath);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int i) {
+ mPaint.setAlpha(i);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ mPaint.setColorFilter(colorFilter);
+ }
+
+ private static void addDownPointingRoundedTriangleToPath(float width, float height,
+ float radius, Path path) {
+ // Calculated for the arrow pointing down, will be flipped later if needed.
+
+ // Theta is half of the angle inside the triangle tip
+ float tanTheta = width / (2.0f * height);
+ float theta = (float) atan(tanTheta);
+
+ // Some trigonometry to find the center of the circle for the rounded tip
+ float roundedPointCenterY = (float) (height - (radius / sin(theta)));
+
+ // p is the distance along the triangle side to the intersection with the point circle
+ float p = radius / tanTheta;
+ float lineRoundPointIntersectFromCenter = (float) (p * sin(theta));
+ float lineRoundPointIntersectFromTop = (float) (height - (p * cos(theta)));
+
+ float centerX = width / 2.0f;
+ float thetaDeg = (float) toDegrees(theta);
+
+ path.reset();
+ path.moveTo(0, 0);
+ // Draw the top
+ path.lineTo(width, 0);
+ // Draw the right side up to the circle intersection
+ path.lineTo(
+ centerX + lineRoundPointIntersectFromCenter,
+ lineRoundPointIntersectFromTop);
+ // Draw the rounded point
+ path.arcTo(
+ centerX - radius,
+ roundedPointCenterY - radius,
+ centerX + radius,
+ roundedPointCenterY + radius,
+ thetaDeg,
+ 180 - (2 * thetaDeg),
+ false);
+ // Draw the left edge to close
+ path.lineTo(0, 0);
+ path.close();
+ }
+
+ private static void clipPopupBodyFromPath(float popupRadius, float popupWidth,
+ float popupHeight, float arrowOffsetX, float arrowOffsetY, Path path) {
+ // Make a path that is used to clip the triangle, this represents the body of the popup
+ Path clipPiece = new Path();
+ clipPiece.addRoundRect(
+ 0, 0, popupWidth, popupHeight,
+ popupRadius, popupRadius, Path.Direction.CW);
+ // clipping is performed as if the arrow is pointing down and positioned on the left, the
+ // resulting path will be flipped as needed later.
+ // The extra 0.5 in the vertical offset is to close the gap between this anti-aliased object
+ // and the anti-aliased body of the popup.
+ clipPiece.offset(-arrowOffsetX, -popupHeight + arrowOffsetY - 0.5f);
+ path.op(clipPiece, Path.Op.DIFFERENCE);
+ }
+}
diff --git a/src/com/android/launcher3/allapps/search/SearchAlgorithm.java b/src/com/android/launcher3/search/SearchAlgorithm.java
similarity index 76%
rename from src/com/android/launcher3/allapps/search/SearchAlgorithm.java
rename to src/com/android/launcher3/search/SearchAlgorithm.java
index c409b1c..1665354 100644
--- a/src/com/android/launcher3/allapps/search/SearchAlgorithm.java
+++ b/src/com/android/launcher3/search/SearchAlgorithm.java
@@ -13,17 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.allapps.search;
+package com.android.launcher3.search;
/**
* An interface for handling search.
+ *
+ * @param <T> Search Result type
*/
-public interface SearchAlgorithm {
+public interface SearchAlgorithm<T> {
/**
- * Performs search and sends the result to the callback.
+ * Performs search and sends the result to {@link SearchCallback}.
*/
- void doSearch(String query, AllAppsSearchBarController.Callbacks callback);
+ void doSearch(String query, SearchCallback<T> callback);
/**
* Cancels any active request.
diff --git a/src/com/android/launcher3/search/SearchCallback.java b/src/com/android/launcher3/search/SearchCallback.java
new file mode 100644
index 0000000..5796116
--- /dev/null
+++ b/src/com/android/launcher3/search/SearchCallback.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.search;
+
+import java.util.ArrayList;
+
+/**
+ * An interface for receiving search results.
+ *
+ * @param <T> Search Result type
+ */
+public interface SearchCallback<T> {
+
+ /**
+ * Called when the search from primary source is complete.
+ *
+ * @param items list of search results
+ */
+ void onSearchResult(String query, ArrayList<T> items);
+
+ /**
+ * Called when the search from secondary source is complete.
+ *
+ * @param items list of search results
+ */
+ void onAppendSearchResult(String query, ArrayList<T> items);
+
+ /**
+ * Called when the search results should be cleared.
+ */
+ void clearSearchResult();
+}
+
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index ac8dac5..f03065c 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -129,6 +129,7 @@
private String mHighLightKey;
private boolean mPreferenceHighlighted = false;
private NotificationDotsPreference mNotificationSettingsChangedListener;
+ private Preference mDeveloperOptionPref;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@@ -202,18 +203,37 @@
return FeatureFlags.showFlagTogglerUi(getContext());
case DEVELOPER_OPTIONS_KEY:
- // Show if plugins are enabled or flag UI is enabled.
- return FeatureFlags.showFlagTogglerUi(getContext()) ||
- PluginManagerWrapper.hasPlugins(getContext());
+ mDeveloperOptionPref = preference;
+ return updateDeveloperOption();
}
return true;
}
+ /**
+ * Show if plugins are enabled or flag UI is enabled.
+ * @return True if we should show the preference option.
+ */
+ private boolean updateDeveloperOption() {
+ boolean showPreference = FeatureFlags.showFlagTogglerUi(getContext())
+ || PluginManagerWrapper.hasPlugins(getContext());
+ if (mDeveloperOptionPref != null) {
+ mDeveloperOptionPref.setEnabled(showPreference);
+ if (showPreference) {
+ getPreferenceScreen().addPreference(mDeveloperOptionPref);
+ } else {
+ getPreferenceScreen().removePreference(mDeveloperOptionPref);
+ }
+ }
+ return showPreference;
+ }
+
@Override
public void onResume() {
super.onResume();
+ updateDeveloperOption();
+
if (isAdded() && !mPreferenceHighlighted) {
PreferenceHighlighter highlighter = createHighlighter();
if (highlighter != null) {
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 098d90d..61bd30a 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -41,7 +41,6 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.folder.Folder;
@@ -59,6 +58,7 @@
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.FloatingIconView;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.WidgetAddFlowHandler;
import com.android.launcher3.widget.WidgetManagerHelper;
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 7baeab8..919673f 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ITEM_LONG_PRESSED;
import android.view.View;
import android.view.View.OnLongClickListener;
@@ -32,6 +33,7 @@
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.folder.Folder;
+import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
@@ -86,6 +88,12 @@
if (!launcher.isInState(ALL_APPS) && !launcher.isInState(OVERVIEW)) return false;
if (launcher.getWorkspace().isSwitchingState()) return false;
+ StatsLogger logger = launcher.getStatsLogManager().logger();
+ if (v.getTag() instanceof ItemInfo) {
+ logger.withItemInfo((ItemInfo) v.getTag());
+ }
+ logger.log(LAUNCHER_ALLAPPS_ITEM_LONG_PRESSED);
+
// Start the drag
final DragController dragController = launcher.getDragController();
dragController.addDragListener(new DragController.DragListener() {
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 804fb3e..ae34257 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -34,6 +34,7 @@
import android.view.ViewConfiguration;
import android.widget.TextView;
+import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.BaseRecyclerView;
@@ -99,6 +100,7 @@
private boolean mIsThumbDetached;
private final boolean mCanThumbDetach;
private boolean mIgnoreDragGesture;
+ private boolean mIsRecyclerViewFirstChildInParent = true;
// This is the offset from the top of the scrollbar when the user first starts touching. To
// prevent jumping, this offset is applied as the user scrolls.
@@ -112,6 +114,7 @@
protected BaseRecyclerView mRv;
private RecyclerView.OnScrollListener mOnScrollListener;
+ @Nullable private OnFastScrollChangeListener mOnFastScrollChangeListener;
private int mDownX;
private int mDownY;
@@ -188,6 +191,9 @@
updatePopupY(y);
mThumbOffsetY = y;
invalidate();
+ if (mOnFastScrollChangeListener != null) {
+ mOnFastScrollChangeListener.onThumbOffsetYChanged(mThumbOffsetY);
+ }
}
public int getThumbOffsetY() {
@@ -391,7 +397,9 @@
return false;
}
getHitRect(sTempRect);
- sTempRect.top += mRv.getScrollBarTop();
+ if (mIsRecyclerViewFirstChildInParent) {
+ sTempRect.top += mRv.getScrollBarTop();
+ }
if (outOffset != null) {
outOffset.set(sTempRect.left, sTempRect.top);
}
@@ -404,4 +412,23 @@
// alpha is so low, it does not matter.
return false;
}
+
+ public void setIsRecyclerViewFirstChildInParent(boolean isRecyclerViewFirstChildInParent) {
+ mIsRecyclerViewFirstChildInParent = isRecyclerViewFirstChildInParent;
+ }
+
+ public void setOnFastScrollChangeListener(
+ @Nullable OnFastScrollChangeListener onFastScrollChangeListener) {
+ mOnFastScrollChangeListener = onFastScrollChangeListener;
+ }
+
+ /**
+ * A callback that is invoked when there is a scroll change in {@link RecyclerViewFastScroller}.
+ */
+ public interface OnFastScrollChangeListener {
+ /**
+ * Called when the thumb offset vertical position, in pixels, has changed to {@code y}.
+ */
+ void onThumbOffsetYChanged(int y);
+ }
}
diff --git a/src/com/android/launcher3/views/WorkEduView.java b/src/com/android/launcher3/views/WorkEduView.java
index 03d3026..c8cf627 100644
--- a/src/com/android/launcher3/views/WorkEduView.java
+++ b/src/com/android/launcher3/views/WorkEduView.java
@@ -168,8 +168,8 @@
}
private AllAppsPagedView getAllAppsPagedView() {
- View v = mLauncher.getAppsView().getContentView();
- return (v instanceof AllAppsPagedView) ? (AllAppsPagedView) v : null;
+ View v = mLauncher.getAppsView().getContentView();
+ return (v instanceof AllAppsPagedView) ? (AllAppsPagedView) v : null;
}
/**
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
similarity index 96%
rename from src/com/android/launcher3/LauncherAppWidgetHost.java
rename to src/com/android/launcher3/widget/LauncherAppWidgetHost.java
index fea26df..d745754 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.launcher3;
+package com.android.launcher3.widget;
import static android.app.Activity.RESULT_CANCELED;
@@ -29,12 +29,13 @@
import android.util.SparseArray;
import android.widget.Toast;
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.widget.DeferredAppWidgetHostView;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.ArrayList;
@@ -199,7 +200,7 @@
}
}
- void addPendingView(int appWidgetId, PendingAppWidgetHostView view) {
+ public void addPendingView(int appWidgetId, PendingAppWidgetHostView view) {
mPendingViews.put(appWidgetId, view);
}
@@ -247,7 +248,7 @@
super.onProviderChanged(appWidgetId, info);
// The super method updates the dimensions of the providerInfo. Update the
// launcher spans accordingly.
- info.initSpans(mContext);
+ info.initSpans(mContext, LauncherAppState.getIDP(mContext));
}
/**
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 41098f9..54e51b2 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -37,7 +37,6 @@
import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragLayer;
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
similarity index 92%
rename from src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
rename to src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
index 618b5de..b0c85f1 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
@@ -1,4 +1,4 @@
-package com.android.launcher3;
+package com.android.launcher3.widget;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
@@ -11,6 +11,9 @@
import android.os.Parcel;
import android.os.UserHandle;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.Utilities;
import com.android.launcher3.icons.ComponentWithLabelAndIcon;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -48,7 +51,7 @@
launcherInfo = new LauncherAppWidgetProviderInfo(p);
p.recycle();
}
- launcherInfo.initSpans(context);
+ launcherInfo.initSpans(context, LauncherAppState.getIDP(context));
return launcherInfo;
}
@@ -58,9 +61,7 @@
super(in);
}
- public void initSpans(Context context) {
- InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
-
+ public void initSpans(Context context, InvariantDeviceProfile idp) {
Point landCellSize = idp.landscapeProfile.getCellSize();
Point portCellSize = idp.portraitProfile.getCellSize();
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index bef9a08..ee0b84e 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -20,7 +20,6 @@
import android.appwidget.AppWidgetHostView;
import android.os.Bundle;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.PendingAddItemInfo;
diff --git a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
index ebc2a25..1ac5a33 100644
--- a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
+++ b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java
@@ -21,7 +21,6 @@
import android.os.Parcelable;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.PendingRequestArgs;
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index bef91d2..8c315fd 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -16,6 +16,8 @@
package com.android.launcher3.widget;
+import static com.android.launcher3.Utilities.ATLEAST_S;
+
import android.content.Context;
import android.graphics.Bitmap;
import android.os.CancellationSignal;
@@ -24,7 +26,6 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
-import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.LinearLayout;
@@ -60,12 +61,15 @@
/** Widget preview width is calculated by multiplying this factor to the widget cell width. */
private static final float PREVIEW_SCALE = 0.8f;
+ private int mPreviewWidth;
+ private int mPreviewHeight;
protected int mPresetPreviewSize;
private int mCellSize;
private WidgetImageView mWidgetImage;
private TextView mWidgetName;
private TextView mWidgetDims;
+ private TextView mWidgetDescription;
protected WidgetItem mItem;
@@ -106,15 +110,17 @@
private void setContainerWidth() {
mCellSize = (int) (mDeviceProfile.allAppsIconSizePx * WIDTH_SCALE);
mPresetPreviewSize = (int) (mCellSize * PREVIEW_SCALE);
+ mPreviewWidth = mPreviewHeight = mPresetPreviewSize;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mWidgetImage = (WidgetImageView) findViewById(R.id.widget_preview);
- mWidgetName = ((TextView) findViewById(R.id.widget_name));
- mWidgetDims = ((TextView) findViewById(R.id.widget_dims));
+ mWidgetImage = findViewById(R.id.widget_preview);
+ mWidgetName = findViewById(R.id.widget_name);
+ mWidgetDims = findViewById(R.id.widget_dims);
+ mWidgetDescription = findViewById(R.id.widget_description);
}
/**
@@ -128,6 +134,9 @@
mWidgetImage.setBitmap(null, null);
mWidgetName.setText(null);
mWidgetDims.setText(null);
+ mWidgetDescription.setText(null);
+ mWidgetDescription.setVisibility(GONE);
+ mPreviewWidth = mPreviewHeight = mPresetPreviewSize;
if (mActiveRequest != null) {
mActiveRequest.cancel();
@@ -142,8 +151,17 @@
mItem.spanX, mItem.spanY));
mWidgetDims.setContentDescription(getContext().getString(
R.string.widget_accessible_dims_format, mItem.spanX, mItem.spanY));
- mWidgetPreviewLoader = loader;
+ if (ATLEAST_S && mItem.widgetInfo != null) {
+ CharSequence description = mItem.widgetInfo.loadDescription(getContext());
+ if (description != null && description.length() > 0) {
+ mWidgetDescription.setText(description);
+ mWidgetDescription.setVisibility(VISIBLE);
+ } else {
+ mWidgetDescription.setVisibility(GONE);
+ }
+ }
+ mWidgetPreviewLoader = loader;
if (item.activityInfo != null) {
setTag(new PendingAddShortcutInfo(item.activityInfo));
} else {
@@ -181,6 +199,11 @@
return;
}
if (bitmap != null) {
+ LayoutParams layoutParams = (LayoutParams) mWidgetImage.getLayoutParams();
+ layoutParams.width = bitmap.getWidth();
+ layoutParams.height = bitmap.getHeight();
+ mWidgetImage.setLayoutParams(layoutParams);
+
mWidgetImage.setBitmap(bitmap, mWidgetPreviewLoader.getBadgeForUser(mItem.user,
BaseIconFactory.getBadgeSizeForIconSize(mDeviceProfile.allAppsIconSizePx)));
if (mAnimatePreview) {
@@ -197,8 +220,16 @@
if (mActiveRequest != null) {
return;
}
- mActiveRequest = mWidgetPreviewLoader.getPreview(
- mItem, mPresetPreviewSize, mPresetPreviewSize, this);
+ mActiveRequest = mWidgetPreviewLoader.getPreview(mItem, mPreviewWidth, mPreviewHeight,
+ this);
+ }
+
+ /** Sets the widget preview image size in number of cells. */
+ public void setPreviewSize(int spanX, int spanY) {
+ int padding = 2 * getResources()
+ .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
+ mPreviewWidth = mDeviceProfile.cellWidthPx * spanX + padding;
+ mPreviewHeight = mDeviceProfile.cellHeightPx * spanY + padding;
}
@Override
@@ -233,12 +264,6 @@
}
@Override
- public void setLayoutParams(ViewGroup.LayoutParams params) {
- params.width = params.height = mCellSize;
- super.setLayoutParams(params);
- }
-
- @Override
public CharSequence getAccessibilityClassName() {
return WidgetCell.class.getName();
}
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index 2438bdf..31cbff6 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -13,7 +13,6 @@
import com.android.launcher3.AppWidgetResizeFrame;
import com.android.launcher3.DropTarget;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
diff --git a/src/com/android/launcher3/widget/WidgetManagerHelper.java b/src/com/android/launcher3/widget/WidgetManagerHelper.java
index c0c5c48..15fa844 100644
--- a/src/com/android/launcher3/widget/WidgetManagerHelper.java
+++ b/src/com/android/launcher3/widget/WidgetManagerHelper.java
@@ -27,18 +27,14 @@
import androidx.annotation.Nullable;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -122,15 +118,6 @@
appWidgetId).getBoolean(WIDGET_OPTION_RESTORE_COMPLETED);
}
- public static Map<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap(Context context) {
- if (WidgetsModel.GO_DISABLE_WIDGETS) {
- return Collections.emptyMap();
- }
- return allWidgetsSteam(context).collect(
- Collectors.toMap(info -> new ComponentKey(info.provider, info.getProfile()),
- Function.identity()));
- }
-
private static Stream<AppWidgetProviderInfo> allWidgetsSteam(Context context) {
AppWidgetManager awm = context.getSystemService(AppWidgetManager.class);
return Stream.concat(
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 223cda2..6abbf21 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -24,22 +24,25 @@
import android.util.AttributeSet;
import android.util.IntProperty;
import android.util.Pair;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
+import android.widget.ScrollView;
+import android.widget.TableLayout;
+import android.widget.TableRow;
import android.widget.TextView;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
-import com.android.launcher3.ResourceUtils;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.dragndrop.LivePreviewWidgetCell;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.util.WidgetsTableUtils;
import java.util.List;
@@ -65,6 +68,8 @@
private static final int DEFAULT_CLOSE_DURATION = 200;
private ItemInfo mOriginalItemInfo;
private Rect mInsets;
+ private final int mMaxTableHeight;
+ private int mMaxHorizontalSpan = 4;
public WidgetsBottomSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -75,12 +80,41 @@
setWillNotDraw(false);
mInsets = new Rect();
mContent = this;
+ DeviceProfile deviceProfile = mLauncher.getDeviceProfile();
+ // Set the max table height to 2 / 3 of the grid height so that the bottom picker won't
+ // take over the entire view vertically.
+ mMaxTableHeight = deviceProfile.inv.numRows * 2 / 3 * deviceProfile.cellHeightPx;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ int paddingPx = 2 * getResources().getDimensionPixelOffset(
+ R.dimen.widget_cell_horizontal_padding);
+ int maxHorizontalSpan = findViewById(R.id.widgets_table).getMeasuredWidth()
+ / (mLauncher.getDeviceProfile().cellWidthPx + paddingPx);
+
+ if (mMaxHorizontalSpan != maxHorizontalSpan) {
+ // Ensure the table layout is showing widgets in the right column after measure.
+ mMaxHorizontalSpan = maxHorizontalSpan;
+ onWidgetsBound();
+ }
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
setTranslationShift(mTranslationShift);
+
+ // Ensure the scroll view height is not larger than mMaxTableHeight, which is a value
+ // smaller than the entire screen height.
+ ScrollView widgetsTableScrollView = findViewById(R.id.widgets_table_scroll_view);
+ if (widgetsTableScrollView.getMeasuredHeight() > mMaxTableHeight) {
+ ViewGroup.LayoutParams layoutParams = widgetsTableScrollView.getLayoutParams();
+ layoutParams.height = mMaxTableHeight;
+ widgetsTableScrollView.setLayoutParams(layoutParams);
+ }
}
public void populateAndShow(ItemInfo itemInfo) {
@@ -101,39 +135,21 @@
mOriginalItemInfo.getTargetComponent().getPackageName(),
mOriginalItemInfo.user));
- ViewGroup widgetRow = findViewById(R.id.widgets);
- ViewGroup widgetCells = widgetRow.findViewById(R.id.widgets_cell_list);
+ TableLayout widgetsTable = findViewById(R.id.widgets_table);
+ widgetsTable.removeAllViews();
- widgetCells.removeAllViews();
-
- for (int i = 0; i < widgets.size(); i++) {
- WidgetCell widget = addItemCell(widgetCells);
- widget.applyFromCellItem(widgets.get(i), LauncherAppState.getInstance(mLauncher)
- .getWidgetCache());
- widget.ensurePreview();
- widget.setVisibility(View.VISIBLE);
- if (i < widgets.size() - 1) {
- addDivider(widgetCells);
- }
- }
-
- if (widgets.size() == 1) {
- // If there is only one widget, we want to center it instead of left-align.
- WidgetsBottomSheet.LayoutParams params = (WidgetsBottomSheet.LayoutParams)
- widgetRow.getLayoutParams();
- params.gravity = Gravity.CENTER_HORIZONTAL;
- } else {
- // Otherwise, add an empty view to the start as padding (but still scroll edge to edge).
- View leftPaddingView = LayoutInflater.from(getContext()).inflate(
- R.layout.widget_list_divider, widgetRow, false);
- leftPaddingView.getLayoutParams().width = ResourceUtils.pxFromDp(
- 16, getResources().getDisplayMetrics());
- widgetCells.addView(leftPaddingView, 0);
- }
- }
-
- private void addDivider(ViewGroup parent) {
- LayoutInflater.from(getContext()).inflate(R.layout.widget_list_divider, parent, true);
+ WidgetsTableUtils.groupWidgetItemsIntoTable(widgets, mMaxHorizontalSpan).forEach(row -> {
+ TableRow tableRow = new TableRow(getContext());
+ row.forEach(widgetItem -> {
+ WidgetCell widget = addItemCell(tableRow);
+ widget.setPreviewSize(widgetItem.spanX, widgetItem.spanY);
+ widget.applyFromCellItem(widgetItem, LauncherAppState.getInstance(mLauncher)
+ .getWidgetCache());
+ widget.ensurePreview();
+ widget.setVisibility(View.VISIBLE);
+ });
+ widgetsTable.addView(tableRow);
+ });
}
protected WidgetCell addItemCell(ViewGroup parent) {
diff --git a/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java
index 1086987..8b3bbce 100644
--- a/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java
@@ -22,8 +22,9 @@
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
/**
* Custom app widget provider info that can be used as a widget, but provide extra functionality
@@ -57,7 +58,7 @@
}
@Override
- public void initSpans(Context context) { }
+ public void initSpans(Context context, InvariantDeviceProfile idp) { }
@Override
public String getLabel(PackageManager packageManager) {
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
index 0b66ec0..329a444 100644
--- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -16,7 +16,7 @@
package com.android.launcher3.widget.custom;
-import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
+import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
@@ -29,12 +29,12 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.systemui.plugins.CustomWidgetPlugin;
import com.android.systemui.plugins.PluginListener;
diff --git a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
new file mode 100644
index 0000000..a5ed20a
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
@@ -0,0 +1,162 @@
+/*
+ * 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.widget.picker;
+
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.launcher3.views.RecyclerViewFastScroller;
+import com.android.launcher3.widget.picker.WidgetsFullSheet.SearchAndRecommendationViewHolder;
+import com.android.launcher3.workprofile.PersonalWorkPagedView;
+
+/**
+ * A controller which measures & updates {@link WidgetsFullSheet}'s views padding, margin and
+ * vertical displacement upon scrolling.
+ */
+final class SearchAndRecommendationsScrollController implements
+ RecyclerViewFastScroller.OnFastScrollChangeListener {
+ private final boolean mHasWorkProfile;
+ private final SearchAndRecommendationViewHolder mViewHolder;
+ private final RecyclerView mPrimaryRecyclerView;
+
+ // The following are only non null if mHasWorkProfile is true.
+ @Nullable private final RecyclerView mWorkRecyclerView;
+ @Nullable private final View mPrimaryWorkTabsView;
+ @Nullable private final PersonalWorkPagedView mPrimaryWorkViewPager;
+
+ private int mMaxCollapsibleHeight = 0;
+
+ SearchAndRecommendationsScrollController(
+ boolean hasWorkProfile,
+ SearchAndRecommendationViewHolder viewHolder,
+ RecyclerView primaryRecyclerView,
+ @Nullable RecyclerView workRecyclerView,
+ @Nullable View personalWorkTabsView,
+ @Nullable PersonalWorkPagedView primaryWorkViewPager) {
+ mHasWorkProfile = hasWorkProfile;
+ mViewHolder = viewHolder;
+ mPrimaryRecyclerView = primaryRecyclerView;
+ mWorkRecyclerView = workRecyclerView;
+ mPrimaryWorkTabsView = personalWorkTabsView;
+ mPrimaryWorkViewPager = primaryWorkViewPager;
+ }
+
+ /**
+ * Updates the margin and padding of {@link WidgetsFullSheet} to accumulate collapsible views.
+ */
+ public void updateMarginAndPadding() {
+ // The maximum vertical distance, in pixels, until the last collapsible element is not
+ // visible from the screen when the user scrolls down the recycler view.
+ mMaxCollapsibleHeight = mViewHolder.mContainer.getPaddingTop()
+ + mViewHolder.mCollapseHandle.getMeasuredHeight()
+ + mViewHolder.mHeaderTitle.getMeasuredHeight();
+
+ int topContainerHeight = mViewHolder.mContainer.getMeasuredHeight();
+ if (mHasWorkProfile) {
+ // In a work profile setup, the full widget sheet contains the following views:
+ // ------- -|
+ // Widgets -|---> LinearLayout for search & recommendations
+ // Search bar -|
+ // Personal | Work
+ // View Pager
+ //
+ // Views after the search & recommendations are not bound by RelativelyLayout param.
+ // To position them on the expected location, padding & margin are added to these views
+
+ // Tabs should have a padding of the height of the search & recommendations container.
+ mPrimaryWorkTabsView.setPadding(
+ mPrimaryWorkTabsView.getPaddingLeft(),
+ topContainerHeight,
+ mPrimaryWorkTabsView.getPaddingRight(),
+ mPrimaryWorkTabsView.getPaddingBottom());
+
+ // Instead of setting the top offset directly, we split the top offset into two values:
+ // 1. topOffsetAfterAllViewsCollapsed: this is the top offset after all collapsible
+ // views are no longer visible on the screen.
+ // This value is set as the margin for the view pager.
+ // 2. mMaxCollapsibleDistance
+ // This value is set as the padding for the recycler views in order to work with
+ // clipToPadding="false", which is an attribute for not showing top / bottom padding
+ // when a recycler view has not reached the top or bottom of the list.
+ // e.g. a list of 10 entries, only 3 entries are visible at a time.
+ // case 1: recycler view is scrolled to the top. Top padding is visible/
+ // (top padding)
+ // item 1
+ // item 2
+ // item 3
+ //
+ // case 2: recycler view is scrolled to the middle. No padding is visible.
+ // item 4
+ // item 5
+ // item 6
+ //
+ // case 3: recycler view is scrolled to the end. bottom padding is visible.
+ // item 8
+ // item 9
+ // item 10
+ // (bottom padding): not set in this case.
+ //
+ // When the views are first inflated, the sum of topOffsetAfterAllViewsCollapsed and
+ // mMaxCollapsibleDistance should equal to the top container height.
+ int tabsViewActualHeight =
+ mPrimaryWorkTabsView.getMeasuredHeight() - mPrimaryWorkTabsView.getPaddingTop();
+ int topOffsetAfterAllViewsCollapsed =
+ topContainerHeight + tabsViewActualHeight - mMaxCollapsibleHeight;
+
+ RelativeLayout.LayoutParams layoutParams =
+ (RelativeLayout.LayoutParams) mPrimaryWorkViewPager.getLayoutParams();
+ layoutParams.setMargins(0, topOffsetAfterAllViewsCollapsed, 0, 0);
+ mPrimaryWorkViewPager.setLayoutParams(layoutParams);
+ mPrimaryWorkViewPager.requestLayout();
+
+ mPrimaryRecyclerView.setPadding(
+ mPrimaryRecyclerView.getPaddingLeft(),
+ mMaxCollapsibleHeight,
+ mPrimaryRecyclerView.getPaddingRight(),
+ mPrimaryRecyclerView.getPaddingBottom());
+ mWorkRecyclerView.setPadding(
+ mWorkRecyclerView.getPaddingLeft(),
+ mMaxCollapsibleHeight,
+ mWorkRecyclerView.getPaddingRight(),
+ mWorkRecyclerView.getPaddingBottom());
+ } else {
+ mPrimaryRecyclerView.setPadding(
+ mPrimaryRecyclerView.getPaddingLeft(),
+ topContainerHeight,
+ mPrimaryRecyclerView.getPaddingRight(),
+ mPrimaryRecyclerView.getPaddingBottom());
+ }
+ }
+
+ /**
+ * Changes the displacement of collapsible views (e.g. title & widget recommendations) and fixed
+ * views (e.g. recycler views, tabs) upon scrolling.
+ */
+ @Override
+ public void onThumbOffsetYChanged(int y) {
+ if (mMaxCollapsibleHeight > 0) {
+ int yDisplacement = Math.max(-y, -mMaxCollapsibleHeight);
+ mViewHolder.mHeaderTitle.setTranslationY(yDisplacement);
+ mViewHolder.mSearchBar.setTranslationY(yDisplacement);
+ if (mHasWorkProfile) {
+ mPrimaryWorkTabsView.setTranslationY(yDisplacement);
+ }
+ }
+ }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 39953b1..91b79f9 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -34,6 +34,8 @@
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.widget.EditText;
+import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -43,13 +45,13 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.R;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.TopRoundedCornerView;
import com.android.launcher3.widget.BaseWidgetSheet;
+import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.workprofile.PersonalWorkPagedView;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
@@ -61,7 +63,8 @@
* Popup for showing the full list of available widgets
*/
public class WidgetsFullSheet extends BaseWidgetSheet
- implements Insettable, ProviderChangedListener, OnActivePageChangedListener {
+ implements Insettable, ProviderChangedListener, OnActivePageChangedListener,
+ WidgetsRecyclerView.HeaderViewDimensionsProvider {
private static final long DEFAULT_OPEN_DURATION = 267;
private static final long FADE_IN_DURATION = 150;
@@ -77,6 +80,10 @@
mPrimaryWidgetsFilter.negate();
@Nullable private PersonalWorkPagedView mViewPager;
+ private int mInitialTabsHeight = 0;
+ private View mTabsView;
+ private SearchAndRecommendationViewHolder mSearchAndRecommendationViewHolder;
+ private SearchAndRecommendationsScrollController mSearchAndRecommendationsScrollController;
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -98,8 +105,9 @@
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
int contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view
: R.layout.widgets_full_sheet_recyclerview;
- layoutInflater.inflate(contentLayoutRes, springLayout, true);
+ layoutInflater.inflate(contentLayoutRes, springLayout, true);
+ RecyclerViewFastScroller fastScroller = findViewById(R.id.fast_scroller);
if (mHasWorkProfile) {
mViewPager = findViewById(R.id.widgets_view_pager);
// Temporarily disable swipe gesture until widgets list horizontal scrollviews per
@@ -108,10 +116,12 @@
mViewPager.initParentViews(this);
mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.PRIMARY);
+ mTabsView = findViewById(R.id.tabs);
findViewById(R.id.tab_personal)
.setOnClickListener((View view) -> mViewPager.snapToPage(0));
findViewById(R.id.tab_work)
.setOnClickListener((View view) -> mViewPager.snapToPage(1));
+ fastScroller.setIsRecyclerViewFirstChildInParent(false);
springLayout.addSpringView(R.id.primary_widgets_list_view);
springLayout.addSpringView(R.id.work_widgets_list_view);
} else {
@@ -119,12 +129,36 @@
springLayout.addSpringView(R.id.primary_widgets_list_view);
}
+ layoutInflater.inflate(R.layout.widgets_full_sheet_search_and_recommendations, springLayout,
+ true);
+ springLayout.addSpringView(R.id.search_and_recommendations_container);
+
+ mSearchAndRecommendationViewHolder = new SearchAndRecommendationViewHolder(
+ findViewById(R.id.search_and_recommendations_container));
+ mSearchAndRecommendationsScrollController = new SearchAndRecommendationsScrollController(
+ mHasWorkProfile,
+ mSearchAndRecommendationViewHolder,
+ findViewById(R.id.primary_widgets_list_view),
+ mHasWorkProfile ? findViewById(R.id.work_widgets_list_view) : null,
+ mTabsView,
+ mViewPager);
+ fastScroller.setOnFastScrollChangeListener(mSearchAndRecommendationsScrollController);
+
onWidgetsBound();
}
@Override
public void onActivePageChanged(int currentActivePage) {
mAdapters.get(currentActivePage).mWidgetsRecyclerView.bindFastScrollbar();
+
+ reset();
+ }
+
+ private void reset() {
+ mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.scrollToTop();
+ if (mHasWorkProfile) {
+ mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView.scrollToTop();
+ }
}
@VisibleForTesting
@@ -198,8 +232,9 @@
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
- int maxSpansPerRow = getMeasuredWidth() / (deviceProfile.cellWidthPx
- + deviceProfile.workspaceCellPaddingXPx);
+ int paddingPx = 2 * getResources().getDimensionPixelOffset(
+ R.dimen.widget_cell_horizontal_padding);
+ int maxSpansPerRow = getMeasuredWidth() / (deviceProfile.cellWidthPx + paddingPx);
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
maxSpansPerRow);
if (mHasWorkProfile) {
@@ -220,6 +255,12 @@
contentLeft + contentWidth, height);
setTranslationShift(mTranslationShift);
+
+ if (mInitialTabsHeight == 0 && mTabsView != null) {
+ mInitialTabsHeight = mTabsView.getMeasuredHeight();
+ }
+
+ mSearchAndRecommendationsScrollController.updateMarginAndPadding();
}
@Override
@@ -325,6 +366,14 @@
AccessibilityManagerCompat.sendStateEventToTest(getContext(), NORMAL_STATE_ORDINAL);
}
+ @Override
+ public int getHeaderViewHeight() {
+ // No need to check work profile here because mInitialTabHeight is always 0 if there is no
+ // work profile.
+ return mInitialTabsHeight
+ + mSearchAndRecommendationViewHolder.mContainer.getMeasuredHeight();
+ }
+
/** A holder class for holding adapters & their corresponding recycler view. */
private final class AdapterHolder {
static final int PRIMARY = 0;
@@ -354,9 +403,24 @@
void setup(WidgetsRecyclerView recyclerView) {
mWidgetsRecyclerView = recyclerView;
mWidgetsRecyclerView.setAdapter(mWidgetsListAdapter);
+ mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
mWidgetsRecyclerView.setEdgeEffectFactory(
((TopRoundedCornerView) mContent).createEdgeEffectFactory());
mWidgetsListAdapter.setApplyBitmapDeferred(false, mWidgetsRecyclerView);
}
}
+
+ final class SearchAndRecommendationViewHolder {
+ final View mContainer;
+ final View mCollapseHandle;
+ final EditText mSearchBar;
+ final TextView mHeaderTitle;
+
+ SearchAndRecommendationViewHolder(View searchAndRecommendationContainer) {
+ mContainer = searchAndRecommendationContainer;
+ mCollapseHandle = mContainer.findViewById(R.id.collapse_handle);
+ mSearchBar = mContainer.findViewById(R.id.widgets_search_bar);
+ mHeaderTitle = mContainer.findViewById(R.id.title);
+ }
+ }
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index 2355700..9c8684a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -112,7 +112,9 @@
TableRow row = (TableRow) table.getChildAt(i);
row.setVisibility(View.VISIBLE);
WidgetCell widget = (WidgetCell) row.getChildAt(j);
+ widget.clear();
WidgetItem widgetItem = widgetItemsPerRow.get(j);
+ widget.setPreviewSize(widgetItem.spanX, widgetItem.spanY);
widget.applyFromCellItem(widgetItem, mWidgetPreviewLoader);
widget.setApplyBitmapDeferred(mApplyBitmapDeferred);
widget.ensurePreview();
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index 52e9496..d65a809 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -40,6 +40,7 @@
private final Point mFastScrollerOffset = new Point();
private boolean mTouchDownOnScroller;
+ private HeaderViewDimensionsProvider mHeaderViewDimensionsProvider;
public WidgetsRecyclerView(Context context) {
this(context, null);
@@ -135,8 +136,8 @@
@Override
protected int getAvailableScrollHeight() {
View child = getChildAt(0);
- return child.getMeasuredHeight() * mAdapter.getItemCount() - getScrollbarTrackHeight()
- - mScrollbarTop;
+ return child.getMeasuredHeight() * mAdapter.getItemCount() + getScrollBarTop()
+ + getPaddingBottom() - mScrollbar.getHeight();
}
private boolean isModelNotReady() {
@@ -145,7 +146,9 @@
@Override
public int getScrollBarTop() {
- return mScrollbarTop;
+ return mHeaderViewDimensionsProvider == null
+ ? mScrollbarTop
+ : mHeaderViewDimensionsProvider.getHeaderViewHeight() + mScrollbarTop;
}
@Override
@@ -171,4 +174,21 @@
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
+
+ public void setHeaderViewDimensionsProvider(
+ HeaderViewDimensionsProvider headerViewDimensionsProvider) {
+ mHeaderViewDimensionsProvider = headerViewDimensionsProvider;
+ }
+
+ /**
+ * Provides dimensions of the header view that is shown at the top of a
+ * {@link WidgetsRecyclerView}.
+ */
+ public interface HeaderViewDimensionsProvider {
+ /**
+ * Returns the height, in pixels, of the header view that is shown at the top of a
+ * {@link WidgetsRecyclerView}.
+ */
+ int getHeaderViewHeight();
+ }
}
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index a7e3472..a8c7c48 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -17,7 +17,6 @@
import com.android.launcher3.AppFilter;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.AlphabeticIndexCompat;
import com.android.launcher3.config.FeatureFlags;
@@ -27,6 +26,7 @@
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index f243f27..744dee0 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -98,7 +98,7 @@
<activity
android:name="com.android.launcher3.testcomponent.TestLauncherActivity"
android:clearTaskOnLaunch="true"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout"
android:enabled="false"
android:label="Test launcher"
android:launchMode="singleTask"
diff --git a/tests/src/com/android/launcher3/ui/TestViewHelpers.java b/tests/src/com/android/launcher3/ui/TestViewHelpers.java
index eceff34..083f580 100644
--- a/tests/src/com/android/launcher3/ui/TestViewHelpers.java
+++ b/tests/src/com/android/launcher3/ui/TestViewHelpers.java
@@ -24,9 +24,9 @@
import android.view.View;
import android.view.ViewGroup;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.testcomponent.AppWidgetNoConfig;
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
import java.util.concurrent.Callable;
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index aef26ae..5e41d43d 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -154,9 +154,12 @@
Log.d(TestProtocol.WORK_PROFILE_REMOVED, "Work tab not setup. Skipping test");
return false;
}
- return ((AllAppsPagedView) l.getAppsView().getContentView()).getCurrentPage()
- == WORK_PAGE && ((TextView) workEduView.findViewById(
- R.id.content_text)).getText().equals(
+ if (((AllAppsPagedView) l.getAppsView().getContentView()).getCurrentPage()
+ != WORK_PAGE) {
+ Log.d(TestProtocol.WORK_PROFILE_REMOVED, "Work page not highlighted");
+ return false;
+ }
+ return ((TextView) workEduView.findViewById(R.id.content_text)).getText().equals(
l.getResources().getString(R.string.work_profile_edu_work_apps));
}, 60000);
}
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 737f891..b421b0e 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -28,7 +28,6 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Workspace;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -39,6 +38,7 @@
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.Wait.Condition;
import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import org.junit.Before;
import org.junit.Rule;
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index f146db5..714b11b 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -23,12 +23,12 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.tapl.Widget;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import org.junit.Rule;
import org.junit.Test;
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index fa495f5..9c6c317 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -37,7 +37,6 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -47,6 +46,7 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
import org.junit.After;
diff --git a/tests/src_common/com/android/launcher3/common/WidgetUtils.java b/tests/src_common/com/android/launcher3/common/WidgetUtils.java
index c0913bf..ffad93f 100644
--- a/tests/src_common/com/android/launcher3/common/WidgetUtils.java
+++ b/tests/src_common/com/android/launcher3/common/WidgetUtils.java
@@ -23,12 +23,12 @@
import android.content.Context;
import android.os.Bundle;
-import com.android.launcher3.LauncherAppWidgetHost;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.ContentWriter;
+import com.android.launcher3.widget.LauncherAppWidgetHost;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 3fc83ff..c4a566b 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -67,7 +67,7 @@
() -> "Launching an app didn't open a new window: " + label);
mLauncher.assertTrue(
- "App didn't start: " + label,
+ "App didn't start: " + label + " (" + selector + ")",
TestHelpers.wait(Until.hasObject(selector), LauncherInstrumentation.WAIT_TIME_MS));
return new Background(mLauncher);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 6afadfa..f279a82 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -365,9 +365,11 @@
if (hasSystemUiObject("keyguard_status_view")) return "Phone is locked";
- if (!mDevice.hasObject(By.textStartsWith(""))) return "Screen is empty";
+ if (!mDevice.wait(Until.hasObject(By.textStartsWith("")), WAIT_TIME_MS)) {
+ return "Screen is empty";
+ }
- final String navigationModeError = getNavigationModeMismatchError();
+ final String navigationModeError = getNavigationModeMismatchError(true);
if (navigationModeError != null) return navigationModeError;
} catch (Throwable e) {
Log.w(TAG, "getSystemAnomalyMessage failed", e);
@@ -535,17 +537,28 @@
mExpectedRotation = expectedRotation;
}
- public String getNavigationModeMismatchError() {
+ public String getNavigationModeMismatchError(boolean waitForCorrectState) {
+ final int waitTime = waitForCorrectState ? WAIT_TIME_MS : 0;
final NavigationModel navigationModel = getNavigationModel();
- final boolean hasRecentsButton = hasSystemUiObject("recent_apps");
- final boolean hasHomeButton = hasSystemUiObject("home");
- if ((navigationModel == NavigationModel.THREE_BUTTON) != hasRecentsButton) {
- return "Presence of recents button doesn't match the interaction mode, mode="
- + navigationModel.name() + ", hasRecents=" + hasRecentsButton;
+
+ if (navigationModel == NavigationModel.THREE_BUTTON) {
+ if (!mDevice.wait(Until.hasObject(By.res(SYSTEMUI_PACKAGE, "recent_apps")), waitTime)) {
+ return "Recents button not present in 3-button mode";
+ }
+ } else {
+ if (!mDevice.wait(Until.gone(By.res(SYSTEMUI_PACKAGE, "recent_apps")), waitTime)) {
+ return "Recents button is present in non-3-button mode";
+ }
}
- if ((navigationModel != NavigationModel.ZERO_BUTTON) != hasHomeButton) {
- return "Presence of home button doesn't match the interaction mode, mode="
- + navigationModel.name() + ", hasHome=" + hasHomeButton;
+
+ if (navigationModel == NavigationModel.ZERO_BUTTON) {
+ if (!mDevice.wait(Until.gone(By.res(SYSTEMUI_PACKAGE, "home")), waitTime)) {
+ return "Home button is present in gestural mode";
+ }
+ } else {
+ if (!mDevice.wait(Until.hasObject(By.res(SYSTEMUI_PACKAGE, "home")), waitTime)) {
+ return "Home button not present in non-gestural mode";
+ }
}
return null;
}
@@ -556,7 +569,7 @@
assertEquals("Unexpected display rotation",
mExpectedRotation, mDevice.getDisplayRotation());
- final String error = getNavigationModeMismatchError();
+ final String error = getNavigationModeMismatchError(true);
assertTrue(error, error == null);
log("verifyContainerType: " + containerType);
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index f0e686f..d43e235 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -110,7 +110,8 @@
TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT).
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
LauncherInstrumentation.log(
- "switchToAllApps: swipeHeight = " + swipeHeight + ", slop = "
+ "switchToAllApps: deviceHeight = " + deviceHeight + ", startY = " + startY
+ + ", swipeHeight = " + swipeHeight + ", slop = "
+ mLauncher.getTouchSlop());
mLauncher.swipeToState(