136f9d6f8a
- Have the animation happen according to the state of private space. - Have the transition happen only once by setting the current transition to null at the end of transition and by ensuring where the transitions are allowed. - Removing controller class. - The onClick controls the enablement of the profile. On reset (when getting the transition) is what controls the animation during expand. tldr- In the collapse case: execute() is called -> animation happens -> addPsHeader tldr- Expand case: post() is called -> addPsHeader -> animation happens. Collapse: onClick() -> AACV.onAppsUpdated() that resets & apply/RUNS runnable because EXECUTE -> AAList.onAppsUpdated() (which is called at the same time animating happens which we should cancel and do at end callback) -> AAList.onAppsUpdated() gets called again Expand: onCLick() -> AACV.onAppsUpdated() that resets & apply runnable -> AAList.onAppsUpdated() (no animation running) -> AAList.onAppsUpdated() (no animation running) -> addPrivateSpaceHeader -> then unlockAction() runnable because its posted at this point bug: 326206132 bug: 330444548 bug: 299294792 Test: manually locally and presubmit: https://screenshot.googleplex.com/9wavvwKQ8hY6oUw & https://screenshot.googleplex.com/BiqmidLFjPwS28j video: https://drive.google.com/file/d/1XGhmTncdUFtJj188_l7alGyyNz_fhXNw/view?usp=sharing Scrolling fix before: https://drive.google.com/file/d/1XykDm4UELoCvcwZdj8ZlJ6TszptB8W0W/view?usp=sharing scrolling fix after when not a lot of apps: https://drive.google.com/file/d/1Y4VY1eX7WE8ShSLXRrT56ieBdAuJo_zn/view?usp=sharing scrolling fix after with a lot of apps: https://drive.google.com/file/d/1Y58c-Z9xnU1GILp0Ih-oLORXYkMB-jWn/view?usp=sharing Flag: ACONFIG com.android.launcher3.Flags.private_space_animation Change-Id: I8d03ae60e2c9fe0ec145c4b0a2e9604b9e6e9017
224 lines
8.7 KiB
Java
224 lines
8.7 KiB
Java
/*
|
|
* Copyright (C) 2015 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.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.accessibility.AccessibilityEvent;
|
|
|
|
import androidx.core.view.accessibility.AccessibilityEventCompat;
|
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
|
import androidx.core.view.accessibility.AccessibilityRecordCompat;
|
|
import androidx.recyclerview.widget.GridLayoutManager;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
import androidx.recyclerview.widget.RecyclerView.Adapter;
|
|
|
|
import com.android.launcher3.allapps.search.SearchAdapterProvider;
|
|
import com.android.launcher3.util.ScrollableLayoutManager;
|
|
import com.android.launcher3.views.ActivityContext;
|
|
|
|
import java.util.List;
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
|
|
|
/**
|
|
* The grid view adapter of all the apps.
|
|
*
|
|
* @param <T> Type of context inflating all apps.
|
|
*/
|
|
public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
|
|
BaseAllAppsAdapter<T> {
|
|
|
|
public static final String TAG = "AppsGridAdapter";
|
|
private final AppsGridLayoutManager mGridLayoutMgr;
|
|
private final CopyOnWriteArrayList<OnLayoutCompletedListener> mOnLayoutCompletedListeners =
|
|
new CopyOnWriteArrayList<>();
|
|
|
|
/**
|
|
* Listener for {@link RecyclerView.LayoutManager#onLayoutCompleted(RecyclerView.State)}
|
|
*/
|
|
public interface OnLayoutCompletedListener {
|
|
void onLayoutCompleted();
|
|
}
|
|
|
|
/**
|
|
* Adds a {@link OnLayoutCompletedListener} to receive a callback when {@link
|
|
* RecyclerView.LayoutManager#onLayoutCompleted(RecyclerView.State)} is called
|
|
*/
|
|
public void addOnLayoutCompletedListener(OnLayoutCompletedListener listener) {
|
|
mOnLayoutCompletedListeners.add(listener);
|
|
}
|
|
|
|
/**
|
|
* Removes a {@link OnLayoutCompletedListener} to not receive a callback when {@link
|
|
* RecyclerView.LayoutManager#onLayoutCompleted(RecyclerView.State)} is called
|
|
*/
|
|
public void removeOnLayoutCompletedListener(OnLayoutCompletedListener listener) {
|
|
mOnLayoutCompletedListeners.remove(listener);
|
|
}
|
|
|
|
|
|
public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
|
|
AlphabeticalAppsList apps, SearchAdapterProvider<?> adapterProvider) {
|
|
super(activityContext, inflater, apps, adapterProvider);
|
|
mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
|
|
mGridLayoutMgr.setSpanSizeLookup(new GridSpanSizer());
|
|
setAppsPerRow(activityContext.getDeviceProfile().numShownAllAppsColumns);
|
|
}
|
|
|
|
/**
|
|
* Returns the grid layout manager.
|
|
*/
|
|
public AppsGridLayoutManager getLayoutManager() {
|
|
return mGridLayoutMgr;
|
|
}
|
|
|
|
/** @return the column index that the given adapter index falls. */
|
|
public int getSpanIndex(int adapterIndex) {
|
|
AppsGridLayoutManager lm = getLayoutManager();
|
|
return lm.getSpanSizeLookup().getSpanIndex(adapterIndex, lm.getSpanCount());
|
|
}
|
|
|
|
/**
|
|
* A subclass of GridLayoutManager that overrides accessibility values during app search.
|
|
*/
|
|
public class AppsGridLayoutManager extends ScrollableLayoutManager {
|
|
|
|
public AppsGridLayoutManager(Context context) {
|
|
super(context);
|
|
}
|
|
|
|
@Override
|
|
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
|
|
super.onInitializeAccessibilityEvent(event);
|
|
|
|
// Ensure that we only report the number apps for accessibility not including other
|
|
// adapter views
|
|
final AccessibilityRecordCompat record = AccessibilityEventCompat
|
|
.asRecord(event);
|
|
record.setItemCount(mApps.getNumFilteredApps());
|
|
record.setFromIndex(Math.max(0,
|
|
record.getFromIndex() - getRowsNotForAccessibility(record.getFromIndex())));
|
|
record.setToIndex(Math.max(0,
|
|
record.getToIndex() - getRowsNotForAccessibility(record.getToIndex())));
|
|
}
|
|
|
|
@Override
|
|
public int getRowCountForAccessibility(RecyclerView.Recycler recycler,
|
|
RecyclerView.State state) {
|
|
return super.getRowCountForAccessibility(recycler, state) -
|
|
getRowsNotForAccessibility(mApps.getAdapterItems().size() - 1);
|
|
}
|
|
|
|
@Override
|
|
public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
|
|
RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
|
|
super.onInitializeAccessibilityNodeInfoForItem(recycler, state, host, info);
|
|
|
|
ViewGroup.LayoutParams lp = host.getLayoutParams();
|
|
AccessibilityNodeInfoCompat.CollectionItemInfoCompat cic = info.getCollectionItemInfo();
|
|
if (!(lp instanceof LayoutParams) || (cic == null)) {
|
|
return;
|
|
}
|
|
LayoutParams glp = (LayoutParams) lp;
|
|
info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
|
|
cic.getRowIndex() - getRowsNotForAccessibility(glp.getViewAdapterPosition()),
|
|
cic.getRowSpan(),
|
|
cic.getColumnIndex(),
|
|
cic.getColumnSpan(),
|
|
cic.isHeading(),
|
|
cic.isSelected()));
|
|
}
|
|
|
|
/**
|
|
* Returns the number of rows before {@param adapterPosition}, including this position
|
|
* which should not be counted towards the collection info.
|
|
*/
|
|
private int getRowsNotForAccessibility(int adapterPosition) {
|
|
List<AdapterItem> items = mApps.getAdapterItems();
|
|
adapterPosition = Math.max(adapterPosition, items.size() - 1);
|
|
int extraRows = 0;
|
|
for (int i = 0; i <= adapterPosition && i < items.size(); i++) {
|
|
if (!isViewType(items.get(i).viewType, VIEW_TYPE_MASK_ICON)) {
|
|
extraRows++;
|
|
}
|
|
}
|
|
return extraRows;
|
|
}
|
|
|
|
@Override
|
|
public void onLayoutCompleted(RecyclerView.State state) {
|
|
super.onLayoutCompleted(state);
|
|
for (OnLayoutCompletedListener listener : mOnLayoutCompletedListeners) {
|
|
listener.onLayoutCompleted();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected int incrementTotalHeight(Adapter adapter, int position, int heightUntilLastPos) {
|
|
AllAppsGridAdapter.AdapterItem item = mApps.getAdapterItems().get(position);
|
|
// only account for the first icon in the row since they are the same size within a row
|
|
return (isIconViewType(item.viewType) && item.rowAppIndex != 0)
|
|
? heightUntilLastPos
|
|
: (heightUntilLastPos + mCachedSizes.get(item.viewType));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setAppsPerRow(int appsPerRow) {
|
|
mAppsPerRow = appsPerRow;
|
|
int totalSpans = mAppsPerRow;
|
|
for (int itemPerRow : mAdapterProvider.getSupportedItemsPerRowArray()) {
|
|
if (totalSpans % itemPerRow != 0) {
|
|
totalSpans *= itemPerRow;
|
|
}
|
|
}
|
|
mGridLayoutMgr.setSpanCount(totalSpans);
|
|
}
|
|
|
|
/**
|
|
* Helper class to size the grid items.
|
|
*/
|
|
public class GridSpanSizer extends GridLayoutManager.SpanSizeLookup {
|
|
|
|
public GridSpanSizer() {
|
|
super();
|
|
setSpanIndexCacheEnabled(true);
|
|
}
|
|
|
|
@Override
|
|
public int getSpanSize(int position) {
|
|
int totalSpans = mGridLayoutMgr.getSpanCount();
|
|
List<AdapterItem> items = mApps.getAdapterItems();
|
|
if (position >= items.size()) {
|
|
return totalSpans;
|
|
}
|
|
int viewType = items.get(position).viewType;
|
|
if (isIconViewType(viewType)) {
|
|
return totalSpans / mAppsPerRow;
|
|
} else {
|
|
if (mAdapterProvider.isViewSupported(viewType)) {
|
|
return totalSpans / mAdapterProvider.getItemsPerRow(viewType, mAppsPerRow);
|
|
}
|
|
|
|
// Section breaks span the full width
|
|
return totalSpans;
|
|
}
|
|
}
|
|
}
|
|
}
|