Initial changes to break out AllApps into its own view.
- Moves launcher state-transition code into its own class - Moves all-apps related code into a separate view/set of classes - Implements a basic list view for all apps Change-Id: I68f174aa9e1bf82c4e46ce9549c78a8dc4623f46
This commit is contained in:
@@ -0,0 +1,609 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SectionIndexer;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a row in the apps list view.
|
||||
*/
|
||||
class AppsRow {
|
||||
int sectionId;
|
||||
String sectionDescription;
|
||||
List<AppInfo> apps;
|
||||
|
||||
public AppsRow(int sId, String sc, List<AppInfo> ai) {
|
||||
sectionId = sId;
|
||||
sectionDescription = sc;
|
||||
apps = ai;
|
||||
}
|
||||
|
||||
public AppsRow(int sId, List<AppInfo> ai) {
|
||||
sectionId = sId;
|
||||
apps = ai;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface to an algorithm that generates app rows.
|
||||
*/
|
||||
interface AppRowAlgorithm {
|
||||
public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow);
|
||||
public int getIconViewLayoutId();
|
||||
public int getRowViewLayoutId();
|
||||
public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the rows in the apps list view.
|
||||
*/
|
||||
class SectionedAppsAlgorithm implements AppRowAlgorithm {
|
||||
|
||||
@Override
|
||||
public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow) {
|
||||
List<AppsRow> rows = new ArrayList<>();
|
||||
LinkedHashMap<String, List<AppInfo>> sections = computeSectionedApps(sortedApps);
|
||||
int sectionId = 0;
|
||||
for (Map.Entry<String, List<AppInfo>> sectionEntry : sections.entrySet()) {
|
||||
String section = sectionEntry.getKey();
|
||||
List<AppInfo> apps = sectionEntry.getValue();
|
||||
int numRows = (int) Math.ceil((float) apps.size() / appsPerRow);
|
||||
for (int i = 0; i < numRows; i++) {
|
||||
List<AppInfo> appsInRow = new ArrayList<>();
|
||||
int offset = i * appsPerRow;
|
||||
for (int j = 0; j < appsPerRow; j++) {
|
||||
if (offset + j < apps.size()) {
|
||||
appsInRow.add(apps.get(offset + j));
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
rows.add(new AppsRow(sectionId, section, appsInRow));
|
||||
} else {
|
||||
rows.add(new AppsRow(sectionId, appsInRow));
|
||||
}
|
||||
}
|
||||
sectionId++;
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconViewLayoutId() {
|
||||
return R.layout.apps_grid_row_icon_view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowViewLayoutId() {
|
||||
return R.layout.apps_grid_row_view;
|
||||
}
|
||||
|
||||
private LinkedHashMap<String, List<AppInfo>> computeSectionedApps(List<AppInfo> sortedApps) {
|
||||
LinkedHashMap<String, List<AppInfo>> sections = new LinkedHashMap<>();
|
||||
for (AppInfo info : sortedApps) {
|
||||
String section = getSection(info);
|
||||
List<AppInfo> sectionApps = sections.get(section);
|
||||
if (sectionApps == null) {
|
||||
sectionApps = new ArrayList<>();
|
||||
sections.put(section, sectionApps);
|
||||
}
|
||||
sectionApps.add(info);
|
||||
}
|
||||
return sections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info) {
|
||||
icon.applyFromApplicationInfo(info);
|
||||
}
|
||||
|
||||
private String getSection(AppInfo app) {
|
||||
return app.title.toString().substring(0, 1).toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the rows in the apps grid view.
|
||||
*/
|
||||
class ListedAppsAlgorithm implements AppRowAlgorithm {
|
||||
|
||||
@Override
|
||||
public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow) {
|
||||
List<AppsRow> rows = new ArrayList<>();
|
||||
int sectionId = -1;
|
||||
String prevSection = "";
|
||||
for (AppInfo info : sortedApps) {
|
||||
List<AppInfo> appsInRow = new ArrayList<>();
|
||||
appsInRow.add(info);
|
||||
String section = getSection(info);
|
||||
if (!prevSection.equals(section)) {
|
||||
prevSection = section;
|
||||
sectionId++;
|
||||
rows.add(new AppsRow(sectionId, section, appsInRow));
|
||||
} else {
|
||||
rows.add(new AppsRow(sectionId, appsInRow));
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconViewLayoutId() {
|
||||
return R.layout.apps_list_row_icon_view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowViewLayoutId() {
|
||||
return R.layout.apps_list_row_view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info) {
|
||||
icon.applyFromApplicationInfo(info);
|
||||
}
|
||||
|
||||
private String getSection(AppInfo app) {
|
||||
return app.title.toString().substring(0, 1).toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The adapter of all the apps
|
||||
*/
|
||||
class AppsListAdapter extends BaseAdapter implements SectionIndexer {
|
||||
|
||||
private LayoutInflater mLayoutInflater;
|
||||
private List<AppsRow> mAppRows = new ArrayList<>();
|
||||
private View.OnTouchListener mTouchListener;
|
||||
private View.OnClickListener mIconClickListener;
|
||||
private View.OnLongClickListener mIconLongClickListener;
|
||||
private AppRowAlgorithm mRowAlgorithm;
|
||||
private int mAppsPerRow;
|
||||
|
||||
public AppsListAdapter(Context context, View.OnTouchListener touchListener,
|
||||
View.OnClickListener iconClickListener, View.OnLongClickListener iconLongClickListener) {
|
||||
mLayoutInflater = LayoutInflater.from(context);
|
||||
mTouchListener = touchListener;
|
||||
mIconClickListener = iconClickListener;
|
||||
mIconLongClickListener = iconLongClickListener;
|
||||
}
|
||||
|
||||
void setApps(List<AppsRow> apps, int appsPerRow, AppRowAlgorithm algo) {
|
||||
mAppsPerRow = appsPerRow;
|
||||
mRowAlgorithm = algo;
|
||||
mAppRows.clear();
|
||||
mAppRows.addAll(apps);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mAppRows.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mAppRows.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
AppsRow info = mAppRows.get(position);
|
||||
ViewGroup row = (ViewGroup) convertView;
|
||||
if (row == null) {
|
||||
// Inflate the row and all the icon children necessary
|
||||
row = (ViewGroup) mLayoutInflater.inflate(mRowAlgorithm.getRowViewLayoutId(),
|
||||
parent, false);
|
||||
for (int i = 0; i < mAppsPerRow; i++) {
|
||||
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
|
||||
mRowAlgorithm.getIconViewLayoutId(), row, false);
|
||||
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, 1);
|
||||
lp.gravity = Gravity.CENTER_VERTICAL;
|
||||
icon.setLayoutParams(lp);
|
||||
icon.setOnTouchListener(mTouchListener);
|
||||
icon.setOnClickListener(mIconClickListener);
|
||||
icon.setOnLongClickListener(mIconLongClickListener);
|
||||
icon.setFocusable(true);
|
||||
row.addView(icon);
|
||||
}
|
||||
}
|
||||
// Bind the section header
|
||||
TextView tv = (TextView) row.findViewById(R.id.section);
|
||||
if (info.sectionDescription != null) {
|
||||
tv.setText(info.sectionDescription);
|
||||
tv.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
tv.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
// Bind the icons
|
||||
for (int i = 0; i < mAppsPerRow; i++) {
|
||||
BubbleTextView icon = (BubbleTextView) row.getChildAt(i + 1);
|
||||
if (i < info.apps.size()) {
|
||||
mRowAlgorithm.bindRowViewIconToInfo(icon, info.apps.get(i));
|
||||
icon.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
icon.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSections() {
|
||||
ArrayList<Object> sections = new ArrayList<>();
|
||||
int prevSectionId = -1;
|
||||
for (AppsRow row : mAppRows) {
|
||||
if (row.sectionId != prevSectionId) {
|
||||
sections.add(row.sectionDescription.toUpperCase());
|
||||
prevSectionId = row.sectionId;
|
||||
}
|
||||
}
|
||||
return sections.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPositionForSection(int sectionIndex) {
|
||||
for (int i = 0; i < mAppRows.size(); i++) {
|
||||
AppsRow row = mAppRows.get(i);
|
||||
if (row.sectionId == sectionIndex) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionForPosition(int position) {
|
||||
return mAppRows.get(position).sectionId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The alphabetically sorted list of applications.
|
||||
*/
|
||||
class AlphabeticalAppList {
|
||||
|
||||
/**
|
||||
* Callbacks for when this list is modified.
|
||||
*/
|
||||
public interface Callbacks {
|
||||
public void onAppsUpdated();
|
||||
}
|
||||
|
||||
private List<AppInfo> mApps;
|
||||
private Callbacks mCb;
|
||||
|
||||
public AlphabeticalAppList(Callbacks cb) {
|
||||
mCb = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of applications.
|
||||
*/
|
||||
public List<AppInfo> getApps() {
|
||||
return mApps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current set of apps.
|
||||
*/
|
||||
public void setApps(List<AppInfo> apps) {
|
||||
Collections.sort(apps, LauncherModel.getAppNameComparator());
|
||||
mApps = apps;
|
||||
mCb.onAppsUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new apps to the list.
|
||||
*/
|
||||
public void addApps(List<AppInfo> apps) {
|
||||
// We add it in place, in alphabetical order
|
||||
Comparator<AppInfo> appNameComparator = LauncherModel.getAppNameComparator();
|
||||
for (AppInfo info : apps) {
|
||||
// This call will return the exact index of where the item is if >= 0, or the index
|
||||
// where it should be inserted if < 0.
|
||||
int index = Collections.binarySearch(mApps, info, appNameComparator);
|
||||
if (index < 0) {
|
||||
mApps.add(-(index + 1), info);
|
||||
}
|
||||
}
|
||||
mCb.onAppsUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates existing apps in the list
|
||||
*/
|
||||
public void updateApps(List<AppInfo> apps) {
|
||||
Comparator<AppInfo> appNameComparator = LauncherModel.getAppNameComparator();
|
||||
for (AppInfo info : apps) {
|
||||
int index = mApps.indexOf(info);
|
||||
if (index != -1) {
|
||||
mApps.set(index, info);
|
||||
} else {
|
||||
index = Collections.binarySearch(mApps, info, appNameComparator);
|
||||
if (index < 0) {
|
||||
mApps.add(-(index + 1), info);
|
||||
}
|
||||
}
|
||||
}
|
||||
mCb.onAppsUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes some apps from the list.
|
||||
*/
|
||||
public void removeApps(List<AppInfo> apps) {
|
||||
for (AppInfo info : apps) {
|
||||
int removeIndex = findAppByComponent(mApps, info);
|
||||
if (removeIndex != -1) {
|
||||
mApps.remove(removeIndex);
|
||||
}
|
||||
}
|
||||
mCb.onAppsUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the index of an app given a target AppInfo.
|
||||
*/
|
||||
private int findAppByComponent(List<AppInfo> apps, AppInfo targetInfo) {
|
||||
ComponentName targetComponent = targetInfo.intent.getComponent();
|
||||
int length = apps.size();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
AppInfo info = apps.get(i);
|
||||
if (info.user.equals(info.user)
|
||||
&& info.intent.getComponent().equals(targetComponent)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The all apps list view container.
|
||||
*/
|
||||
public class AppsContainerView extends FrameLayout implements DragSource, View.OnTouchListener,
|
||||
View.OnLongClickListener, Insettable, AlphabeticalAppList.Callbacks {
|
||||
|
||||
static final int GRID_LAYOUT = 0;
|
||||
static final int LIST_LAYOUT = 1;
|
||||
static final int USE_LAYOUT = LIST_LAYOUT;
|
||||
|
||||
private Launcher mLauncher;
|
||||
private AppRowAlgorithm mAppRowsAlgorithm;
|
||||
private AppsListAdapter mAdapter;
|
||||
private AlphabeticalAppList mApps;
|
||||
private ListView mList;
|
||||
private int mAppsRowSize;
|
||||
private Point mLastTouchDownPos = new Point();
|
||||
private Rect mPadding = new Rect();
|
||||
|
||||
public AppsContainerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public AppsContainerView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public AppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public AppsContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
|
||||
mLauncher = (Launcher) context;
|
||||
if (USE_LAYOUT == GRID_LAYOUT) {
|
||||
mAppRowsAlgorithm = new SectionedAppsAlgorithm();
|
||||
mAppsRowSize = grid.allAppsRowsSize;
|
||||
} else if (USE_LAYOUT == LIST_LAYOUT) {
|
||||
mAppRowsAlgorithm = new ListedAppsAlgorithm();
|
||||
mAppsRowSize = 1;
|
||||
}
|
||||
mAdapter = new AppsListAdapter(context, this, mLauncher, this);
|
||||
mApps = new AlphabeticalAppList(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current set of apps.
|
||||
*/
|
||||
public void setApps(List<AppInfo> apps) {
|
||||
mApps.setApps(apps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new apps to the list.
|
||||
*/
|
||||
public void addApps(List<AppInfo> apps) {
|
||||
mApps.addApps(apps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates existing apps in the list
|
||||
*/
|
||||
public void updateApps(List<AppInfo> apps) {
|
||||
mApps.updateApps(apps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes some apps from the list.
|
||||
*/
|
||||
public void removeApps(List<AppInfo> apps) {
|
||||
mApps.removeApps(apps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls this list view to the top.
|
||||
*/
|
||||
public void scrollToTop() {
|
||||
mList.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content view used for the launcher transitions.
|
||||
*/
|
||||
public View getContentView() {
|
||||
return findViewById(R.id.apps_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reveal view used for the launcher transitions.
|
||||
*/
|
||||
public View getRevealView() {
|
||||
return findViewById(R.id.all_apps_transition_overlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppsUpdated() {
|
||||
List<AppsRow> rows = mAppRowsAlgorithm.computeAppRows(mApps.getApps(), mAppsRowSize);
|
||||
mAdapter.setApps(rows, mAppsRowSize, mAppRowsAlgorithm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
mList = (ListView) findViewById(R.id.apps_list);
|
||||
mList.setFastScrollEnabled(true);
|
||||
mList.setFastScrollAlwaysVisible(true);
|
||||
mList.setItemsCanFocus(true);
|
||||
mList.setAdapter(mAdapter);
|
||||
mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
setPadding(mPadding.left + insets.left, mPadding.top + insets.top,
|
||||
mPadding.right + insets.right, mPadding.bottom + insets.bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN ||
|
||||
event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
mLastTouchDownPos.set((int) event.getX(), (int) event.getY());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
// Return early if this is not initiated from a touch
|
||||
if (!v.isInTouchMode()) return false;
|
||||
// When we have exited all apps or are in transition, disregard long clicks
|
||||
if (!mLauncher.isAppsViewVisible() ||
|
||||
mLauncher.getWorkspace().isSwitchingState()) return false;
|
||||
// Return if global dragging is not enabled
|
||||
if (!mLauncher.isDraggingEnabled()) return false;
|
||||
|
||||
// Start the drag
|
||||
mLauncher.getWorkspace().beginDragShared(v, mLastTouchDownPos, this, false);
|
||||
|
||||
// We delay entering spring-loaded mode slightly to make sure the UI
|
||||
// thready is free of any work.
|
||||
postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// We don't enter spring-loaded mode if the drag has been cancelled
|
||||
if (mLauncher.getDragController().isDragging()) {
|
||||
// Go into spring loaded mode (must happen before we startDrag())
|
||||
mLauncher.enterSpringLoadedDragMode();
|
||||
}
|
||||
}
|
||||
}, 150);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFlingToDelete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsAppInfoDropTarget() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsDeleteDropTarget() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getIntrinsicIconScaleFactor() {
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
return (float) grid.allAppsIconSizePx / grid.iconSizePx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlingToDeleteCompleted() {
|
||||
// We just dismiss the drag when we fling, so cleanup here
|
||||
mLauncher.exitSpringLoadedDragModeDelayed(true,
|
||||
Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
|
||||
mLauncher.unlockScreenOrientation(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete, boolean success) {
|
||||
if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
|
||||
!(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
|
||||
// Exit spring loaded mode if we have not successfully dropped or have not handled the
|
||||
// drop in Workspace
|
||||
mLauncher.exitSpringLoadedDragModeDelayed(true,
|
||||
Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
|
||||
}
|
||||
mLauncher.unlockScreenOrientation(false);
|
||||
|
||||
// Display an error message if the drag failed due to there not being enough space on the
|
||||
// target layout we were dropping on.
|
||||
if (!success) {
|
||||
boolean showOutOfSpaceMessage = false;
|
||||
if (target instanceof Workspace) {
|
||||
int currentScreen = mLauncher.getCurrentWorkspaceScreen();
|
||||
Workspace workspace = (Workspace) target;
|
||||
CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
|
||||
ItemInfo itemInfo = (ItemInfo) d.dragInfo;
|
||||
if (layout != null) {
|
||||
layout.calculateSpans(itemInfo);
|
||||
showOutOfSpaceMessage =
|
||||
!layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
|
||||
}
|
||||
}
|
||||
if (showOutOfSpaceMessage) {
|
||||
mLauncher.showOutOfSpaceMessage(false);
|
||||
}
|
||||
|
||||
d.deferDragViewCleanupPostAnimation = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user