Adding SecondaryDisplayLauncher in Launcher using common listener
Bug: 141596722
Change-Id: I480bfadf592f7d0309f17c33a3fe14bb77fb5586
diff --git a/Android.mk b/Android.mk
index 3a9a2c3..a099ada 100644
--- a/Android.mk
+++ b/Android.mk
@@ -78,9 +78,8 @@
LOCAL_USE_AAPT2 := true
LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- Launcher3CommonDepsLib \
- SecondaryDisplayLauncherLib
+LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
+
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
$(call all-java-files-under, src_shortcuts_overrides) \
@@ -154,9 +153,7 @@
endif
LOCAL_MODULE := Launcher3QuickStepLib
LOCAL_PRIVILEGED_MODULE := true
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- Launcher3CommonDepsLib \
- SecondaryDisplayLauncherLib
+LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 555cc73..26698eb 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -184,5 +184,20 @@
android:writePermission="android.permission.WRITE_SECURE_SETTINGS"
android:exported="true"
android:enabled="false" />
+
+ <!--
+ Launcher activity for secondary display
+ -->
+ <activity
+ android:name="com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher"
+ android:theme="@style/AppTheme"
+ android:launchMode="singleTop"
+ android:enabled="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SECONDARY_HOME" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/res/drawable/bg_all_apps_button.xml b/res/drawable/bg_all_apps_button.xml
new file mode 100644
index 0000000..169a468
--- /dev/null
+++ b/res/drawable/bg_all_apps_button.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="oval" >
+ <solid android:color="#ffffffff" />
+ </shape>
+ </item>
+
+ <item>
+ <shape android:shape="oval" >
+ <solid android:color="?android:attr/colorAccent" />
+ </shape>
+ </item>
+</ripple>
diff --git a/res/drawable/ic_apps.xml b/res/drawable/ic_apps.xml
new file mode 100644
index 0000000..db779c2
--- /dev/null
+++ b/res/drawable/ic_apps.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector android:height="24dp" android:tint="#FFFFFF"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF000000" android:pathData="M4,8h4L8,4L4,4v4zM10,20h4v-4h-4v4zM4,20h4v-4L4,16v4zM4,14h4v-4L4,10v4zM10,14h4v-4h-4v4zM16,4v4h4L20,4h-4zM10,8h4L14,4h-4v4zM16,14h4v-4h-4v4zM16,20h4v-4h-4v4z"/>
+</vector>
diff --git a/quickstep/res/drawable/ic_pin.xml b/res/drawable/ic_pin.xml
similarity index 100%
rename from quickstep/res/drawable/ic_pin.xml
rename to res/drawable/ic_pin.xml
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 9427ae0..0da51d9 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -16,7 +16,7 @@
<!-- The top and bottom paddings are defined in this container, but since we want
the list view to span the full width (for touch interception purposes), we
will bake the left/right padding into that view's background itself. -->
-<com.android.launcher3.allapps.AllAppsContainerView
+<com.android.launcher3.allapps.LauncherAllAppsContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/apps_view"
android:layout_width="match_parent"
@@ -79,4 +79,4 @@
layout="@layout/search_container_all_apps"/>
<include layout="@layout/all_apps_fast_scroller" />
-</com.android.launcher3.allapps.AllAppsContainerView>
\ No newline at end of file
+</com.android.launcher3.allapps.LauncherAllAppsContainerView>
\ No newline at end of file
diff --git a/res/layout/secondary_launcher.xml b/res/layout/secondary_launcher.xml
new file mode 100644
index 0000000..98cfc34
--- /dev/null
+++ b/res/layout/secondary_launcher.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.secondarydisplay.SecondaryDragLayer
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/drag_layer" >
+
+ <GridView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginBottom="100dp"
+ android:theme="@style/HomeScreenElementTheme"
+ android:layout_gravity="center_horizontal|top"
+ android:layout_margin="@dimen/dynamic_grid_edge_margin"
+ android:id="@+id/workspace_grid" />
+
+ <ImageButton
+ android:id="@+id/all_apps_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_margin="40dp"
+ android:padding="16dp"
+ android:src="@drawable/ic_apps"
+ android:background="@drawable/bg_all_apps_button"
+ android:contentDescription="@string/all_apps_button_label"
+ android:onClick="onAppsButtonClicked" />
+
+ <com.android.launcher3.allapps.AllAppsContainerView
+ android:id="@+id/apps_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="true"
+ android:clipToPadding="false"
+ android:focusable="false"
+ android:saveEnabled="false"
+ android:layout_gravity="bottom|end"
+ android:background="@drawable/round_rect_primary"
+ android:elevation="2dp"
+ android:visibility="invisible" >
+
+ <include
+ layout="@layout/all_apps_rv_layout"
+ android:visibility="gone" />
+
+ <com.android.launcher3.allapps.FloatingHeaderView
+ android:id="@+id/all_apps_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/search_container_all_apps"
+ android:clipToPadding="false"
+ android:paddingTop="@dimen/all_apps_header_top_padding"
+ android:orientation="vertical" >
+
+ <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/all_apps_header_tab_height"
+ android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
+ android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
+ android:orientation="horizontal"
+ style="@style/TextHeadline">
+
+ <Button
+ android:id="@+id/tab_personal"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:text="@string/all_apps_personal_tab"
+ android:textAllCaps="true"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp" />
+
+ <Button
+ android:id="@+id/tab_work"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:text="@string/all_apps_work_tab"
+ android:textAllCaps="true"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp" />
+ </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
+ </com.android.launcher3.allapps.FloatingHeaderView>
+
+ <com.android.launcher3.allapps.search.AppsSearchContainerLayout
+ android:id="@id/search_container_all_apps"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/all_apps_search_bar_field_height"
+ android:layout_centerHorizontal="true"
+ android:layout_gravity="top|center_horizontal"
+ android:background="@drawable/bg_all_apps_searchbox"
+ android:elevation="1dp"
+ android:focusableInTouchMode="true"
+ android:gravity="center"
+ android:hint="@string/all_apps_search_bar_hint"
+ android:imeOptions="actionSearch|flagNoExtractUi"
+ android:inputType="text|textNoSuggestions|textCapWords"
+ android:maxLines="1"
+ android:padding="8dp"
+ android:saveEnabled="false"
+ android:scrollHorizontally="true"
+ android:singleLine="true"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textColorHint="@drawable/all_apps_search_hint"
+ android:textSize="16sp"
+ android:translationY="24dp" />
+
+ <include layout="@layout/all_apps_fast_scroller" />
+ </com.android.launcher3.allapps.AllAppsContainerView>
+</com.android.launcher3.secondarydisplay.SecondaryDragLayer>
\ No newline at end of file
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 0283eac..dda38b3 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -29,6 +29,7 @@
import android.util.Log;
import android.view.ActionMode;
import android.view.View;
+import android.view.View.OnClickListener;
import android.widget.Toast;
import androidx.annotation.Nullable;
@@ -36,6 +37,7 @@
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.uioverrides.DisplayRotationListener;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.util.PackageManagerHelper;
@@ -262,5 +264,9 @@
}
}
+ public OnClickListener getItemOnClickListener() {
+ return ItemClickHandler.INSTANCE;
+ }
+
protected abstract void reapplyUi();
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index bc6fa6e..0d71da4 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -245,7 +245,7 @@
allAppsIconTextSizePx = originalProfile.iconTextSizePx;
allAppsCellHeightPx = originalProfile.allAppsCellHeightPx;
allAppsIconDrawablePaddingPx = originalProfile.iconDrawablePaddingOriginalPx;
- allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx;
+ allAppsCellWidthPx = allAppsIconSizePx + 2 * allAppsIconDrawablePaddingPx;
}
updateWorkspacePadding();
@@ -360,7 +360,7 @@
allAppsIconTextSizePx = iconTextSizePx;
allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
allAppsCellHeightPx = getCellSize().y;
- allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx;
+ allAppsCellWidthPx = allAppsIconSizePx + 2 * allAppsIconDrawablePaddingPx;
if (isVerticalBarLayout()) {
// Always hide the Workspace text with vertical bar layout.
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 9d87152..a807e4f 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -18,8 +18,8 @@
import static com.android.launcher3.Utilities.getDevicePrefs;
import static com.android.launcher3.config.FeatureFlags.APPLY_CONFIG_AT_RUNTIME;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.settings.SettingsActivity.GRID_OPTIONS_PREFERENCE_KEY;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
import android.annotation.TargetApi;
@@ -41,6 +41,7 @@
import android.util.SparseArray;
import android.util.TypedValue;
import android.util.Xml;
+import android.view.Display;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -48,6 +49,7 @@
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.DefaultDisplay.Info;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Themes;
@@ -172,6 +174,13 @@
}
/**
+ * This constructor should NOT have any monitors by design.
+ */
+ public InvariantDeviceProfile(Context context, Display display) {
+ initGrid(context, null, new Info(display));
+ }
+
+ /**
* Retrieve system defined or RRO overriden icon shape.
*/
private static String getIconShapePath(Context context) {
@@ -183,8 +192,10 @@
}
private String initGrid(Context context, String gridName) {
- DefaultDisplay.Info displayInfo = DefaultDisplay.INSTANCE.get(context).getInfo();
+ return initGrid(context, gridName, DefaultDisplay.INSTANCE.get(context).getInfo());
+ }
+ private String initGrid(Context context, String gridName, DefaultDisplay.Info displayInfo) {
Point smallestSize = new Point(displayInfo.smallestSize);
Point largestSize = new Point(displayInfo.largestSize);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index fe987bc..445ebc0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -371,7 +371,7 @@
mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);
setupViews();
- mPopupDataProvider = new PopupDataProvider(this);
+ mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
mAppTransitionManager = LauncherAppTransitionManager.newInstance(this);
mAppTransitionManager.registerRemoteAnimations();
@@ -1344,7 +1344,7 @@
}
};
- public void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
+ private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
mWorkspace.updateNotificationDots(updatedDots);
mAppsView.getAppsStore().updateNotificationDots(updatedDots);
}
@@ -1807,7 +1807,6 @@
// Note: There should be at most one log per method call. This is enforced implicitly
// by using if-else statements.
- UserEventDispatcher ued = getUserEventDispatcher();
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
if (topView != null && topView.onBackPressed()) {
// Handled by the floating view.
@@ -1875,6 +1874,7 @@
}
}
+ @Override
public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
@Nullable String sourceContainer) {
if (!hasBeenResumed()) {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 27668eb..6f15c9b 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -40,6 +40,7 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.AppInfo;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.DragSource;
@@ -47,9 +48,6 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.keyboard.FocusedItemDecorator;
@@ -61,7 +59,6 @@
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
-import com.android.launcher3.views.WorkEduView;
/**
* The all apps view container.
@@ -74,8 +71,8 @@
private static final float FLING_ANIMATION_THRESHOLD = 0.55f;
private static final int ALPHA_CHANNEL_COUNT = 2;
- private final Launcher mLauncher;
- private final AdapterHolder[] mAH;
+ protected final BaseDraggingActivity mLauncher;
+ protected final AdapterHolder[] mAH;
private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
private final ItemInfoMatcher mWorkMatcher = ItemInfoMatcher.not(mPersonalMatcher);
private final AllAppsStore mAllAppsStore = new AllAppsStore();
@@ -83,18 +80,16 @@
private final Paint mNavBarScrimPaint;
private int mNavBarScrimHeight = 0;
- private SearchUiManager mSearchUiManager;
+ protected SearchUiManager mSearchUiManager;
private View mSearchContainer;
private AllAppsPagedView mViewPager;
private FloatingHeaderView mHeader;
private SpannableStringBuilder mSearchQueryBuilder = null;
- private boolean mUsingTabs;
+ protected boolean mUsingTabs;
private boolean mSearchModeWhileUsingTabs = false;
- private LauncherStateManager.StateListener mWorkTabListener;
-
private RecyclerViewFastScroller mTouchHandler;
private final Point mFastScrollerOffset = new Point();
@@ -111,7 +106,7 @@
public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
+ mLauncher = BaseDraggingActivity.fromContext(context);
mLauncher.addOnDeviceProfileChangeListener(this);
mSearchQueryBuilder = new SpannableStringBuilder();
@@ -133,6 +128,15 @@
mMultiValueAlpha = new MultiValueAlpha(this, ALPHA_CHANNEL_COUNT);
}
+ /**
+ * Sets the long click listener for icons
+ */
+ public void setOnIconLongClickListener(OnLongClickListener listener) {
+ for (AdapterHolder holder : mAH) {
+ holder.adapter.setOnIconLongClickListener(listener);
+ }
+ }
+
public AllAppsStore getAppsStore() {
return mAllAppsStore;
}
@@ -193,11 +197,6 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
-
- // The AllAppsContainerView houses the QSB and is hence visible from the Workspace
- // Overview states. We shouldn't intercept for the scrubber in these cases.
- if (!mLauncher.isInState(LauncherState.ALL_APPS)) return false;
-
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
AllAppsRecyclerView rv = getActiveRecyclerView();
if (rv != null &&
@@ -309,7 +308,6 @@
+ grid.cellLayoutPaddingLeftRightPx;
for (int i = 0; i < mAH.length; i++) {
- mAH[i].adapter.setAppsPerRow(grid.inv.numAllAppsColumns);
mAH[i].padding.bottom = insets.bottom;
mAH[i].padding.left = mAH[i].padding.right = leftRightPadding;
mAH[i].applyPadding();
@@ -327,8 +325,6 @@
setLayoutParams(mlp);
InsettableFrameLayout.dispatchInsets(this, insets);
- mLauncher.getAllAppsController()
- .setScrollRangeDelta(mSearchUiManager.getScrollRangeDelta(insets));
}
@Override
@@ -375,7 +371,6 @@
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
onTabChanged(mViewPager.getNextPage());
- mWorkTabListener = WorkEduView.showEduFlowIfNeeded(mLauncher, mWorkTabListener);
} else {
mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
mAH[AdapterHolder.WORK].recyclerView = null;
@@ -421,9 +416,6 @@
.setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.MAIN));
findViewById(R.id.tab_work)
.setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.WORK));
- if (pos == AdapterHolder.WORK) {
- WorkEduView.showWorkEduIfNeeded(mLauncher);
- }
}
}
@@ -588,7 +580,7 @@
appsList.updateItemFilter(matcher);
recyclerView = (AllAppsRecyclerView) rv;
recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
- recyclerView.setApps(appsList, mUsingTabs);
+ recyclerView.setApps(appsList);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 80ea1eb..442b77b 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -15,17 +15,22 @@
*/
package com.android.launcher3.allapps;
+import static com.android.launcher3.touch.ItemLongClickListener.INSTANCE_ALL_APPS;
+
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
+import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
+import androidx.annotation.Nullable;
import androidx.core.view.accessibility.AccessibilityEventCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityRecordCompat;
@@ -33,14 +38,12 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.AppInfo;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.touch.ItemClickHandler;
-import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.PackageManagerHelper;
import java.util.List;
@@ -174,23 +177,26 @@
}
}
- private final Launcher mLauncher;
+ private final BaseDraggingActivity mLauncher;
private final LayoutInflater mLayoutInflater;
private final AlphabeticalAppsList mApps;
private final GridLayoutManager mGridLayoutMgr;
private final GridSpanSizer mGridSizer;
+ private final OnClickListener mOnIconClickListener;
+ private OnLongClickListener mOnIconLongClickListener = INSTANCE_ALL_APPS;
+
private int mAppsPerRow;
private BindViewCallback mBindViewCallback;
private OnFocusChangeListener mIconFocusListener;
// The text to show when there are no search results and no market search handler.
- private String mEmptySearchMessage;
+ protected String mEmptySearchMessage;
// The intent to send off to the market app, updated each time the search query changes.
private Intent mMarketSearchIntent;
- public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps) {
+ public AllAppsGridAdapter(BaseDraggingActivity launcher, AlphabeticalAppsList apps) {
Resources res = launcher.getResources();
mLauncher = launcher;
mApps = apps;
@@ -200,6 +206,8 @@
mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
mLayoutInflater = LayoutInflater.from(launcher);
+ mOnIconClickListener = launcher.getItemOnClickListener();
+
setAppsPerRow(mLauncher.getDeviceProfile().inv.numAllAppsColumns);
}
@@ -208,6 +216,13 @@
mGridLayoutMgr.setSpanCount(mAppsPerRow);
}
+ /**
+ * Sets the long click listener for icons
+ */
+ public void setOnIconLongClickListener(@Nullable OnLongClickListener listener) {
+ mOnIconLongClickListener = listener;
+ }
+
public static boolean isDividerViewType(int viewType) {
return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
}
@@ -254,8 +269,8 @@
case VIEW_TYPE_ICON:
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
R.layout.all_apps_icon, parent, false);
- icon.setOnClickListener(ItemClickHandler.INSTANCE);
- icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);
+ icon.setOnClickListener(mOnIconClickListener);
+ icon.setOnLongClickListener(mOnIconLongClickListener);
icon.setLongPressTimeoutFactor(1f);
icon.setOnFocusChangeListener(mIconFocusListener);
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index f82e380..b6744cf 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -28,14 +28,13 @@
import androidx.recyclerview.widget.RecyclerView;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager;
-import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -84,7 +83,7 @@
/**
* Sets the list of apps in this view, used to determine the fastscroll position.
*/
- public void setApps(AlphabeticalAppsList apps, boolean usingTabs) {
+ public void setApps(AlphabeticalAppsList apps) {
mApps = apps;
mFastScrollHelper = new AllAppsFastScrollHelper(this, apps);
}
@@ -94,7 +93,7 @@
}
private void updatePoolSize() {
- DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
+ DeviceProfile grid = BaseDraggingActivity.fromContext(getContext()).getDeviceProfile();
RecyclerView.RecycledViewPool pool = getRecycledViewPool();
int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH, 1);
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 10e2821..a33fe4d 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -21,7 +21,7 @@
import android.content.pm.PackageManager;
import com.android.launcher3.AppInfo;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -126,7 +126,7 @@
}
}
- private final Launcher mLauncher;
+ private final BaseDraggingActivity mLauncher;
// The set of apps from the system
private final List<AppInfo> mApps = new ArrayList<>();
@@ -151,7 +151,7 @@
public AlphabeticalAppsList(Context context, AllAppsStore appsStore, boolean isWork) {
mAllAppsStore = appsStore;
- mLauncher = Launcher.getLauncher(context);
+ mLauncher = BaseDraggingActivity.fromContext(context);
mAppNameComparator = new AppInfoComparator(context);
mIsWork = isWork;
mNumAppsPerRow = mLauncher.getDeviceProfile().inv.numColumns;
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 42a0eee..cc33af9 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -31,9 +31,9 @@
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
@@ -393,7 +393,7 @@
@Override
public void setInsets(Rect insets) {
- DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
+ DeviceProfile grid = BaseDraggingActivity.fromContext(getContext()).getDeviceProfile();
for (FloatingHeaderRow row : mAllRows) {
row.setInsets(insets, grid);
}
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
new file mode 100644
index 0000000..9d0ecd3
--- /dev/null
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.views.WorkEduView;
+
+/**
+ * AllAppsContainerView with launcher specific callbacks
+ */
+public class LauncherAllAppsContainerView extends AllAppsContainerView {
+
+ private final Launcher mLauncher;
+
+ private LauncherStateManager.StateListener mWorkTabListener;
+
+ public LauncherAllAppsContainerView(Context context) {
+ this(context, null);
+ }
+
+ public LauncherAllAppsContainerView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public LauncherAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = Launcher.getLauncher(context);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ // The AllAppsContainerView houses the QSB and is hence visible from the Workspace
+ // Overview states. We shouldn't intercept for the scrubber in these cases.
+ if (!mLauncher.isInState(LauncherState.ALL_APPS)) return false;
+
+ return super.onInterceptTouchEvent(ev);
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ super.setInsets(insets);
+ mLauncher.getAllAppsController()
+ .setScrollRangeDelta(mSearchUiManager.getScrollRangeDelta(insets));
+ }
+
+ @Override
+ public void onTabChanged(int pos) {
+ super.onTabChanged(pos);
+ if (mUsingTabs) {
+ if (pos == AdapterHolder.WORK) {
+ WorkEduView.showWorkEduIfNeeded(mLauncher);
+ } else {
+ mWorkTabListener = WorkEduView.showEduFlowIfNeeded(mLauncher, mWorkTabListener);
+ }
+ }
+ }
+}
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index decdcc0..6204f31 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -24,15 +24,14 @@
import android.widget.Button;
import android.widget.LinearLayout;
-import com.android.launcher3.Launcher;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.util.Themes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
/**
* Supports two indicator colors, dedicated for personal and work tabs.
*/
@@ -73,7 +72,7 @@
mDividerPaint.setStrokeWidth(
getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height));
- mSharedPreferences = Launcher.getLauncher(getContext()).getSharedPrefs();
+ mSharedPreferences = Utilities.getPrefs(context);
mIsRtl = Utilities.isRtl(getResources());
}
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 4515dde..ed45749 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -25,8 +25,8 @@
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ExtendedEditText;
-import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.util.ComponentKey;
@@ -41,7 +41,7 @@
implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
OnFocusChangeListener {
- protected Launcher mLauncher;
+ protected BaseDraggingActivity mLauncher;
protected Callbacks mCb;
protected ExtendedEditText mInput;
protected String mQuery;
@@ -56,7 +56,7 @@
*/
public final void initialize(
SearchAlgorithm searchAlgorithm, ExtendedEditText input,
- Launcher launcher, Callbacks cb) {
+ BaseDraggingActivity launcher, Callbacks cb) {
mCb = cb;
mLauncher = launcher;
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 31fcc8c..d497c3a 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -26,8 +26,6 @@
import android.content.Context;
import android.graphics.Rect;
import android.text.Selection;
-import android.text.Spannable;
-import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.method.TextKeyListener;
import android.util.AttributeSet;
@@ -36,18 +34,16 @@
import android.view.ViewGroup.MarginLayoutParams;
import android.view.animation.Interpolator;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.AlphabeticalAppsList;
import com.android.launcher3.allapps.SearchUiManager;
import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.util.ComponentKey;
import java.util.ArrayList;
@@ -59,8 +55,7 @@
implements SearchUiManager, AllAppsSearchBarController.Callbacks,
AllAppsStore.OnUpdateListener, Insettable {
-
- private final Launcher mLauncher;
+ private final BaseDraggingActivity mLauncher;
private final AllAppsSearchBarController mSearchBarController;
private final SpannableStringBuilder mSearchQueryBuilder;
@@ -82,7 +77,7 @@
public AppsSearchContainerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
+ mLauncher = BaseDraggingActivity.fromContext(context);
mSearchBarController = new AllAppsSearchBarController();
mSearchQueryBuilder = new SpannableStringBuilder();
@@ -97,13 +92,13 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mLauncher.getAppsView().getAppsStore().addUpdateListener(this);
+ mAppsView.getAppsStore().addUpdateListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mLauncher.getAppsView().getAppsStore().removeUpdateListener(this);
+ mAppsView.getAppsStore().removeUpdateListener(this);
}
@Override
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 98f7fd8..d9bd714 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -40,8 +40,8 @@
import android.widget.FrameLayout;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.InsettableFrameLayout;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -57,14 +57,16 @@
/**
* A container for shortcuts to deep links and notifications associated with an app.
+ *
+ * @param <T> The activity on with the popup shows
*/
-public abstract class ArrowPopup extends AbstractFloatingView {
+public abstract class ArrowPopup<T extends BaseDraggingActivity> extends AbstractFloatingView {
private final Rect mTempRect = new Rect();
protected final LayoutInflater mInflater;
private final float mOutlineRadius;
- protected final Launcher mLauncher;
+ protected final T mLauncher;
protected final boolean mIsRtl;
private final int mArrowOffset;
@@ -83,7 +85,7 @@
super(context, attrs, defStyleAttr);
mInflater = LayoutInflater.from(context);
mOutlineRadius = Themes.getDialogCornerRadius(context);
- mLauncher = Launcher.getLauncher(context);
+ mLauncher = BaseDraggingActivity.fromContext(context);
mIsRtl = Utilities.isRtl(getResources());
setClipToOutline(true);
@@ -120,16 +122,22 @@
}
}
- public <T extends View> T inflateAndAdd(int resId, ViewGroup container) {
+ /**
+ * Utility method for inflating and adding a view
+ */
+ public <R extends View> R inflateAndAdd(int resId, ViewGroup container) {
View view = mInflater.inflate(resId, container, false);
container.addView(view);
- return (T) view;
+ return (R) view;
}
- public <T extends View> T inflateAndAdd(int resId, ViewGroup container, int index) {
+ /**
+ * Utility method for inflating and adding a view
+ */
+ public <R extends View> R inflateAndAdd(int resId, ViewGroup container, int index) {
View view = mInflater.inflate(resId, container, false);
container.addView(view, index);
- return (T) view;
+ return (R) view;
}
/**
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index b764a07..05ea694 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -44,6 +44,7 @@
import android.widget.ImageView;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget;
@@ -65,7 +66,6 @@
import com.android.launcher3.popup.PopupDataProvider.PopupDataChangeListener;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
-import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.ShortcutUtil;
@@ -74,22 +74,22 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* A container for shortcuts to deep links and notifications associated with an app.
+ *
+ * @param <T> The activity on with the popup shows
*/
-public class PopupContainerWithArrow extends ArrowPopup implements DragSource,
- DragController.DragListener, View.OnLongClickListener,
- View.OnTouchListener, PopupDataChangeListener {
+public class PopupContainerWithArrow<T extends BaseDraggingActivity> extends ArrowPopup<T>
+ implements DragSource, DragController.DragListener {
private final List<DeepShortcutView> mShortcuts = new ArrayList<>();
private final PointF mInterceptTouchDown = new PointF();
- protected final Point mIconLastTouchPos = new Point();
private final int mStartDragThreshold;
- private final LauncherAccessibilityDelegate mAccessibilityDelegate;
private BubbleTextView mOriginalIcon;
private NotificationItemView mNotificationItemView;
@@ -97,11 +97,13 @@
private ViewGroup mSystemShortcutContainer;
+ protected PopupItemDragHandler mPopupItemDragHandler;
+ protected LauncherAccessibilityDelegate mAccessibilityDelegate;
+
public PopupContainerWithArrow(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mStartDragThreshold = getResources().getDimensionPixelSize(
R.dimen.deep_shortcuts_start_drag_threshold);
- mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(mLauncher);
}
public PopupContainerWithArrow(Context context, AttributeSet attrs) {
@@ -117,18 +119,6 @@
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mLauncher.getPopupDataProvider().setChangeListener(this);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mLauncher.getPopupDataProvider().setChangeListener(null);
- }
-
- @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mInterceptTouchDown.set(ev.getX(), ev.getY());
@@ -168,11 +158,15 @@
public OnClickListener getItemClickListener() {
return (view) -> {
- ItemClickHandler.INSTANCE.onClick(view);
+ mLauncher.getItemOnClickListener().onClick(view);
close(true);
};
}
+ public PopupItemDragHandler getItemDragHandler() {
+ return mPopupItemDragHandler;
+ }
+
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
@@ -201,18 +195,35 @@
icon.clearFocus();
return null;
}
- ItemInfo itemInfo = (ItemInfo) icon.getTag();
- if (!ShortcutUtil.supportsShortcuts(itemInfo)) {
+ ItemInfo item = (ItemInfo) icon.getTag();
+ if (!ShortcutUtil.supportsShortcuts(item)) {
return null;
}
final PopupContainerWithArrow container =
(PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
R.layout.popup_container, launcher.getDragLayer(), false);
- container.populateAndShow(icon, itemInfo);
+ container.configureForLauncher(launcher);
+
+ PopupDataProvider popupDataProvider = launcher.getPopupDataProvider();
+ container.populateAndShow(icon,
+ popupDataProvider.getShortcutCountForItem(item),
+ popupDataProvider.getNotificationKeysForItem(item),
+ launcher.getSupportedShortcuts()
+ .map(s -> s.getShortcut(launcher, item))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList()));
+ launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
return container;
}
+ private void configureForLauncher(Launcher launcher) {
+ addOnAttachStateChangeListener(new LiveUpdateHandler(launcher));
+ mPopupItemDragHandler = new LauncherPopupItemDragHandler(launcher, this);
+ mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(launcher);
+ launcher.getDragController().addDragListener(this);
+ }
+
@Override
protected void onInflationComplete(boolean isReversed) {
if (isReversed && mNotificationItemView != null) {
@@ -234,23 +245,8 @@
}
}
- protected void populateAndShow(BubbleTextView icon, ItemInfo item) {
- PopupDataProvider popupDataProvider = mLauncher.getPopupDataProvider();
- populateAndShow(icon,
- popupDataProvider.getShortcutCountForItem(item),
- popupDataProvider.getNotificationKeysForItem(item),
- mLauncher.getSupportedShortcuts()
- .map(s -> s.getShortcut(mLauncher, item))
- .filter(s -> s != null)
- .collect(Collectors.toList()));
- }
-
- public ViewGroup getSystemShortcutContainerForTesting() {
- return mSystemShortcutContainer;
- }
-
@TargetApi(Build.VERSION_CODES.P)
- protected void populateAndShow(final BubbleTextView originalIcon, int shortcutCount,
+ public void populateAndShow(final BubbleTextView originalIcon, int shortcutCount,
final List<NotificationKeyData> notificationKeys, List<SystemShortcut> systemShortcuts) {
mNumNotifications = notificationKeys.size();
mOriginalIcon = originalIcon;
@@ -316,7 +312,6 @@
setAccessibilityPaneTitle(getTitleForAccessibility());
}
- mLauncher.getDragController().addDragListener(this);
mOriginalIcon.setForceHideDot(true);
// All views are added. Animate layout from now on.
@@ -390,44 +385,6 @@
}
}
- @Override
- public void onWidgetsBound() {
- ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag();
- SystemShortcut widgetInfo = SystemShortcut.WIDGETS.getShortcut(mLauncher, itemInfo);
- View widgetsView = null;
- int count = mSystemShortcutContainer.getChildCount();
- for (int i = 0; i < count; i++) {
- View systemShortcutView = mSystemShortcutContainer.getChildAt(i);
- if (systemShortcutView.getTag() instanceof SystemShortcut.Widgets) {
- widgetsView = systemShortcutView;
- break;
- }
- }
-
- if (widgetInfo != null && widgetsView == null) {
- // We didn't have any widgets cached but now there are some, so enable the shortcut.
- if (mSystemShortcutContainer != this) {
- initializeSystemShortcut(
- R.layout.system_shortcut_icon_only, mSystemShortcutContainer, widgetInfo);
- } else {
- // If using the expanded system shortcut (as opposed to just the icon), we need to
- // reopen the container to ensure measurements etc. all work out. While this could
- // be quite janky, in practice the user would typically see a small flicker as the
- // animation restarts partway through, and this is a very rare edge case anyway.
- close(false);
- PopupContainerWithArrow.showForIcon(mOriginalIcon);
- }
- } else if (widgetInfo == null && widgetsView != null) {
- // No widgets exist, but we previously added the shortcut so remove it.
- if (mSystemShortcutContainer != this) {
- mSystemShortcutContainer.removeView(widgetsView);
- } else {
- close(false);
- PopupContainerWithArrow.showForIcon(mOriginalIcon);
- }
- }
- }
-
private void initializeSystemShortcut(int resId, ViewGroup container, SystemShortcut info) {
View view = inflateAndAdd(
resId, container, getInsertIndexForSystemShortcut(container, info));
@@ -498,18 +455,6 @@
};
}
- /**
- * Updates the notification header if the original icon's dot updated.
- */
- @Override
- public void onNotificationDotsUpdated(Predicate<PackageUserKey> updatedDots) {
- ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag();
- PackageUserKey packageUser = PackageUserKey.fromItemInfo(itemInfo);
- if (updatedDots.test(packageUser)) {
- updateNotificationHeader();
- }
- }
-
private void updateNotificationHeader() {
ItemInfoWithIcon itemInfo = (ItemInfoWithIcon) mOriginalIcon.getTag();
DotInfo dotInfo = mLauncher.getDotInfoForItem(itemInfo);
@@ -520,25 +465,6 @@
}
@Override
- public void trimNotifications(Map<PackageUserKey, DotInfo> updatedDots) {
- if (mNotificationItemView == null) {
- return;
- }
- ItemInfo originalInfo = (ItemInfo) mOriginalIcon.getTag();
- DotInfo dotInfo = updatedDots.get(PackageUserKey.fromItemInfo(originalInfo));
- if (dotInfo == null || dotInfo.getNotificationKeys().size() == 0) {
- // No more notifications, remove the notification views and expand all shortcuts.
- mNotificationItemView.removeAllViews();
- mNotificationItemView = null;
- updateHiddenShortcuts();
- updateDividers();
- } else {
- mNotificationItemView.trimNotifications(
- NotificationKeyData.extractKeysOnly(dotInfo.getNotificationKeys()));
- }
- }
-
- @Override
public void onDropCompleted(View target, DragObject d, boolean success) { }
@Override
@@ -592,47 +518,164 @@
super.closeComplete();
}
- @Override
- public boolean onTouch(View v, MotionEvent ev) {
- // Touched a shortcut, update where it was touched so we can drag from there on long click.
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- mIconLastTouchPos.set((int) ev.getX(), (int) ev.getY());
- break;
- }
- return false;
- }
-
- @Override
- public boolean onLongClick(View v) {
- if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
- // Return early if not the correct view
- if (!(v.getParent() instanceof DeepShortcutView)) return false;
-
- // Long clicked on a shortcut.
- DeepShortcutView sv = (DeepShortcutView) v.getParent();
- sv.setWillDrawIcon(false);
-
- // Move the icon to align with the center-top of the touch point
- Point iconShift = new Point();
- iconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x;
- iconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx;
-
- DragView dv = mLauncher.getWorkspace().beginDragShared(sv.getIconView(),
- this, sv.getFinalInfo(),
- new ShortcutDragPreviewProvider(sv.getIconView(), iconShift), new DragOptions());
- dv.animateShift(-iconShift.x, -iconShift.y);
-
- // TODO: support dragging from within folder without having to close it
- AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_FOLDER);
- return false;
- }
-
/**
* Returns a PopupContainerWithArrow which is already open or null
*/
- public static PopupContainerWithArrow getOpen(Launcher launcher) {
+ public static PopupContainerWithArrow getOpen(BaseDraggingActivity launcher) {
return getOpenView(launcher, TYPE_ACTION_POPUP);
}
+
+ /**
+ * Utility class to handle updates while the popup is visible (like widgets and
+ * notification changes)
+ */
+ private class LiveUpdateHandler implements
+ PopupDataChangeListener, View.OnAttachStateChangeListener {
+
+ private final Launcher mLauncher;
+
+ LiveUpdateHandler(Launcher launcher) {
+ mLauncher = launcher;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View view) {
+ mLauncher.getPopupDataProvider().setChangeListener(this);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View view) {
+ mLauncher.getPopupDataProvider().setChangeListener(null);
+ }
+
+ @Override
+ public void onWidgetsBound() {
+ ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag();
+ SystemShortcut widgetInfo = SystemShortcut.WIDGETS.getShortcut(mLauncher, itemInfo);
+ View widgetsView = null;
+ int count = mSystemShortcutContainer.getChildCount();
+ for (int i = 0; i < count; i++) {
+ View systemShortcutView = mSystemShortcutContainer.getChildAt(i);
+ if (systemShortcutView.getTag() instanceof SystemShortcut.Widgets) {
+ widgetsView = systemShortcutView;
+ break;
+ }
+ }
+
+ if (widgetInfo != null && widgetsView == null) {
+ // We didn't have any widgets cached but now there are some, so enable the shortcut.
+ if (mSystemShortcutContainer != PopupContainerWithArrow.this) {
+ initializeSystemShortcut(R.layout.system_shortcut_icon_only,
+ mSystemShortcutContainer, widgetInfo);
+ } else {
+ // If using the expanded system shortcut (as opposed to just the icon), we need
+ // to reopen the container to ensure measurements etc. all work out. While this
+ // could be quite janky, in practice the user would typically see a small
+ // flicker as the animation restarts partway through, and this is a very rare
+ // edge case anyway.
+ close(false);
+ PopupContainerWithArrow.showForIcon(mOriginalIcon);
+ }
+ } else if (widgetInfo == null && widgetsView != null) {
+ // No widgets exist, but we previously added the shortcut so remove it.
+ if (mSystemShortcutContainer != PopupContainerWithArrow.this) {
+ mSystemShortcutContainer.removeView(widgetsView);
+ } else {
+ close(false);
+ PopupContainerWithArrow.showForIcon(mOriginalIcon);
+ }
+ }
+ }
+
+ /**
+ * Updates the notification header if the original icon's dot updated.
+ */
+ @Override
+ public void onNotificationDotsUpdated(Predicate<PackageUserKey> updatedDots) {
+ ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag();
+ PackageUserKey packageUser = PackageUserKey.fromItemInfo(itemInfo);
+ if (updatedDots.test(packageUser)) {
+ updateNotificationHeader();
+ }
+ }
+
+
+ @Override
+ public void trimNotifications(Map<PackageUserKey, DotInfo> updatedDots) {
+ if (mNotificationItemView == null) {
+ return;
+ }
+ ItemInfo originalInfo = (ItemInfo) mOriginalIcon.getTag();
+ DotInfo dotInfo = updatedDots.get(PackageUserKey.fromItemInfo(originalInfo));
+ if (dotInfo == null || dotInfo.getNotificationKeys().size() == 0) {
+ // No more notifications, remove the notification views and expand all shortcuts.
+ mNotificationItemView.removeAllViews();
+ mNotificationItemView = null;
+ updateHiddenShortcuts();
+ updateDividers();
+ } else {
+ mNotificationItemView.trimNotifications(
+ NotificationKeyData.extractKeysOnly(dotInfo.getNotificationKeys()));
+ }
+ }
+ }
+
+ /**
+ * Handler to control drag-and-drop for popup items
+ */
+ public interface PopupItemDragHandler extends OnLongClickListener, OnTouchListener { }
+
+ /**
+ * Drag and drop handler for popup items in Launcher activity
+ */
+ public static class LauncherPopupItemDragHandler implements PopupItemDragHandler {
+
+ protected final Point mIconLastTouchPos = new Point();
+ private final Launcher mLauncher;
+ private final PopupContainerWithArrow mContainer;
+
+ LauncherPopupItemDragHandler(Launcher launcher, PopupContainerWithArrow container) {
+ mLauncher = launcher;
+ mContainer = container;
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent ev) {
+ // Touched a shortcut, update where it was touched so we can drag from there on
+ // long click.
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ mIconLastTouchPos.set((int) ev.getX(), (int) ev.getY());
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
+ // Return early if not the correct view
+ if (!(v.getParent() instanceof DeepShortcutView)) return false;
+
+ // Long clicked on a shortcut.
+ DeepShortcutView sv = (DeepShortcutView) v.getParent();
+ sv.setWillDrawIcon(false);
+
+ // Move the icon to align with the center-top of the touch point
+ Point iconShift = new Point();
+ iconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x;
+ iconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx;
+
+ DragView dv = mLauncher.getWorkspace().beginDragShared(sv.getIconView(),
+ mContainer, sv.getFinalInfo(),
+ new ShortcutDragPreviewProvider(sv.getIconView(), iconShift),
+ new DragOptions());
+ dv.animateShift(-iconShift.x, -iconShift.y);
+
+ // TODO: support dragging from within folder without having to close it
+ AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_FOLDER);
+ return false;
+ }
+ }
}
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index c5aa836..1092c7b 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -24,7 +24,6 @@
import androidx.annotation.Nullable;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.notification.NotificationKeyData;
@@ -41,6 +40,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -52,7 +52,7 @@
private static final boolean LOGD = false;
private static final String TAG = "PopupDataProvider";
- private final Launcher mLauncher;
+ private final Consumer<Predicate<PackageUserKey>> mNotificationDotsChangeListener;
/** Maps launcher activity components to a count of how many shortcuts they have. */
private HashMap<ComponentKey, Integer> mDeepShortcutMap = new HashMap<>();
@@ -63,12 +63,12 @@
private PopupDataChangeListener mChangeListener = PopupDataChangeListener.INSTANCE;
- public PopupDataProvider(Launcher launcher) {
- mLauncher = launcher;
+ public PopupDataProvider(Consumer<Predicate<PackageUserKey>> notificationDotsChangeListener) {
+ mNotificationDotsChangeListener = notificationDotsChangeListener;
}
private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
- mLauncher.updateNotificationDots(updatedDots);
+ mNotificationDotsChangeListener.accept(updatedDots);
mChangeListener.onNotificationDotsUpdated(updatedDots);
}
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index 947f49d..9faeb40 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -24,8 +24,8 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.notification.NotificationInfo;
@@ -33,7 +33,6 @@
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutRequest;
-import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
import java.util.Collections;
@@ -123,7 +122,11 @@
return filteredShortcuts;
}
- public static Runnable createUpdateRunnable(final Launcher launcher, final ItemInfo originalInfo,
+ /**
+ * Returns a runnable to update the provided shortcuts and notifications
+ */
+ public static Runnable createUpdateRunnable(final BaseDraggingActivity launcher,
+ final ItemInfo originalInfo,
final Handler uiHandler, final PopupContainerWithArrow container,
final List<DeepShortcutView> shortcutViews,
final List<NotificationKeyData> notificationKeys) {
@@ -162,11 +165,6 @@
final DeepShortcutView view = shortcutViews.get(i);
uiHandler.post(() -> view.applyShortcutInfo(si, shortcut, container));
}
-
- // This ensures that mLauncher.getWidgetsForPackageUser()
- // doesn't return null (it puts all the widgets in memory).
- uiHandler.post(() -> launcher.refreshAndBindWidgetsForPackageUser(
- PackageUserKey.fromItemInfo(originalInfo)));
};
}
}
diff --git a/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java b/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java
new file mode 100644
index 0000000..54b7fb9
--- /dev/null
+++ b/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.secondarydisplay;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import android.content.ComponentName;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.Process;
+import android.os.UserHandle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsStore;
+import com.android.launcher3.allapps.AppInfoComparator;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Executors;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * Adapter to manage pinned apps and show then in a grid.
+ */
+public class PinnedAppsAdapter extends BaseAdapter implements OnSharedPreferenceChangeListener {
+
+ private static final String PINNED_APPS_KEY = "pinned_apps";
+
+ private final SecondaryDisplayLauncher mLauncher;
+ private final OnClickListener mOnClickListener;
+ private final OnLongClickListener mOnLongClickListener;
+ private final SharedPreferences mPrefs;
+ private final AllAppsStore mAllAppsList;
+ private final AppInfoComparator mAppNameComparator;
+
+ private final Set<ComponentKey> mPinnedApps = new HashSet<>();
+ private final ArrayList<AppInfo> mItems = new ArrayList<>();
+
+ public PinnedAppsAdapter(SecondaryDisplayLauncher launcher, AllAppsStore allAppsStore,
+ OnLongClickListener onLongClickListener) {
+ mLauncher = launcher;
+ mOnClickListener = launcher.getItemOnClickListener();
+ mOnLongClickListener = onLongClickListener;
+ mAllAppsList = allAppsStore;
+ mPrefs = launcher.getSharedPreferences(PINNED_APPS_KEY, MODE_PRIVATE);
+ mAppNameComparator = new AppInfoComparator(launcher);
+
+ mAllAppsList.addUpdateListener(this::createFilteredAppsList);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+ if (PINNED_APPS_KEY.equals(key)) {
+ Executors.MODEL_EXECUTOR.submit(() -> {
+ Set<ComponentKey> apps = prefs.getStringSet(key, Collections.emptySet())
+ .stream()
+ .map(this::parseComponentKey)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+ Executors.MAIN_EXECUTOR.submit(() -> {
+ mPinnedApps.clear();
+ mPinnedApps.addAll(apps);
+ createFilteredAppsList();
+ });
+ });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getCount() {
+ return mItems.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AppInfo getItem(int position) {
+ return mItems.get(position);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ BubbleTextView icon;
+ if (view instanceof BubbleTextView) {
+ icon = (BubbleTextView) view;
+ } else {
+ icon = (BubbleTextView) LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.app_icon, parent, false);
+ icon.setOnClickListener(mOnClickListener);
+ icon.setOnLongClickListener(mOnLongClickListener);
+ icon.setLongPressTimeoutFactor(1f);
+ int padding = mLauncher.getDeviceProfile().edgeMarginPx;
+ icon.setPadding(padding, padding, padding, padding);
+ }
+
+ icon.applyFromApplicationInfo(mItems.get(position));
+ return icon;
+ }
+
+ private void createFilteredAppsList() {
+ mItems.clear();
+ mPinnedApps.stream().map(mAllAppsList::getApp)
+ .filter(Objects::nonNull).forEach(mItems::add);
+ mItems.sort(mAppNameComparator);
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Initialized the pinned apps list and starts listening for changes
+ */
+ public void init() {
+ mPrefs.registerOnSharedPreferenceChangeListener(this);
+ onSharedPreferenceChanged(mPrefs, PINNED_APPS_KEY);
+ }
+
+ /**
+ * Stops listening for any pinned apps changes
+ */
+ public void destroy() {
+ mPrefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ private void update(ItemInfo info, Function<ComponentKey, Boolean> op) {
+ ComponentKey key = new ComponentKey(info.getTargetComponent(), info.user);
+ if (op.apply(key)) {
+ createFilteredAppsList();
+ Set<ComponentKey> copy = new HashSet<>(mPinnedApps);
+ Executors.MODEL_EXECUTOR.submit(() ->
+ mPrefs.edit().putStringSet(PINNED_APPS_KEY,
+ copy.stream().map(this::encode).collect(Collectors.toSet()))
+ .apply());
+ }
+ }
+
+ private ComponentKey parseComponentKey(String string) {
+ try {
+ String[] parts = string.split("#");
+ UserHandle user;
+ if (parts.length > 2) {
+ user = UserCache.INSTANCE.get(mLauncher)
+ .getUserForSerialNumber(Long.parseLong(parts[2]));
+ } else {
+ user = Process.myUserHandle();
+ }
+ ComponentName cn = ComponentName.unflattenFromString(parts[0]);
+ return new ComponentKey(cn, user);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private String encode(ComponentKey key) {
+ return key.componentName.flattenToShortString() + "#"
+ + UserCache.INSTANCE.get(mLauncher).getSerialNumberForUser(key.user);
+ }
+
+ /**
+ * Returns a system shortcut to pin/unpin a shortcut
+ */
+ public SystemShortcut getSystemShortcut(ItemInfo info) {
+ return new PinUnPinShortcut(mLauncher, info,
+ mPinnedApps.contains(new ComponentKey(info.getTargetComponent(), info.user)));
+ }
+
+ private class PinUnPinShortcut extends SystemShortcut<SecondaryDisplayLauncher> {
+
+ private final boolean mIsPinned;
+
+ PinUnPinShortcut(SecondaryDisplayLauncher target, ItemInfo info, boolean isPinned) {
+ super(isPinned ? R.drawable.ic_remove_no_shadow : R.drawable.ic_pin,
+ isPinned ? R.string.remove_drop_target_label : R.string.action_add_to_workspace,
+ target, info);
+ mIsPinned = isPinned;
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (mIsPinned) {
+ update(mItemInfo, mPinnedApps::remove);
+ } else {
+ update(mItemInfo, mPinnedApps::add);
+ }
+ AbstractFloatingView.closeAllOpenViews(mLauncher);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
new file mode 100644
index 0000000..1cc01f4
--- /dev/null
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.secondarydisplay;
+
+import static com.android.launcher3.model.AppLaunchTracker.CONTAINER_ALL_APPS;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewAnimationUtils;
+import android.view.inputmethod.InputMethodManager;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.PromiseAppInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.WorkspaceItemInfo;
+import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.util.ViewOnDrawExecutor;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.widget.WidgetListRowEntry;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Launcher activity for secondary displays
+ */
+public class SecondaryDisplayLauncher extends BaseDraggingActivity
+ implements BgDataModel.Callbacks {
+
+ private LauncherModel mModel;
+
+ private BaseDragLayer mDragLayer;
+ private AllAppsContainerView mAppsView;
+ private View mAppsButton;
+
+ private PopupDataProvider mPopupDataProvider;
+
+ private boolean mAppDrawerShown = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mModel = LauncherAppState.getInstance(this).getModel();
+ if (getWindow().getDecorView().isAttachedToWindow()) {
+ initUi();
+ }
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ initUi();
+ }
+
+ private void initUi() {
+ if (mDragLayer != null) {
+ return;
+ }
+ InvariantDeviceProfile mainIdp = LauncherAppState.getIDP(this);
+ InvariantDeviceProfile currentDisplayIdp =
+ new InvariantDeviceProfile(this, getWindow().getDecorView().getDisplay());
+
+ // Pick the device profile with the smaller icon size so that the cached icons are
+ // shown properly
+ if (mainIdp.iconBitmapSize <= currentDisplayIdp.iconBitmapSize) {
+ mDeviceProfile = mainIdp.getDeviceProfile(this).copy(this);
+ } else {
+ mDeviceProfile = currentDisplayIdp.getDeviceProfile(this);
+ }
+
+ setContentView(R.layout.secondary_launcher);
+ mDragLayer = findViewById(R.id.drag_layer);
+ mAppsView = findViewById(R.id.apps_view);
+ mAppsButton = findViewById(R.id.all_apps_button);
+
+ mPopupDataProvider = new PopupDataProvider(
+ mAppsView.getAppsStore()::updateNotificationDots);
+
+ mModel.addCallbacksAndLoad(this);
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+
+ if (Intent.ACTION_MAIN.equals(intent.getAction())) {
+ // Hide keyboard.
+ final View v = getWindow().peekDecorView();
+ if (v != null && v.getWindowToken() != null) {
+ getSystemService(InputMethodManager.class).hideSoftInputFromWindow(
+ v.getWindowToken(), 0);
+ }
+ }
+
+ // A new intent will bring the launcher to top. Hide the app drawer to reset the state.
+ showAppDrawer(false);
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (finishAutoCancelActionMode()) {
+ return;
+ }
+
+ // Note: There should be at most one log per method call. This is enforced implicitly
+ // by using if-else statements.
+ AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
+ if (topView != null && topView.onBackPressed()) {
+ // Handled by the floating view.
+ } else {
+ showAppDrawer(false);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mModel.removeCallbacks(this);
+ }
+
+ public boolean isAppDrawerShown() {
+ return mAppDrawerShown;
+ }
+
+ public AllAppsContainerView getAppsView() {
+ return mAppsView;
+ }
+
+ @Override
+ public <T extends View> T getOverviewPanel() {
+ return null;
+ }
+
+ @Override
+ public View getRootView() {
+ return mDragLayer;
+ }
+
+ @Override
+ public ActivityOptions getActivityLaunchOptions(View v) {
+ return null;
+ }
+
+ @Override
+ protected void reapplyUi() { }
+
+ @Override
+ public BaseDragLayer getDragLayer() {
+ return mDragLayer;
+ }
+
+ @Override
+ public int getPageToBindSynchronously() {
+ return 0;
+ }
+
+ @Override
+ public void clearPendingBinds() { }
+
+ @Override
+ public void startBinding() { }
+
+ @Override
+ public void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons) { }
+
+ @Override
+ public void bindScreens(IntArray orderedScreenIds) { }
+
+ @Override
+ public void finishFirstPageBind(ViewOnDrawExecutor executor) {
+ if (executor != null) {
+ executor.onLoadAnimationCompleted();
+ }
+ }
+
+ @Override
+ public void finishBindingItems(int pageBoundFirst) { }
+
+ @Override
+ public void preAddApps() { }
+
+ @Override
+ public void bindAppsAdded(IntArray newScreens, ArrayList<ItemInfo> addNotAnimated,
+ ArrayList<ItemInfo> addAnimated) { }
+
+ @Override
+ public void bindPromiseAppProgressUpdated(PromiseAppInfo app) {
+ mAppsView.getAppsStore().updatePromiseAppProgress(app);
+ }
+
+ @Override
+ public void bindWorkspaceItemsChanged(ArrayList<WorkspaceItemInfo> updated) { }
+
+ @Override
+ public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) { }
+
+ @Override
+ public void bindRestoreItemsChange(HashSet<ItemInfo> updates) { }
+
+ @Override
+ public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) { }
+
+ @Override
+ public void bindAllWidgets(ArrayList<WidgetListRowEntry> widgets) { }
+
+ @Override
+ public void onPageBoundSynchronously(int page) { }
+
+ @Override
+ public void executeOnNextDraw(ViewOnDrawExecutor executor) {
+ executor.attachTo(getDragLayer(), false, null);
+ }
+
+ /**
+ * Called when apps-button is clicked
+ */
+ public void onAppsButtonClicked(View v) {
+ showAppDrawer(true);
+ }
+
+ /**
+ * Show/hide app drawer card with animation.
+ */
+ public void showAppDrawer(boolean show) {
+ if (show == mAppDrawerShown) {
+ return;
+ }
+
+ float openR = (float) Math.hypot(mAppsView.getWidth(), mAppsView.getHeight());
+ float closeR = Themes.getDialogCornerRadius(this);
+ float startR = mAppsButton.getWidth() / 2f;
+
+ float[] buttonPos = new float[] { startR, startR};
+ mDragLayer.getDescendantCoordRelativeToSelf(mAppsButton, buttonPos);
+ mDragLayer.mapCoordInSelfToDescendant(mAppsView, buttonPos);
+ final Animator animator = ViewAnimationUtils.createCircularReveal(mAppsView,
+ (int) buttonPos[0], (int) buttonPos[1],
+ show ? closeR : openR, show ? openR : closeR);
+
+ if (show) {
+ mAppDrawerShown = true;
+ mAppsView.setVisibility(View.VISIBLE);
+ mAppsButton.setVisibility(View.INVISIBLE);
+ } else {
+ mAppDrawerShown = false;
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAppsView.setVisibility(View.INVISIBLE);
+ mAppsButton.setVisibility(View.VISIBLE);
+ mAppsView.getSearchUiManager().resetSearch();
+ }
+ });
+ }
+ animator.start();
+ }
+
+ @Override
+ public void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMap) {
+ mPopupDataProvider.setDeepShortcutMap(deepShortcutMap);
+ }
+
+ @Override
+ public void bindAllApplications(AppInfo[] apps) {
+ mAppsView.getAppsStore().setApps(apps);
+ }
+
+ public PopupDataProvider getPopupDataProvider() {
+ return mPopupDataProvider;
+ }
+
+ @Override
+ public OnClickListener getItemOnClickListener() {
+ return this::onIconClicked;
+ }
+
+ private void onIconClicked(View v) {
+ // Make sure that rogue clicks don't get through while allapps is launching, or after the
+ // view has detached (it's possible for this to happen if the view is removed mid touch).
+ if (v.getWindowToken() == null) return;
+
+ Object tag = v.getTag();
+ if (tag instanceof ItemInfo) {
+ ItemInfo item = (ItemInfo) tag;
+ Intent intent;
+ if (item instanceof PromiseAppInfo) {
+ PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
+ intent = promiseAppInfo.getMarketIntent(this);
+ } else {
+ intent = item.getIntent();
+ }
+ if (intent == null) {
+ throw new IllegalArgumentException("Input must have a valid intent");
+ }
+ startActivitySafely(v, intent, item, CONTAINER_ALL_APPS);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
new file mode 100644
index 0000000..8fffee8
--- /dev/null
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.secondarydisplay;
+
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.GridView;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.util.ShortcutUtil;
+import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.BaseDragLayer;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * DragLayer for Secondary launcher
+ */
+public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> {
+
+ private View mAllAppsButton;
+ private AllAppsContainerView mAppsView;
+
+ private GridView mWorkspace;
+ private PinnedAppsAdapter mPinnedAppsAdapter;
+
+ public SecondaryDragLayer(Context context, AttributeSet attrs) {
+ super(context, attrs, 1 /* alphaChannelCount */);
+ mControllers = new TouchController[] {new CloseAllAppsTouchController()};
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mAllAppsButton = findViewById(R.id.all_apps_button);
+
+ mAppsView = findViewById(R.id.apps_view);
+ mAppsView.setOnIconLongClickListener(this::onIconLongClicked);
+
+ // Setup workspace
+ mWorkspace = findViewById(R.id.workspace_grid);
+ mPinnedAppsAdapter = new PinnedAppsAdapter(mActivity, mAppsView.getAppsStore(),
+ this::onIconLongClicked);
+ mWorkspace.setAdapter(mPinnedAppsAdapter);
+ mWorkspace.setNumColumns(mActivity.getDeviceProfile().inv.numColumns);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mPinnedAppsAdapter.init();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mPinnedAppsAdapter.destroy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ setMeasuredDimension(width, height);
+
+ DeviceProfile grid = mActivity.getDeviceProfile();
+ InvariantDeviceProfile idp = grid.inv;
+
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child == mAppsView) {
+ int padding = 2 * (grid.desiredWorkspaceLeftRightMarginPx
+ + grid.cellLayoutPaddingLeftRightPx);
+ int maxWidth = grid.allAppsCellWidthPx * idp.numAllAppsColumns + padding;
+
+ int appsWidth = Math.min(width, maxWidth);
+ int appsHeight = Math.round(appsWidth * (float) height / (float) width);
+
+ mAppsView.measure(
+ makeMeasureSpec(appsWidth, EXACTLY), makeMeasureSpec(appsHeight, EXACTLY));
+
+ } else if (child == mAllAppsButton) {
+ int appsButtonSpec = makeMeasureSpec(grid.iconSizePx, EXACTLY);
+ mAllAppsButton.measure(appsButtonSpec, appsButtonSpec);
+
+ } else if (child == mWorkspace) {
+ measureChildWithMargins(mWorkspace, widthMeasureSpec, 0, heightMeasureSpec,
+ grid.iconSizePx + grid.edgeMarginPx);
+
+ } else {
+ measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+ }
+ }
+ }
+
+ private class CloseAllAppsTouchController implements TouchController {
+
+ @Override
+ public boolean onControllerTouchEvent(MotionEvent ev) {
+ return false;
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (!mActivity.isAppDrawerShown()) {
+ return false;
+ }
+
+ if (AbstractFloatingView.getTopOpenView(mActivity) != null) {
+ return false;
+ }
+
+ if (ev.getAction() == MotionEvent.ACTION_DOWN
+ && !isEventOverView(mActivity.getAppsView(), ev)) {
+ mActivity.showAppDrawer(false);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private boolean onIconLongClicked(View v) {
+ if (!(v instanceof BubbleTextView)) {
+ return false;
+ }
+ if (PopupContainerWithArrow.getOpen(mActivity) != null) {
+ // There is already an items container open, so don't open this one.
+ v.clearFocus();
+ return false;
+ }
+ ItemInfo item = (ItemInfo) v.getTag();
+ if (!ShortcutUtil.supportsShortcuts(item)) {
+ return false;
+ }
+ final PopupContainerWithArrow container =
+ (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
+ R.layout.popup_container, mActivity.getDragLayer(), false);
+
+ container.populateAndShow((BubbleTextView) v,
+ mActivity.getPopupDataProvider().getShortcutCountForItem(item),
+ Collections.emptyList(),
+ Arrays.asList(mPinnedAppsAdapter.getSystemShortcut(item),
+ APP_INFO.getShortcut(mActivity, item)));
+ v.getParent().requestDisallowInterceptTouchEvent(true);
+ return true;
+ }
+}
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 9274d44..9cc7d8f 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -27,8 +27,8 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
-import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.Utilities;
+import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
/**
@@ -111,8 +111,8 @@
// TODO: Add the click handler to this view directly and not the child view.
mBubbleText.setOnClickListener(container.getItemClickListener());
- mBubbleText.setOnLongClickListener(container);
- mBubbleText.setOnTouchListener(container);
+ mBubbleText.setOnLongClickListener(container.getItemDragHandler());
+ mBubbleText.setOnTouchListener(container.getItemDragHandler());
}
/**
diff --git a/src/com/android/launcher3/util/DefaultDisplay.java b/src/com/android/launcher3/util/DefaultDisplay.java
index 8529d50..d3dac04 100644
--- a/src/com/android/launcher3/util/DefaultDisplay.java
+++ b/src/com/android/launcher3/util/DefaultDisplay.java
@@ -128,8 +128,10 @@
public final DisplayMetrics metrics;
private Info(Context context) {
- Display display = context.getSystemService(WindowManager.class).getDefaultDisplay();
+ this(context.getSystemService(WindowManager.class).getDefaultDisplay());
+ }
+ public Info(Display display) {
id = display.getDisplayId();
rotation = display.getRotation();
diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
index 451ae28..82e24c2 100644
--- a/src/com/android/launcher3/util/ViewOnDrawExecutor.java
+++ b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
@@ -29,6 +29,7 @@
import java.util.ArrayList;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* An executor which runs all the tasks after the first onDraw is called on the target view.
@@ -38,7 +39,7 @@
private final ArrayList<Runnable> mTasks = new ArrayList<>();
- private Launcher mLauncher;
+ private Consumer<ViewOnDrawExecutor> mOnClearCallback;
private View mAttachedView;
private boolean mCompleted;
@@ -46,11 +47,16 @@
private boolean mFirstDrawCompleted;
public void attachTo(Launcher launcher) {
- attachTo(launcher, launcher.getWorkspace(), true /* waitForLoadAnimation */);
+ attachTo(launcher.getWorkspace(), true /* waitForLoadAnimation */,
+ launcher::clearPendingExecutor);
}
- public void attachTo(Launcher launcher, View attachedView, boolean waitForLoadAnimation) {
- mLauncher = launcher;
+ /**
+ * Attached the executor to the existence of the view
+ */
+ public void attachTo(View attachedView, boolean waitForLoadAnimation,
+ Consumer<ViewOnDrawExecutor> onClearCallback) {
+ mOnClearCallback = onClearCallback;
mAttachedView = attachedView;
mAttachedView.addOnAttachStateChangeListener(this);
if (!waitForLoadAnimation) {
@@ -110,8 +116,8 @@
mAttachedView.getViewTreeObserver().removeOnDrawListener(this);
mAttachedView.removeOnAttachStateChangeListener(this);
}
- if (mLauncher != null) {
- mLauncher.clearPendingExecutor(this);
+ if (mOnClearCallback != null) {
+ mOnClearCallback.accept(this);
}
MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 5ba931d..880f123 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -126,7 +126,8 @@
popup.mTargetRect = targetRect;
for (OptionItem item : items) {
- DeepShortcutView view = popup.inflateAndAdd(R.layout.system_shortcut, popup);
+ DeepShortcutView view =
+ (DeepShortcutView) popup.inflateAndAdd(R.layout.system_shortcut, popup);
view.getIconView().setBackgroundResource(item.mIconRes);
view.getBubbleText().setText(item.mLabelRes);
view.setDividerVisibility(View.INVISIBLE);
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index f713b33..f055adf 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -104,7 +104,7 @@
}
private void setContainerWidth() {
- mCellSize = (int) (mDeviceProfile.allAppsCellWidthPx * WIDTH_SCALE);
+ mCellSize = (int) (mDeviceProfile.cellWidthPx * WIDTH_SCALE);
mPresetPreviewSize = (int) (mCellSize * PREVIEW_SCALE);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index ede5bd9..8659aa7 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -24,6 +24,8 @@
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiObject2;
+import com.android.launcher3.tapl.LauncherInstrumentation.GestureScope;
+
import java.util.Collection;
/**
@@ -93,7 +95,7 @@
int i = 0;
for (; ; ) {
final Collection<UiObject2> cells = mLauncher.getObjectsInContainer(
- widgetsContainer, "widgets_cell_list_container");
+ widgetsContainer, "widgets_scroll_container");
mLauncher.assertTrue("Widgets doesn't have 2 rows", cells.size() >= 2);
for (UiObject2 cell : cells) {
final UiObject2 label = cell.findObject(labelSelector);
@@ -105,6 +107,19 @@
"com.android.launcher3.widget.WidgetCell",
widget.getClassName());
+ int maxWidth = 0;
+ for (UiObject2 sibling : widget.getParent().getChildren()) {
+ maxWidth = Math.max(sibling.getVisibleBounds().width(), maxWidth);
+ }
+
+ int visibleDelta = maxWidth - widget.getVisibleBounds().width();
+ if (visibleDelta > 0) {
+ Rect parentBounds = cell.getVisibleBounds();
+ mLauncher.linearGesture(parentBounds.centerX() + visibleDelta,
+ parentBounds.centerY(), parentBounds.centerX(),
+ parentBounds.centerY(), 10, true, GestureScope.INSIDE);
+ }
+
if (widget.getVisibleBounds().bottom
<= displaySize.y - mLauncher.getBottomGestureSize()) {
return new Widget(mLauncher, widget);