/* * 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.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.LinearLayout; import com.android.launcher3.AppInfo; import com.android.launcher3.BubbleTextView; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ComponentKeyMapper; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; public class PredictionRowView extends LinearLayout { private static final String TAG = "PredictionRowView"; private HashMap mComponentToAppMap; private int mNumPredictedAppsPerRow; // The set of predicted app component names private final List> mPredictedAppComponents = new ArrayList<>(); // The set of predicted apps resolved from the component names and the current set of apps private final List mPredictedApps = new ArrayList<>(); // This adapter is only used to create an identical item w/ same behavior as in the all apps RV private AllAppsGridAdapter mAdapter; public PredictionRowView(@NonNull Context context) { this(context, null); } public PredictionRowView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); setOrientation(LinearLayout.HORIZONTAL); } public void setup(AllAppsGridAdapter adapter, HashMap componentToAppMap, int numPredictedAppsPerRow) { mAdapter = adapter; mComponentToAppMap = componentToAppMap; mNumPredictedAppsPerRow = numPredictedAppsPerRow; } /** * Sets the number of apps per row. */ public void setNumAppsPerRow(int numPredictedAppsPerRow) { mNumPredictedAppsPerRow = numPredictedAppsPerRow; } /** * Returns the predicted apps. */ public List getPredictedApps() { return mPredictedApps; } /** * Sets the current set of predicted apps. * * This can be called before we get the full set of applications, we should merge the results * only in onAppsUpdated() which is idempotent. * * If the number of predicted apps is the same as the previous list of predicted apps, * we can optimize by swapping them in place. */ public void setPredictedApps(List> apps) { mPredictedAppComponents.clear(); mPredictedAppComponents.addAll(apps); mPredictedApps.addAll(processPredictedAppComponents(mPredictedAppComponents)); onAppsUpdated(); } private void onAppsUpdated() { if (getChildCount() != mNumPredictedAppsPerRow) { while (getChildCount() > mNumPredictedAppsPerRow) { removeViewAt(0); } while (getChildCount() < mNumPredictedAppsPerRow) { AllAppsGridAdapter.ViewHolder holder = mAdapter .onCreateViewHolder(this, AllAppsGridAdapter.VIEW_TYPE_ICON); BubbleTextView icon = (BubbleTextView) holder.itemView; LinearLayout.LayoutParams params = new LayoutParams(0, icon.getLayoutParams().height); params.weight = 1; icon.setLayoutParams(params); addView(icon); } } for (int i = 0; i < getChildCount(); i++) { BubbleTextView icon = (BubbleTextView) getChildAt(i); icon.reset(); if (mPredictedApps.size() > i) { icon.setVisibility(View.VISIBLE); icon.applyFromApplicationInfo(mPredictedApps.get(i)); } else { icon.setVisibility(View.INVISIBLE); } } } private List processPredictedAppComponents( List> components) { if (mComponentToAppMap.isEmpty()) { // Apps have not been bound yet. return Collections.emptyList(); } List predictedApps = new ArrayList<>(); for (ComponentKeyMapper mapper : components) { AppInfo info = mapper.getItem(mComponentToAppMap); if (info != null) { predictedApps.add(info); } else { if (FeatureFlags.IS_DOGFOOD_BUILD) { Log.e(TAG, "Predicted app not found: " + mapper); } } // Stop at the number of predicted apps if (predictedApps.size() == mNumPredictedAppsPerRow) { break; } } return predictedApps; } }