2153e1c814
> Enable to use floating for prediction row even without tabs. > Behind ALL_APPS_PREDICTION_ROW_VIEW feature flag. > Expand/Collapse personal/work tabs in stopped intermediate state. Bug: 68713881 Change-Id: I7817e7b7c6f572358f2b9a7a347339a9081708ee
151 lines
5.4 KiB
Java
151 lines
5.4 KiB
Java
/*
|
|
* 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<ComponentKey, AppInfo> mComponentToAppMap;
|
|
private int mNumPredictedAppsPerRow;
|
|
// The set of predicted app component names
|
|
private final List<ComponentKeyMapper<AppInfo>> mPredictedAppComponents = new ArrayList<>();
|
|
// The set of predicted apps resolved from the component names and the current set of apps
|
|
private final List<AppInfo> 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<ComponentKey, AppInfo> 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<AppInfo> 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<ComponentKeyMapper<AppInfo>> 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<AppInfo> processPredictedAppComponents(
|
|
List<ComponentKeyMapper<AppInfo>> components) {
|
|
if (mComponentToAppMap.isEmpty()) {
|
|
// Apps have not been bound yet.
|
|
return Collections.emptyList();
|
|
}
|
|
|
|
List<AppInfo> predictedApps = new ArrayList<>();
|
|
for (ComponentKeyMapper<AppInfo> 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;
|
|
}
|
|
}
|