Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 94d5d3cb authored by Andy Wickham's avatar Andy Wickham
Browse files

Support for animating A-Z <-> Search.

Demo videos (1/5 speed) and APK: https://drive.google.com/drive/folders/1qQNzcoibiFMzxYhvXc7UEHCaBhJg6SjN?resourcekey=0-OWD06iLXg3wf_eWce4rUPA&usp=sharing

Bug: 234882587
Bug: 243688989
Test: Manually tested a bunch of cases at 1/10 animation speed.
Such as work profile or not, suggested apps enabled/disabled,
typing during the animation, going back during the animation,
web results injected above apps, etc.

Change-Id: Id4f1a858d387bf3a7f9cf2d23564a276544abef1
parent 3426372f
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -20,6 +20,8 @@
    android:layout_width="match_parent"
    android:layout_width="match_parent"
    android:layout_height="@dimen/all_apps_header_pill_height"
    android:layout_height="@dimen/all_apps_header_pill_height"
    android:layout_gravity="center_horizontal"
    android:layout_gravity="center_horizontal"
    android:paddingTop="@dimen/all_apps_tabs_vertical_padding"
    android:paddingBottom="@dimen/all_apps_tabs_vertical_padding"
    android:orientation="horizontal"
    android:orientation="horizontal"
    style="@style/TextHeadline">
    style="@style/TextHeadline">


@@ -28,7 +30,6 @@
        android:layout_width="0dp"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_height="match_parent"
        android:layout_marginEnd="@dimen/all_apps_tabs_button_horizontal_padding"
        android:layout_marginEnd="@dimen/all_apps_tabs_button_horizontal_padding"
        android:layout_marginVertical="@dimen/all_apps_tabs_vertical_padding"
        android:layout_weight="1"
        android:layout_weight="1"
        android:background="@drawable/all_apps_tabs_background"
        android:background="@drawable/all_apps_tabs_background"
        android:text="@string/all_apps_personal_tab"
        android:text="@string/all_apps_personal_tab"
@@ -41,7 +42,6 @@
        android:layout_width="0dp"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="@dimen/all_apps_tabs_button_horizontal_padding"
        android:layout_marginStart="@dimen/all_apps_tabs_button_horizontal_padding"
        android:layout_marginVertical="@dimen/all_apps_tabs_vertical_padding"
        android:layout_weight="1"
        android:layout_weight="1"
        android:background="@drawable/all_apps_tabs_background"
        android:background="@drawable/all_apps_tabs_background"
        android:text="@string/all_apps_work_tab"
        android:text="@string/all_apps_work_tab"
+1 −1
Original line number Original line Diff line number Diff line
@@ -18,7 +18,7 @@
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/search_results_list_view"
    android:id="@+id/search_results_list_view"
    android:layout_width="match_parent"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:clipToPadding="false"
    android:descendantFocusability="afterDescendants"
    android:descendantFocusability="afterDescendants"
    android:focusable="true" />
    android:focusable="true" />
+1 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@
    android:textColor="@color/all_apps_tab_text"
    android:textColor="@color/all_apps_tab_text"
    android:textSize="14sp"
    android:textSize="14sp"
    android:background="@drawable/work_apps_toggle_background"
    android:background="@drawable/work_apps_toggle_background"
    android:forceHasOverlappingRendering="false"
    android:drawablePadding="8dp"
    android:drawablePadding="8dp"
    android:drawableStart="@drawable/ic_corp_off"
    android:drawableStart="@drawable/ic_corp_off"
    android:layout_marginBottom="@dimen/work_fab_margin_bottom"
    android:layout_marginBottom="@dimen/work_fab_margin_bottom"
+65 −24
Original line number Original line Diff line number Diff line
@@ -15,6 +15,8 @@
 */
 */
package com.android.launcher3.allapps;
package com.android.launcher3.allapps;


import static com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder.SEARCH;

import android.content.Context;
import android.content.Context;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.KeyEvent;
@@ -34,7 +36,6 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.views.AppLauncher;
import com.android.launcher3.views.AppLauncher;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Objects;


/**
/**
 * All apps container view with search support for use in a dragging activity.
 * All apps container view with search support for use in a dragging activity.
@@ -44,6 +45,11 @@ import java.util.Objects;
public class ActivityAllAppsContainerView<T extends Context & AppLauncher
public class ActivityAllAppsContainerView<T extends Context & AppLauncher
        & DeviceProfileListenable> extends BaseAllAppsContainerView<T> {
        & DeviceProfileListenable> extends BaseAllAppsContainerView<T> {


    private static final long DEFAULT_SEARCH_TRANSITION_DURATION_MS = 300;

    // Used to animate Search results out and A-Z apps in, or vice-versa.
    private final SearchTransitionController mSearchTransitionController;

    protected SearchUiManager mSearchUiManager;
    protected SearchUiManager mSearchUiManager;
    /**
    /**
     * View that defines the search box. Result is rendered inside the recycler view defined in the
     * View that defines the search box. Result is rendered inside the recycler view defined in the
@@ -52,6 +58,7 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher
    private View mSearchContainer;
    private View mSearchContainer;
    /** {@code true} when rendered view is in search state instead of the scroll state. */
    /** {@code true} when rendered view is in search state instead of the scroll state. */
    private boolean mIsSearching;
    private boolean mIsSearching;
    private boolean mRebindAdaptersAfterSearchAnimation;


    public ActivityAllAppsContainerView(Context context) {
    public ActivityAllAppsContainerView(Context context) {
        this(context, null);
        this(context, null);
@@ -63,6 +70,8 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher


    public ActivityAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
    public ActivityAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        super(context, attrs, defStyleAttr);

        mSearchTransitionController = new SearchTransitionController(this);
    }
    }


    public SearchUiManager getSearchUiManager() {
    public SearchUiManager getSearchUiManager() {
@@ -73,19 +82,10 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher
        return mSearchContainer;
        return mSearchContainer;
    }
    }


    /** Updates all apps container with the latest search query. */
    public void setLastSearchQuery(String query) {
        mIsSearching = true;
        rebindAdapters();
        mHeader.setCollapsed(true);
    }

    /** Invoke when the current search session is finished. */
    /** Invoke when the current search session is finished. */
    public void onClearSearchResult() {
    public void onClearSearchResult() {
        mIsSearching = false;
        animateToSearchState(false);
        mHeader.setCollapsed(false);
        rebindAdapters();
        rebindAdapters();
        mHeader.reset(false);
    }
    }


    /**
    /**
@@ -93,12 +93,42 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher
     */
     */
    public void setSearchResults(ArrayList<AdapterItem> results) {
    public void setSearchResults(ArrayList<AdapterItem> results) {
        if (getSearchResultList().setSearchResults(results)) {
        if (getSearchResultList().setSearchResults(results)) {
            for (int i = 0; i < mAH.size(); i++) {
            getSearchRecyclerView().onSearchResultsChanged();
                if (mAH.get(i).mRecyclerView != null) {
                    mAH.get(i).mRecyclerView.onSearchResultsChanged();
        }
        }
        if (results != null) {
            animateToSearchState(true);
        }
        }
    }
    }

    private void animateToSearchState(boolean goingToSearch) {
        animateToSearchState(goingToSearch, DEFAULT_SEARCH_TRANSITION_DURATION_MS);
    }

    private void animateToSearchState(boolean goingToSearch, long durationMs) {
        if (!mSearchTransitionController.isRunning() && goingToSearch == isSearching()) {
            return;
        }
        if (goingToSearch) {
            // Fade out the button to pause work apps.
            mWorkManager.onActivePageChanged(SEARCH);
        }
        mSearchTransitionController.animateToSearchState(goingToSearch, durationMs,
                /* onEndRunnable = */ () -> {
                    mIsSearching = goingToSearch;
                    updateSearchResultsVisibility();
                    int previousPage = getCurrentPage();
                    if (mRebindAdaptersAfterSearchAnimation) {
                        rebindAdapters(false);
                        mRebindAdaptersAfterSearchAnimation = false;
                    }
                    if (!goingToSearch) {
                        setSearchResults(null);
                        if (mViewPager != null) {
                            mViewPager.setCurrentPage(previousPage);
                        }
                        onActivePageChanged(previousPage);
                    }
                });
    }
    }


    @Override
    @Override
@@ -121,6 +151,8 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher
        super.reset(animate);
        super.reset(animate);
        // Reset the search bar after transitioning home.
        // Reset the search bar after transitioning home.
        mSearchUiManager.resetSearch();
        mSearchUiManager.resetSearch();
        // Animate to A-Z with 0 time to reset the animation with proper state management.
        animateToSearchState(false, 0);
    }
    }


    @Override
    @Override
@@ -156,22 +188,31 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher
        return mIsSearching;
        return mIsSearching;
    }
    }


    @Override
    public void onActivePageChanged(int currentActivePage) {
        if (mSearchTransitionController.isRunning()) {
            // Will be called at the end of the animation.
            return;
        }
        super.onActivePageChanged(currentActivePage);
    }

    @Override
    @Override
    protected void rebindAdapters(boolean force) {
    protected void rebindAdapters(boolean force) {
        if (mSearchTransitionController.isRunning()) {
            mRebindAdaptersAfterSearchAnimation = true;
            return;
        }
        super.rebindAdapters(force);
        super.rebindAdapters(force);
        if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()
        if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()
                || getMainAdapterProvider().getDecorator() == null) {
                || getMainAdapterProvider().getDecorator() == null
                || getSearchRecyclerView() == null) {
            return;
            return;
        }
        }


        RecyclerView.ItemDecoration decoration = getMainAdapterProvider().getDecorator();
        RecyclerView.ItemDecoration decoration = getMainAdapterProvider().getDecorator();
        mAH.stream()
        getSearchRecyclerView().removeItemDecoration(decoration); // In case it is already added.
                .map(adapterHolder -> adapterHolder.mRecyclerView)
        getSearchRecyclerView().addItemDecoration(decoration);
                .filter(Objects::nonNull)
                .forEach(v -> {
                    v.removeItemDecoration(decoration); // Remove in case it is already added.
                    v.addItemDecoration(decoration);
                });
    }
    }


    @Override
    @Override
+5 −0
Original line number Original line Diff line number Diff line
@@ -127,6 +127,11 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex
        public boolean isContentSame(AdapterItem other) {
        public boolean isContentSame(AdapterItem other) {
            return itemInfo == null && other.itemInfo == null;
            return itemInfo == null && other.itemInfo == null;
        }
        }

        /** Sets the alpha of the decorator for this item. Returns true if successful. */
        public boolean setDecorationFillAlpha(int alpha) {
            return false;
        }
    }
    }


    protected final T mActivityContext;
    protected final T mActivityContext;
Loading