Files
Lawnchair/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
T
sfufa@google.com de0132939b [Foldable] Apply max width to AllApps in unfolded state.
Since we are applying the same iconWidth in AllApps as Workspace in unfolded state, this change restricts AllApps to span only the area required to display AllApps contents and not span full available width. Unfolded/phone behavior remains the same.

Bug: 199959857
Bug: 194259694
Test: visual
Change-Id: Ie5658d566f20e825e666ef17db79a87b07dc2936
2021-09-24 15:18:01 -07:00

275 lines
9.1 KiB
Java

/*
* Copyright (C) 2012 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.appprediction;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.keyboard.FocusIndicatorHelper;
import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@TargetApi(Build.VERSION_CODES.P)
public class PredictionRowView extends LinearLayout implements
OnDeviceProfileChangeListener, FloatingHeaderRow {
private final Launcher mLauncher;
private int mNumPredictedAppsPerRow;
// Helper to drawing the focus indicator.
private final FocusIndicatorHelper mFocusHelper;
// The set of predicted apps resolved from the component names and the current set of apps
private final List<WorkspaceItemInfo> mPredictedApps = new ArrayList<>();
private FloatingHeaderView mParent;
private boolean mScrolledOut;
private boolean mPredictionsEnabled = false;
@Nullable
private List<ItemInfo> mPendingPredictedItems;
public PredictionRowView(@NonNull Context context) {
this(context, null);
}
public PredictionRowView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.HORIZONTAL);
mFocusHelper = new SimpleFocusIndicatorHelper(this);
mLauncher = Launcher.getLauncher(context);
mLauncher.addOnDeviceProfileChangeListener(this);
mNumPredictedAppsPerRow = mLauncher.getDeviceProfile().numShownAllAppsColumns;
updateVisibility();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
}
public void setup(FloatingHeaderView parent, FloatingHeaderRow[] rows, boolean tabsHidden) {
mParent = parent;
}
private void updateVisibility() {
setVisibility(mPredictionsEnabled ? VISIBLE : GONE);
if (mLauncher.getAppsView() != null) {
if (mPredictionsEnabled) {
mLauncher.getAppsView().getAppsStore().registerIconContainer(this);
} else {
mLauncher.getAppsView().getAppsStore().unregisterIconContainer(this);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getExpectedHeight(),
MeasureSpec.EXACTLY));
}
@Override
protected void dispatchDraw(Canvas canvas) {
mFocusHelper.draw(canvas);
super.dispatchDraw(canvas);
}
@Override
public int getExpectedHeight() {
return getVisibility() == GONE ? 0 :
Launcher.getLauncher(getContext()).getDeviceProfile().allAppsCellHeightPx
+ getPaddingTop() + getPaddingBottom();
}
@Override
public boolean shouldDraw() {
return getVisibility() != GONE;
}
@Override
public boolean hasVisibleContent() {
return mPredictionsEnabled;
}
@Override
public boolean isVisible() {
return getVisibility() == VISIBLE;
}
/**
* Returns the predicted apps.
*/
public List<ItemInfoWithIcon> getPredictedApps() {
return new ArrayList<>(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 onPredictionsUpdated() 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<ItemInfo> items) {
if (!FeatureFlags.ENABLE_APP_PREDICTIONS_WHILE_VISIBLE.get()
&& !mLauncher.isWorkspaceLoading()
&& isShown()
&& getWindowVisibility() == View.VISIBLE) {
mPendingPredictedItems = items;
return;
}
applyPredictedApps(items);
}
private void applyPredictedApps(List<ItemInfo> items) {
mPendingPredictedItems = null;
mPredictedApps.clear();
mPredictedApps.addAll(items.stream()
.filter(itemInfo -> itemInfo instanceof WorkspaceItemInfo)
.map(itemInfo -> (WorkspaceItemInfo) itemInfo).collect(Collectors.toList()));
applyPredictionApps();
}
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
mNumPredictedAppsPerRow = dp.numShownAllAppsColumns;
removeAllViews();
applyPredictionApps();
}
private void applyPredictionApps() {
if (getChildCount() != mNumPredictedAppsPerRow) {
while (getChildCount() > mNumPredictedAppsPerRow) {
removeViewAt(0);
}
LayoutInflater inflater = mLauncher.getAppsView().getLayoutInflater();
while (getChildCount() < mNumPredictedAppsPerRow) {
BubbleTextView icon = (BubbleTextView) inflater.inflate(
R.layout.all_apps_icon, this, false);
icon.setOnClickListener(ItemClickHandler.INSTANCE);
icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);
icon.setLongPressTimeoutFactor(1f);
icon.setOnFocusChangeListener(mFocusHelper);
LayoutParams lp = (LayoutParams) icon.getLayoutParams();
// Ensure the all apps icon height matches the workspace icons in portrait mode.
lp.height = mLauncher.getDeviceProfile().allAppsCellHeightPx;
lp.width = 0;
lp.weight = 1;
addView(icon);
}
}
int predictionCount = mPredictedApps.size();
for (int i = 0; i < getChildCount(); i++) {
BubbleTextView icon = (BubbleTextView) getChildAt(i);
icon.reset();
if (predictionCount > i) {
icon.setVisibility(View.VISIBLE);
icon.applyFromWorkspaceItem(mPredictedApps.get(i));
} else {
icon.setVisibility(predictionCount == 0 ? GONE : INVISIBLE);
}
}
boolean predictionsEnabled = predictionCount > 0;
if (predictionsEnabled != mPredictionsEnabled) {
mPredictionsEnabled = predictionsEnabled;
mLauncher.reapplyUi(false /* cancelCurrentAnimation */);
updateVisibility();
}
mParent.onHeightUpdated();
}
@Override
public boolean hasOverlappingRendering() {
return false;
}
@Override
public void setVerticalScroll(int scroll, boolean isScrolledOut) {
mScrolledOut = isScrolledOut;
if (!isScrolledOut) {
setTranslationY(scroll);
}
setAlpha(mScrolledOut ? 0 : 1);
if (getVisibility() != GONE) {
AlphaUpdateListener.updateVisibility(this);
}
}
@Override
public void setInsets(Rect insets, DeviceProfile grid) {
int leftRightPadding = grid.allAppsLeftRightPadding;
setPadding(leftRightPadding, getPaddingTop(), leftRightPadding, getPaddingBottom());
}
@Override
public Class<PredictionRowView> getTypeClass() {
return PredictionRowView.class;
}
@Override
public View getFocusedChild() {
return getChildAt(0);
}
@Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
if (mPendingPredictedItems != null && !isVisible) {
applyPredictedApps(mPendingPredictedItems);
}
}
}