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

Commit 26c1105f authored by Samuel Fufa's avatar Samuel Fufa
Browse files

[search api part 1] Setup centralized SearchEventTracker

- Rename AdapterItemWIthPayload to SearchAdapterItem, PayloadResultHandler to SearchTargetHandler
- Setup SliceViewWrapper for self contained slices

Bug: 170702596
Change-Id: I0baf984ec8123c95011abcc17372f8d055e98ad7
parent 057f2d0d
Loading
Loading
Loading
Loading
+10 −11
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@
package com.android.launcher3.allapps;

import static com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
import static com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
import static com.android.launcher3.allapps.AllAppsGridAdapter.SearchAdapterItem;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
@@ -57,6 +57,7 @@ import com.android.launcher3.Insettable;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.search.SearchEventTracker;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.model.data.AppInfo;
@@ -67,9 +68,7 @@ import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
import com.android.systemui.plugins.shared.SearchTargetEvent;

import java.util.function.IntConsumer;
import com.android.systemui.plugins.shared.SearchTarget;

/**
 * The all apps view container.
@@ -546,13 +545,9 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
            return mLauncher.startActivitySafely(v, headerItem.getIntent(), headerItem);
        }
        AdapterItem focusedItem = getActiveRecyclerView().getApps().getFocusedChild();
        if (focusedItem instanceof AdapterItemWithPayload) {
            IntConsumer onSelection =
                    ((AdapterItemWithPayload) focusedItem).getSelectionHandler();
            if (onSelection != null) {
                onSelection.accept(SearchTargetEvent.QUICK_SELECT);
                return true;
            }
        if (focusedItem instanceof SearchAdapterItem) {
            SearchTarget searchTarget = ((SearchAdapterItem) focusedItem).getSearchTarget();
            SearchEventTracker.INSTANCE.get(getContext()).quickSelect(searchTarget);
        }
        if (focusedItem.appInfo != null) {
            ItemInfo itemInfo = focusedItem.appInfo;
@@ -585,6 +580,10 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
        int padding = mHeader.getMaxTranslation();
        for (int i = 0; i < mAH.length; i++) {
            mAH[i].padding.top = padding;
            if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mUsingTabs) {
                //add extra space between tabs and recycler view
                mAH[i].padding.top += mLauncher.getDeviceProfile().edgeMarginPx;
            }
            mAH[i].applyPadding();
        }
    }
+43 −76
Original line number Diff line number Diff line
@@ -20,8 +20,6 @@ import static com.android.launcher3.touch.ItemLongClickListener.INSTANCE_ALL_APP
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -37,29 +35,25 @@ import androidx.annotation.Nullable;
import androidx.core.view.accessibility.AccessibilityEventCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityRecordCompat;
import androidx.lifecycle.LiveData;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.slice.Slice;
import androidx.slice.widget.SliceLiveData;
import androidx.slice.widget.SliceView;

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.search.AllAppsSearchBarController.PayloadResultHandler;
import com.android.launcher3.allapps.search.AllAppsSearchBarController.SearchTargetHandler;
import com.android.launcher3.allapps.search.SearchEventTracker;
import com.android.launcher3.allapps.search.SearchSectionInfo;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.HeroSearchResultView;
import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.launcher3.views.SearchSliceWrapper;
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;

import java.util.List;
import java.util.function.IntConsumer;

/**
 * The grid view adapter of all the apps.
@@ -201,28 +195,13 @@ public class AllAppsGridAdapter extends
     *
     * @param <T> Play load Type
     */
    public static class AdapterItemWithPayload<T> extends AdapterItem {
        private T mPayload;
    public static class SearchAdapterItem extends AdapterItem {
        private SearchTarget mSearchTarget;
        private String mSearchSessionId;
        private AllAppsSearchPlugin mPlugin;
        private IntConsumer mSelectionHandler;

        public AllAppsSearchPlugin getPlugin() {
            return mPlugin;
        }

        public void setPlugin(AllAppsSearchPlugin plugin) {
            mPlugin = plugin;
        }

        public AdapterItemWithPayload(T payload, int type, AllAppsSearchPlugin plugin) {
            mPayload = payload;
        public SearchAdapterItem(SearchTarget searchTarget, int type) {
            mSearchTarget = searchTarget;
            viewType = type;
            mPlugin = plugin;
        }

        public void setSelectionHandler(IntConsumer runnable) {
            mSelectionHandler = runnable;
        }

        public void setSearchSessionId(String searchSessionId) {
@@ -233,15 +212,9 @@ public class AllAppsGridAdapter extends
            return mSearchSessionId;
        }

        public IntConsumer getSelectionHandler() {
            return mSelectionHandler;
        public SearchTarget getSearchTarget() {
            return mSearchTarget;
        }

        public T getPayload() {
            return mPayload;
        }


    }

    /**
@@ -492,26 +465,35 @@ public class AllAppsGridAdapter extends
                }
                //TODO: replace with custom TopHitBubbleTextView with support for both shortcut
                // and apps
                if (adapterItem instanceof AdapterItemWithPayload) {
                    AdapterItemWithPayload item = (AdapterItemWithPayload) adapterItem;
                    item.setSelectionHandler(type -> {
                if (adapterItem instanceof SearchAdapterItem) {
                    SearchAdapterItem item = (SearchAdapterItem) adapterItem;
                    SearchTargetHandler searchTargetHandler = new SearchTargetHandler() {
                        @Override
                        public void applySearchTarget(SearchTarget searchTarget) {
                            // Does nothing
                        }

                        @Override
                        public void handleSelection(int type) {
                            SearchTargetEvent e = new SearchTargetEvent(SearchTarget.ItemType.APP,
                                    type, item.position, item.getSearchSessionId());
                            e.bundle = HeroSearchResultView.getAppBundle(info);
                        if (item.getPlugin() != null) {
                            item.getPlugin().notifySearchTargetEvent(e);
                            SearchEventTracker.INSTANCE.get(mLauncher).notifySearchTargetEvent(e);
                        }
                    });
                    };
                    SearchEventTracker.INSTANCE.get(mLauncher).registerWeakHandler(
                            ((SearchAdapterItem) adapterItem).getSearchTarget(),
                            searchTargetHandler);

                    icon.setOnClickListener(view -> {
                        item.getSelectionHandler().accept(SearchTargetEvent.SELECT);
                        searchTargetHandler.handleSelection(SearchTargetEvent.SELECT);
                        mOnIconClickListener.onClick(view);
                    });
                    icon.setOnLongClickListener(view -> {
                        item.getSelectionHandler().accept(SearchTargetEvent.SELECT);
                        searchTargetHandler.handleSelection(SearchTargetEvent.LONG_PRESS);
                        return mOnIconLongClickListener.onLongClick(view);
                    });
                }
                else {
                } else {
                    icon.setOnClickListener(mOnIconClickListener);
                    icon.setOnLongClickListener(mOnIconLongClickListener);
                }
@@ -532,26 +514,12 @@ public class AllAppsGridAdapter extends
                break;
            case VIEW_TYPE_SEARCH_SLICE:
                SliceView sliceView = (SliceView) holder.itemView;
                AdapterItemWithPayload<Uri> slicePayload =
                        (AdapterItemWithPayload<Uri>) mApps.getAdapterItems().get(position);
                sliceView.setOnSliceActionListener((info1, s) -> {
                    if (slicePayload.getPlugin() != null) {
                        SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
                                SearchTarget.ItemType.SETTINGS_SLICE,
                                SearchTargetEvent.CHILD_SELECT, slicePayload.position,
                                slicePayload.getSearchSessionId());
                        searchTargetEvent.bundle = new Bundle();
                        searchTargetEvent.bundle.putParcelable("uri", slicePayload.getPayload());
                        slicePayload.getPlugin().notifySearchTargetEvent(searchTargetEvent);
                    }
                });
                try {
                    LiveData<Slice> liveData = SliceLiveData.fromUri(mLauncher,
                            slicePayload.getPayload());
                    liveData.observe((Launcher) mLauncher, sliceView);
                    sliceView.setTag(liveData);
                } catch (Exception ignored) {
                }
                SearchAdapterItem slicePayload = (SearchAdapterItem) mApps.getAdapterItems().get(
                        position);
                SearchTarget searchTarget = slicePayload.getSearchTarget();
                sliceView.setTag(new SearchSliceWrapper(mLauncher, sliceView, searchTarget,
                        slicePayload.getSearchSessionId(), slicePayload.position));

                break;
            case VIEW_TYPE_SEARCH_CORPUS_TITLE:
            case VIEW_TYPE_SEARCH_ROW_WITH_BUTTON:
@@ -561,9 +529,9 @@ public class AllAppsGridAdapter extends
            case VIEW_TYPE_SEARCH_PEOPLE:
            case VIEW_TYPE_SEARCH_THUMBNAIL:
            case VIEW_TYPE_SEARCH_SUGGEST:
                AdapterItemWithPayload item =
                        (AdapterItemWithPayload) mApps.getAdapterItems().get(position);
                PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView;
                SearchAdapterItem item =
                        (SearchAdapterItem) mApps.getAdapterItems().get(position);
                SearchTargetHandler payloadResultView = (SearchTargetHandler) holder.itemView;
                payloadResultView.setup(item);
                break;
            case VIEW_TYPE_ALL_APPS_DIVIDER:
@@ -582,11 +550,10 @@ public class AllAppsGridAdapter extends
            icon.setOnLongClickListener(null);
        } else if (holder.itemView instanceof SliceView) {
            SliceView sliceView = (SliceView) holder.itemView;
            sliceView.setOnSliceActionListener(null);
            if (sliceView.getTag() instanceof LiveData) {
                LiveData sliceLiveData = (LiveData) sliceView.getTag();
                sliceLiveData.removeObservers((Launcher) mLauncher);
            if (sliceView.getTag() instanceof SearchSliceWrapper) {
                ((SearchSliceWrapper) sliceView.getTag()).destroy();
            }
            sliceView.setTag(null);
        }
    }

+5 −4
Original line number Diff line number Diff line
@@ -25,9 +25,9 @@ import com.android.launcher3.config.FeatureFlags;

public class AllAppsPagedView extends PagedView<PersonalWorkSlidingTabStrip> {

  final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
  final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
  final static float TOUCH_SLOP_DAMPING_FACTOR = 4;
    static final float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
    static final float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
    static final float TOUCH_SLOP_DAMPING_FACTOR = 4;

    public AllAppsPagedView(Context context) {
        this(context, null);
@@ -42,6 +42,7 @@ public class AllAppsPagedView extends PagedView<PersonalWorkSlidingTabStrip> {
        int topPadding = FeatureFlags.ENABLE_DEVICE_SEARCH.get() ? 0
                : context.getResources().getDimensionPixelOffset(
                        R.dimen.all_apps_header_top_padding);
        setPadding(0, topPadding, 0, 0);
    }

    @Override
+21 −9
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsGridAdapter;
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
import com.android.launcher3.allapps.AllAppsGridAdapter.SearchAdapterItem;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.systemui.plugins.AllAppsSearchPlugin;
@@ -211,26 +211,31 @@ public class AllAppsSearchBarController
     *
     * @param <T> Type of payload
     */
    public interface PayloadResultHandler<T> {
    public interface SearchTargetHandler {
        /**
         * Updates View using Adapter's payload
         */

        default void setup(AdapterItemWithPayload<T> adapterItemWithPayload) {
        default void setup(SearchAdapterItem searchAdapterItem) {
            Object[] targetInfo = getTargetInfo();
            if (targetInfo != null) {
                targetInfo[0] = adapterItemWithPayload.getSearchSessionId();
                targetInfo[1] = adapterItemWithPayload.position;
                targetInfo[0] = searchAdapterItem.getSearchSessionId();
                targetInfo[1] = searchAdapterItem.position;
            }
            applyAdapterInfo(adapterItemWithPayload);
            applySearchTarget(searchAdapterItem.getSearchTarget());
        }

        void applyAdapterInfo(AdapterItemWithPayload<T> adapterItemWithPayload);
        /**
         * Update view using values from {@link SearchTarget}
         */
        void applySearchTarget(SearchTarget searchTarget);

        /**
         * Gets object created by {@link PayloadResultHandler#createTargetInfo()}
         * Gets object created by {@link SearchTargetHandler#createTargetInfo()}
         */
        Object[] getTargetInfo();
        default Object[] getTargetInfo() {
            return null;
        }

        /**
         * Creates a wrapper object to hold searchSessionId and item position
@@ -252,6 +257,13 @@ public class AllAppsSearchBarController
            return new SearchTargetEvent(itemType, eventType,
                    position, searchSessionId);
        }

        /**
         * Handles selection of SearchTarget
         */
        default void handleSelection(int eventType) {
        }

    }


+91 −0
Original line number Diff line number Diff line
/*
 * 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.search;

import android.content.Context;

import androidx.annotation.Nullable;

import com.android.launcher3.allapps.search.AllAppsSearchBarController.SearchTargetHandler;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;

import java.util.WeakHashMap;

/**
 * A singleton class to track and report search events to search provider
 */
public class SearchEventTracker {
    @Nullable
    private AllAppsSearchPlugin mPlugin;
    private final WeakHashMap<SearchTarget, SearchTargetHandler>
            mCallbacks = new WeakHashMap<>();

    public static final MainThreadInitializedObject<SearchEventTracker> INSTANCE =
            new MainThreadInitializedObject<>(SearchEventTracker::new);

    private SearchEventTracker(Context context) {
    }

    /**
     * Returns instance of SearchEventTracker
     */
    public static SearchEventTracker getInstance(Context context) {
        return SearchEventTracker.INSTANCE.get(context);
    }

    /**
     * Sets current connected plugin for event reporting
     */
    public void setPlugin(@Nullable AllAppsSearchPlugin plugin) {
        mPlugin = plugin;
    }

    /**
     * Sends SearchTargetEvent to search provider
     */
    public void notifySearchTargetEvent(SearchTargetEvent searchTargetEvent) {
        if (mPlugin != null) {
            mPlugin.notifySearchTargetEvent(searchTargetEvent);
        }
    }

    /**
     * Registers a {@link SearchTargetHandler} to handle quick launch for specified SearchTarget.
     */
    public void registerWeakHandler(SearchTarget searchTarget, SearchTargetHandler targetHandler) {
        mCallbacks.put(searchTarget, targetHandler);
    }

    /**
     * Handles quick select for SearchTarget
     */
    public void quickSelect(SearchTarget searchTarget) {
        SearchTargetHandler searchTargetHandler = mCallbacks.get(searchTarget);
        if (searchTargetHandler != null) {
            searchTargetHandler.handleSelection(SearchTargetEvent.QUICK_SELECT);
        }
    }

    /**
     * flushes all registered quick select handlers
     */
    public void clearHandlers() {
        mCallbacks.clear();
    }
}
Loading